国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術(shù)及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數(shù)據(jù)庫技術(shù)|

服務器之家 - 數(shù)據(jù)庫 - Redis - Redis構(gòu)建分布式鎖

Redis構(gòu)建分布式鎖

2021-05-06 17:05壹葉隨風 Redis

本文主要介紹了Redis構(gòu)建分布式鎖的相關(guān)知識。具有很好的參考價值,下面跟著小編一起來看下吧

1、前言

為什么要構(gòu)建鎖呢?因為構(gòu)建合適的鎖可以在高并發(fā)下能夠保持數(shù)據(jù)的一致性,即客戶端在執(zhí)行連貫的命令時上鎖的數(shù)據(jù)不會被別的客戶端的更改而發(fā)生錯誤。同時還能夠保證命令執(zhí)行的成功率。

看到這里你不禁要問redis中不是有事務操作么?事務操作不能夠?qū)崿F(xiàn)上面的功能么?

的確,redis中的事務可以watch可以監(jiān)控數(shù)據(jù),從而能夠保證連貫執(zhí)行的時數(shù)據(jù)的一致性,但是我們必須清楚的認識到,在多個客戶端同時處理相同的數(shù)據(jù)的時候,很容易導致事務的執(zhí)行失敗,甚至會導致數(shù)據(jù)的出錯。

在關(guān)系型數(shù)據(jù)庫中,用戶首先向數(shù)據(jù)庫服務器發(fā)送begin,然后執(zhí)行各個相互一致的寫操作和讀操作,最后用戶可以選擇發(fā)送commit來確認之前的修改,或者發(fā)送rollback進行回滾。

在redis中,通過特殊的命令multi為開始,之后用戶傳入一連貫的命令,最后exec為結(jié)束(在這一過程中可以使用watch進行監(jiān)控一些key)。進一步分析,redis事務中的命令會先推入隊列,等到exec命令出現(xiàn)的時候才會將一條條命令執(zhí)行。假若watch監(jiān)控的key發(fā)生改變,這個事務將會失敗。這也就說明redis事務中不存在鎖,其他客戶端可以修改正在執(zhí)行事務中的有關(guān)數(shù)據(jù),這也就為什么在多個客戶端同時處理相同的數(shù)據(jù)時事務往往會發(fā)生錯誤。

2、簡單理解redis的單線程io多路復用

redis采用單線程io多路復用模型來實現(xiàn)高內(nèi)存數(shù)據(jù)服務。何為單線程io多路復用呢?從字面的意思可以知道redis采用的是單線程、使用的是多個io。整個過程簡單的來講就是,哪個命令的數(shù)據(jù)流先到達就先執(zhí)行。

請看下面的形象理解圖:圖中是一座窄橋,只能允許一輛車通過,左邊是車輛進入的通道,哪一輛車先到達就先進入。即哪個io流先到達就先處理哪個。

linux下網(wǎng)絡io使用socket套接字來通訊,普通io模型只能監(jiān)聽一個socket,而io多路復用可同時監(jiān)控多個socket。io多路復用避免阻塞在io上,單線程保存多個socket的狀態(tài)后輪循處理。

Redis構(gòu)建分布式鎖

3、并發(fā)測試

我們就模擬一個簡單典型的并發(fā)測試,然后從這個測試中得出問題,再進一步研究。

并發(fā)測試思路:

1、在redis中設(shè)置一個字符串count,運用程序?qū)⑵淙〕鰜砑?1,再存儲回去,一直循環(huán)十萬次

2、在兩個瀏覽器上同時執(zhí)行這個代碼

3、將count取出來,查看結(jié)果

測試步驟:

1、建立test.php文件

?
1
2
3
4
5
6
7
8
9
10
11
<?php
$redis=new redis();
$redis->connect('192.168.95.11','6379');
for ($i=0; $i < 100000; $i++)
{
 $count=$redis->get('count');
 $count=$count+1;
 $redis->set('count',$count);
}
echo "this ok";
?>

