国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Redis 分布式鎖--PHP

canger / 1617人閱讀

摘要:分布式鎖的作用在單機(jī)環(huán)境下,有個(gè)秒殺商品的活動(dòng),在短時(shí)間內(nèi),服務(wù)器壓力和流量會(huì)陡然上升。分布式集群業(yè)務(wù)業(yè)務(wù)場(chǎng)景下,每臺(tái)服務(wù)器是獨(dú)立存在的。這里就用到了分布式鎖這里簡(jiǎn)單介紹一下,以的事務(wù)機(jī)制來(lái)延生。

Redis 分布式鎖的作用

在單機(jī)環(huán)境下,有個(gè)秒殺商品的活動(dòng),在短時(shí)間內(nèi),服務(wù)器壓力和流量會(huì)陡然上升。這個(gè)就會(huì)存在并發(fā)的問(wèn)題。想要解決并發(fā)需要解決以下問(wèn)題

1、提高系統(tǒng)吞吐率也就是qps 每秒處理的請(qǐng)求書
2、避免商品在高并發(fā)的情況下,出現(xiàn)資源爭(zhēng)搶導(dǎo)致的超買超買問(wèn)題

解決問(wèn)題一:采用內(nèi)存型數(shù)據(jù)庫(kù)提高系統(tǒng)的qps
解決問(wèn)題二:就要用到經(jīng)常會(huì)遇到的鎖,例如MySQL 有讀鎖、寫鎖、排他鎖、悲觀鎖、樂(lè)觀鎖。不過(guò)這里只討論redis來(lái)實(shí)現(xiàn)鎖

簡(jiǎn)單版設(shè)置鎖
$redis = new Redis();
$redis->connect("127.0.0.1", 6379); //連接Redis

$expire = 10;//有效期10秒
$key = "lock";//key
$value = time() + $expire;//鎖的值 = Unix時(shí)間戳 + 鎖的有效期
$lock = $redis->setnx($key, $value);
//判斷是否上鎖成功,成功則執(zhí)行下步操作
if(!empty($lock))
{
//下步操作...       
}

如果以這樣的簡(jiǎn)單版設(shè)置鎖就能解決所有問(wèn)題,未免也太小看在程序中應(yīng)用了。

按正常的操作示例基本上都是這樣寫的。但是這樣寫有一些問(wèn)題

1、假如有10000 個(gè)請(qǐng)求訪問(wèn)了redis 不存在的鍵,這樣請(qǐng)求就是指接到了MySQL數(shù)據(jù),造成CPU短時(shí)間內(nèi)達(dá)到100%甚至宕機(jī)。這樣場(chǎng)景俗稱緩存擊穿造成的緩存雪崩。
2、 假如CPU過(guò)高或者網(wǎng)絡(luò)延時(shí)問(wèn)題,造成鎖沒(méi)有被刪除掉或者緩存鍵過(guò)期沒(méi)有被回收的情況,就會(huì)形成死鎖。

解決問(wèn)題:引用reids setnx 方法的作用是,當(dāng)設(shè)置的key 不存在時(shí),設(shè)置新的值。這樣就避免了緩存擊穿的問(wèn)題。檢測(cè)鍵的過(guò)期時(shí)間,避免產(chǎn)生死鎖

解決死鎖問(wèn)題
    $expire = 10;//有效期10秒
    $key = "lock";//key
    $value = time() + $expire;//鎖的值 = Unix時(shí)間戳 + 鎖的有效期
    $status = true;
    while($status)
    {
        $lock = $redis->setnx($key, $value);
        if(empty($lock))
        {
            $value = $redis->get($key);
            if($value < time())
            {
                $redis->del($key);
            }       
        }else{
            $status = false;
            //下步操作....
        }
    }
1、按理說(shuō)這樣解決單機(jī)版鎖競(jìng)爭(zhēng)問(wèn)題已經(jīng)是沒(méi)有多大問(wèn)題了。那么特殊情況來(lái)了,如果這個(gè)設(shè)置鎖的鍵由于意外情況沒(méi)有被刪除,這樣同樣會(huì)有死鎖的情況發(fā)生。

