<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                **什么是秒殺?** 秒殺會產生一個瞬間的高并發,使用數據庫會增加數據庫的訪問壓力,也會降低訪問速度,所以我們應該使用緩存,來降低數據庫的訪問壓力;可以看出這里的操作和原來的下單是不一樣的:產生的秒殺預訂單不會馬上寫入數據庫,會先寫入緩存,等用戶支付成功時,修改狀態,寫入數據庫。 **場景描述** 假設num是存儲在數據庫中的字段,保存了被秒殺產品的剩余數量。 ~~~text if($num > 0){ //用戶搶購成功,記錄用戶信息 $num--; } ~~~ 假設在一個并發量較高的場景,數據庫中 num 的值為 1 時,可能同時會有多個進程讀取到 num 為 1,程序判斷符合條件,搶購成功,num 減一。這樣會導致商品超發的情況,本來只有 10 件可以搶購的商品,可能會有超過 10 個人搶到,此時 num 在搶購完成之后為負值。 **解決方案** 解決該問題的方案由很多,可以簡單分為基于 mysql 和 redis 的解決方案,redis 的性能要由于 mysql,因此可以承載更高的并發量,不過下面介紹的方案都是基于單臺 mysql 和 redis 的,更高的并發量需要分布式的解決方案 **基于 redis 的解決方案** 1、基于 watch 的樂觀鎖方案 watch 用于監視一個 (或多個) key ,如果在事務執行之前這個 (或這些) key 被其他命令所改動,那么事務將被打斷。這種方案跟 mysql 中的樂觀鎖方案類似,具體表現也是一樣的。 ~~~text $num = $this->redis->get('num'); if($num > 0) { $this->redis->watch('num'); usleep(100); $res = $this->redis->multi()->decr('num')->lPush('result',$num)->exec(); if($res == false){ echo "fail1"; }else{ echo "success:".$num; } }else{ echo "fail2"; } ~~~ 2、基于 list 的隊列方案 基于隊列的方案利用了 redis 出隊操作的原子性,搶購開始之前首先將商品編號放入響應的隊列中,在搶購時依次從隊列中彈出操作,這樣可以保證每個商品只能被一個進程獲取并操作,不存在超發的情況。該方案的優點是理解和實現起來都比較簡單,缺點是當商品數量較多是,需要將大量的數據存入到隊列中,并且不同的商品需要存入到不同的消息隊列中。 ~~~text public function init(){ $this->redis->del('goods'); for($i=1;$i<=10;$i++){ $this->redis->lPush('goods',$i); } $this->redis->del('result'); echo 'init done'; } public function run(){ $goods_id = $this->redis->rPop('goods'); usleep(100); if($goods_id == false) { echo "fail1"; }else{ $res = $this->redis->lPush('result',$goods_id); if($res == false){ echo "writelog:".$goods_id; }else{ echo "success".$goods_id; } } } ~~~ 3、基于 decr 返回值的方案 如果我們將剩余量 num 設置為一個鍵值類型,每次先 get 之后判斷,然后再 decr 是不能解決超發問題的。但是 redis 中的 decr 操作會返回執行后的結果,可以解決超發問題。我們首先 get 到 num 的值進行第一步判斷,避免每次都去更新 num 的值,然后再對 num 執行 decr 操作,并判斷 decr 的返回值,如果返回值不小于 0,這說明 decr 之前是大于 0 的,用戶搶購成功。 ~~~text public function run(){ $num = $this->redis->get('num'); if($num > 0) { usleep(100); $retNum = $this->redis->decr('num'); if($retNum >= 0){ $res = $this->redis->lPush('result',$retNum); if($res == false){ echo "writeLog:".$retNum; }else{ echo "success:".$retNum; } }else{ echo "fail1"; } }else{ echo "fail2"; } } ~~~ 4、基于 setnx 的排它鎖方案 redis 沒有像 mysql 中的排它鎖,但是可以通過一些方式實現排它鎖的功能,就類似 php 使用文件鎖實現排它鎖一樣。 setnx 實現了 exists 和 set 兩個指令的功能,若給定的 key 已存在,則 setnx 不做任何動作,返回 0;若 key 不存在,則執行類似 set 的操作,返回 1。我們設置一個超時時間 timeout,每隔一定時間嘗試 setnx 操作,如果設置成功就是獲得了相應的鎖,執行 num 的 decr 操作,操作完成刪除相應的 key,模擬釋放鎖的操作。 ~~~text public function run(){ do { $res = $this->redis->setnx("numKey",1); $this->timeout -= 100; usleep(100); }while($res == 0 && $this->timeout>0); if($res == 0){ echo 'fail1'; }else{ $num = $this->redis->get('num'); if($num > 0) { $this->redis->decr('num'); usleep(100); $res = $this->redis->lPush('result',$num); if($res == false){ echo "fail2"; }else{ echo "success:".$num; } }else{ echo "fail3"; } $this->redis->del("numKey"); } } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看