2、分別在兩個瀏覽器中訪問test.php文件

Redis構(gòu)建分布式鎖

結(jié)果由上圖可知,總共執(zhí)行兩次,count原本應該是二十萬才對的,但實際上count等于十三萬多,遠遠小于二十萬,這是為什么呢?

由前面的內(nèi)容可知,redis是采用單線程io多路復用模型的。因此我們使用兩個瀏覽器即為兩個會話(a、b),取出、加1、存入這三個命令并不是原子操作,并且在執(zhí)行取出、存入這兩個redis命令時是哪個客戶端先到就先執(zhí)行。

例如:

1、此時count=120

2、a取出count=120,緊接著b的取出命令流到了,也將count=120取出

3、a取出后立即加1,并將count=121存回去

4、此時b也緊跟著,也將count=121存進去了

注意:

1、設(shè)置循環(huán)次數(shù)盡量大一點,太小的話,當在第一個瀏覽器執(zhí)行完畢,第二個瀏覽器還沒開始進行呢

2、必須要兩個瀏覽器同時執(zhí)行。假若在一個瀏覽器中同時執(zhí)行兩次test.php文件,不管是否同時執(zhí)行,最終結(jié)果就是count=200000。因為在同一個瀏覽器中執(zhí)行,都是屬于同一個會話(所有命令都在同一個通道通過),所以redis會讓先執(zhí)行的十萬次執(zhí)行完,再接著執(zhí)行其他的十萬次。

4、事務解決與原子性操作解決

4.1、事務解決

更改后的test.php文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
header("content-type: text/html;charset=utf8;");
$start=time();
$redis=new redis();
$redis->connect('192.168.95.11','6379');
for ($i=0; $i < 100000; $i++)
{
 $redis->multi();
 $count=$redis->get('count');
 $count=$count+1;
 $redis->set('count',$count);
 $redis->exec();
}
$end=time();
echo "this ok<br/>";
echo "執(zhí)行時間為:".($end-$start);
?>

執(zhí)行結(jié)果失敗,表名使用事務不能夠解決此問題。

Redis構(gòu)建分布式鎖

分析原因:

我們都知道當redis開啟時,事務中的命令是不執(zhí)行的,而是先將命令壓入隊列,然后當出現(xiàn)exec命令的時候,才會阻塞式的將所有的命令一個接一個的執(zhí)行。

所以當使用php中的redis類進行redis事務的時候,所有有關(guān)redis的命令都不會真正的執(zhí)行,而僅僅是將命令發(fā)送到redis中進行存儲起來。

因此下圖中所圈到的$count實際上不是我們想要的數(shù)據(jù),而是一個對象,因此test.php中11行出錯。

Redis構(gòu)建分布式鎖

查看對象count:

Redis構(gòu)建分布式鎖

Redis構(gòu)建分布式鎖

4.2、原子性操作incr解決

#更新test.php文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
header("content-type: text/html;charset=utf8;");
$start=time();
$redis=new redis();
$redis->connect('192.168.95.11','6379');
for ($i=0; $i < 100000; $i++)
{
 $count=$redis->incr('count');
}
$end=time();
echo "this ok<br/>";
echo "執(zhí)行時間為:".($end-$start);
?>

兩個瀏覽器同時執(zhí)行,耗時14、15秒,count=200000,可以解決此問題。

缺點:

僅僅只是解決這里的取出加1的問題,本質(zhì)上還是沒能解決問題的,在實際環(huán)境中,我們需要做的是一系列操作,不僅僅只是取出加1,因此就很有必要構(gòu)建一個萬能鎖了。

5、構(gòu)建分布式鎖  

我們構(gòu)造鎖的目的就是在高并發(fā)下消除選擇競爭、保持數(shù)據(jù)一致性

構(gòu)造鎖的時候,我們需要注意幾個問題:

1、預防處理持有鎖在執(zhí)行操作的時候進程奔潰,導致死鎖,其他進程一直得不到此鎖