2、分布式集群業(yè)務(wù)業(yè)務(wù)場(chǎng)景下,每臺(tái)服務(wù)器是獨(dú)立存在的。多臺(tái)服務(wù)器怎么通過(guò)一個(gè)標(biāo)識(shí)來(lái)相互競(jìng)爭(zhēng)鎖呢。這里就用到了分布式鎖

這里簡(jiǎn)單介紹一下,以MYSQL 的事務(wù)機(jī)制來(lái)延生。事務(wù)四個(gè)特性ACID,有四種隔離級(jí)別:未提交讀、已提交讀、可重復(fù)讀、串行化。這些特性都只在單臺(tái)服務(wù)器上生效。到了分布式集群了,數(shù)據(jù)在不同的服務(wù)器上,緊靠事務(wù)很難保持?jǐn)?shù)據(jù)的一致性及隔離性,事務(wù)的作用就意義不大了。Redis也是如此。

正確的分布式鎖的打開方式
   /**
     * 實(shí)現(xiàn)Redis分布鎖
     */
    $key        = "demo";       //要更新信息的緩存KEY
    $lockKey    = "lock:".$key; //設(shè)置鎖KEY
    $lockExpire = 10;           //設(shè)置鎖的有效期為10秒
     
    //獲取緩存信息
    $result = $redis->get($key);
    //判斷緩存中是否有數(shù)據(jù)
    if(empty($result))
    {
        $status = TRUE;
        while ($status)
        {
            //設(shè)置鎖值為當(dāng)前時(shí)間戳 + 有效期
            $lockValue = time() + $lockExpire;
            /**
             * 創(chuàng)建鎖
             * 試圖以$lockKey為key創(chuàng)建一個(gè)緩存,value值為當(dāng)前時(shí)間戳
             * 由于setnx()函數(shù)只有在不存在當(dāng)前key的緩存時(shí)才會(huì)創(chuàng)建成功
             * 所以,用此函數(shù)就可以判斷當(dāng)前執(zhí)行的操作是否已經(jīng)有其他進(jìn)程在執(zhí)行了
             * @var [type]
             */
            $lock = $redis->setnx($lockKey, $lockValue);
            /**
             * 滿足兩個(gè)條件中的一個(gè)即可進(jìn)行操作
             * 1、上面一步創(chuàng)建鎖成功;
             * 2、   1)判斷鎖的值(時(shí)間戳)是否小于當(dāng)前時(shí)間    $redis->get()
             *      2)同時(shí)給鎖設(shè)置新值成功    $redis->getset()
             */
            if(!empty($lock) || ($redis->get($lockKey) < time() && $redis->getSet($lockKey, $lockValue) < time() ))
            {
                //給鎖設(shè)置生存時(shí)間
                $redis->expire($lockKey, $lockExpire);
                //******************************
                //此處執(zhí)行插入、更新緩存操作...
                //******************************
     
                //以上程序走完刪除鎖
                //檢測(cè)鎖是否過(guò)期,過(guò)期鎖沒(méi)必要?jiǎng)h除
                if($redis->ttl($lockKey))
                    $redis->del($lockKey);
                $status = FALSE;
            }else{
                /**
                 * 如果存在有效鎖這里做相應(yīng)處理
                 *      等待當(dāng)前操作完成再執(zhí)行此次請(qǐng)求
                 *      直接返回
                 */
                sleep(2);//等待2秒后再嘗試執(zhí)行操作
            }
        }
    }
結(jié)尾

文章從知識(shí)面的廣度(mysql)、示例代碼優(yōu)缺點(diǎn)的簡(jiǎn)介及應(yīng)用的場(chǎng)景,區(qū)別于其他博客文章。嘿嘿~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/31258.html

相關(guān)文章

  • PHP 使用 Redis 實(shí)現(xiàn)布式

    摘要:由于執(zhí)行的原子性所以不要在中執(zhí)行過(guò)長(zhǎng)開銷的程序,否則會(huì)驗(yàn)證影響其它請(qǐng)求的執(zhí)行。同一個(gè)腳本生成的簽名都是相同的,所以簽名可以先在本地生成,然后在服務(wù)器上一次腳本,程序中只需保存和使用該簽名即可。同樣的腳本,是始終生成相同的簽名的。 Last-Modified: 2019年6月5日15:59:34 參考鏈接 PHP使用Redis+Lua腳本操作的注意事項(xiàng) 《Redis官方文檔》用Redi...

    Coly 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<