2、持有鎖進程因為操作時間長而導致鎖自動釋放,但本身進程并不知道,最后錯誤的釋放其他進程的鎖

3、一個進程鎖過期后,其他多個進程同時嘗試獲取鎖,并且都成功獲得鎖

我們將不對test.php文件修改了,而是直接建立一個相對比較規(guī)范的面向?qū)ο髄ock.class.php類文件  

#建立lock.class,php文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<?php
#分布式鎖
class lock
{
 private $redis=''; #存儲redis對象
 /**
 * @desc 構(gòu)造函數(shù)
 *
 * @param $host string | redis主機
 * @param $port int | 端口
 */
 public function __construct($host,$port=6379)
 {
  $this->redis=new redis();
  $this->redis->connect($host,$port);
 }
 /**
 * @desc 加鎖方法
 *
 * @param $lockname string | 鎖的名字
 * @param $timeout int | 鎖的過期時間
 *
 * @return 成功返回identifier/失敗返回false
 */
 public function getlock($lockname, $timeout=2)
 {
  $identifier=uniqid();  #獲取唯一標識符
  $timeout=ceil($timeout); #確保是整數(shù)
  $end=time()+$timeout;
  while(time()<$end)   #循環(huán)獲取鎖
  {
   if($this->redis->setnx($lockname, $identifier)) #查看$lockname是否被上鎖
   {
    $this->redis->expire($lockname, $timeout);  #為$lockname設(shè)置過期時間,防止死鎖
    return $identifier;        #返回一維標識符
   }
   elseif ($this->redis->ttl($lockname)===-1)
   {                        
    $this->redis->expire($lockname, $timeout);  #檢測是否有設(shè)置過期時間,沒有則加上(假設(shè),客戶端a上一步?jīng)]能設(shè)置時間就進程奔潰了,客戶端b就可檢測出來,并設(shè)置時間)
   }
   usleep(0.001);   #停止0.001ms
  }
  return false;
 }
 /**
 * @desc 釋放鎖
 *
 * @param $lockname string | 鎖名
 * @param $identifier string | 鎖的唯一值
 *
 * @param bool
 */
 public function releaselock($lockname,$identifier)
 {
  if($this->redis->get($lockname)==$identifier) #判斷是鎖有沒有被其他客戶端修改
  {
   $this->redis->multi();
   $this->redis->del($lockname); #釋放鎖
   $this->redis->exec();
   return true;
  }
  else
  {
   return false; #其他客戶端修改了鎖,不能刪除別人的鎖
  }
 }
 /**
 * @desc 測試
 *
 * @param $lockname string | 鎖名
 */
 public function test($lockname)
 {
  $start=time();
  for ($i=0; $i < 10000; $i++)
  {
   $identifier=$this->getlock($lockname);
   if($identifier)
   {
    $count=$this->redis->get('count');
    $count=$count+1;
    $this->redis->set('count',$count);
    $this->releaselock($lockname,$identifier);
   }
  }
  $end=time();
  echo "this ok<br/>";
  echo "執(zhí)行時間為:".($end-$start);
 }
 
}
header("content-type: text/html;charset=utf8;");
$obj=new lock('192.168.95.11');
$obj->test('lock_count');
?>

測試結(jié)果:

在兩個不同的瀏覽器中執(zhí)行,最終結(jié)果count=200000,但是耗時相對較多,需要近八十多秒左右。但是在高并發(fā)下,對同一個數(shù)據(jù),二十萬次上鎖執(zhí)行釋放鎖的操作還是可以接受的,甚至已經(jīng)很不錯了。

以上的簡單例子僅僅只是為了模擬并發(fā)測試并檢驗而已,實際上我們可以使用lock.class.php中的鎖結(jié)合自己的項目加以修改就可以很好地使用這個鎖了。例如商城中的瘋狂搶購、游戲中虛擬商城玩家買賣東西等等。

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持服務器之家!

原文鏈接:http://www.cnblogs.com/phpstudy2015-6/p/6575775.html

延伸 · 閱讀

精彩推薦
  • RedisRedis的配置、啟動、操作和關(guān)閉方法

    Redis的配置、啟動、操作和關(guān)閉方法

    今天小編就為大家分享一篇Redis的配置、啟動、操作和關(guān)閉方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    大道化簡5312019-11-14
  • RedisRedis全量復制與部分復制示例詳解

    Redis全量復制與部分復制示例詳解

    這篇文章主要給大家介紹了關(guān)于Redis全量復制與部分復制的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis爬蟲具有一定的參考學習...

    豆子先生5052019-11-27
  • Redisredis 交集、并集、差集的具體使用

    redis 交集、并集、差集的具體使用

    這篇文章主要介紹了redis 交集、并集、差集的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友...

    xiaojin21cen10152021-07-27
  • RedisRedis 事務知識點相關(guān)總結(jié)

    Redis 事務知識點相關(guān)總結(jié)

    這篇文章主要介紹了Redis 事務相關(guān)總結(jié),幫助大家更好的理解和學習使用Redis,感興趣的朋友可以了解下...

    AsiaYe8232021-07-28
  • Redis詳解Redis復制原理

    詳解Redis復制原理

    與大多數(shù)db一樣,Redis也提供了復制機制,以滿足故障恢復和負載均衡等需求。復制也是Redis高可用的基礎(chǔ),哨兵和集群都是建立在復制基礎(chǔ)上實現(xiàn)高可用的...

    李留廣10222021-08-09
  • RedisRedis如何實現(xiàn)數(shù)據(jù)庫讀寫分離詳解

    Redis如何實現(xiàn)數(shù)據(jù)庫讀寫分離詳解

    Redis的主從架構(gòu),能幫助我們實現(xiàn)讀多,寫少的情況,下面這篇文章主要給大家介紹了關(guān)于Redis如何實現(xiàn)數(shù)據(jù)庫讀寫分離的相關(guān)資料,文中通過示例代碼介紹...

    羅兵漂流記6092019-11-11
  • Redisredis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    這篇文章主要給大家介紹了關(guān)于redis中如何使用lua腳本讓你的靈活性提高5個逼格的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具...

    一線碼農(nóng)5812019-11-18
  • Redisredis實現(xiàn)排行榜功能

    redis實現(xiàn)排行榜功能

    排行榜在很多地方都能使用到,redis的zset可以很方便地用來實現(xiàn)排行榜功能,本文就來簡單的介紹一下如何使用,具有一定的參考價值,感興趣的小伙伴們...

    乘月歸5022021-08-05
主站蜘蛛池模板: 亚洲国产精品电影在线观看 | 国产黄a三级三级看三级 | 欧美电影网站 | 福利视频网址导航 | 日韩午夜| 91在线高清| 欧美 日韩 精品 | 欧美日韩一二三区 | 性视频网站免费 | 免费三级黄色 | 中文字幕在线观看 | 亚洲免费二区 | 91久草视频 | 亚洲欧洲成人 | 国产精品久久久久久久久免费桃花 | 人人澡人人射 | 天天色av| 国产成人久久一区二区三区 | 免费成人在线电影 | 国产成年人在线观看 | 国产裸体bbb视频 | 四虎小视频 | 国产偷亚洲偷欧美偷精品 | 99re视频在线观看 | 免费av一区二区三区 | 免费一级网站 | 国产精品1区 | 日产欧产va高清 | 亚洲一区中文字幕 | 色噜噜狠狠一区二区三区狼国成人 | 久久av一区二区三区 | 美日韩视频 | 欧美一级一区 | 日韩免费av | 欧美黑人一级爽快片淫片高清 | 97视频在线| 成人黄网在线观看 | 欧美一区二区三区免费观看视频 | 久久精品一区二区 | 精品无人区一区二区三区动漫 | 精品96久久久久久中文字幕无 |