成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

程序員必懂的Redis技術實戰(zhàn)

開發(fā) 前端 Redis
Redis是現(xiàn)在很受歡迎的NoSQL數(shù)據(jù)庫之一,目前廣泛用于緩存系統(tǒng)、分布式鎖、計數(shù)器、消息隊列系統(tǒng)、排行榜、社交網(wǎng)絡等場景中,本篇文章成哥為大家?guī)韗edis日常使用實踐,及通過代碼實現(xiàn)redis的分布式鎖。

 Redis是現(xiàn)在很受歡迎的NoSQL數(shù)據(jù)庫之一,目前廣泛用于緩存系統(tǒng)、分布式鎖、計數(shù)器、消息隊列系統(tǒng)、排行榜、社交網(wǎng)絡等場景中,本篇文章成哥為大家?guī)韗edis日常使用實踐,及通過代碼實現(xiàn)redis的分布式鎖。

01 Redis簡介

Redis是一個開源使用ANSI C語言編寫、遵守BSD協(xié)議、支持網(wǎng)絡、可基于內(nèi)存亦可以持久化的日志類型、key-value數(shù)據(jù)庫,并提供多種語言的API。Redis的出現(xiàn),很大程度上彌補了Memcache這類key/value存儲的不足,在部分場合可以對關系型數(shù)據(jù)庫(MySql、DB2等,關系型數(shù)據(jù)庫通過外鍵關聯(lián)來建立表與表之間的關系。非關系型數(shù)據(jù)庫通常指數(shù)據(jù)以對象的形式存儲在數(shù)據(jù)庫中,而對象之間的關系通過每個對象自身的屬性來決定)起到很好的補充作用。(如可降低數(shù)據(jù)庫訪問壓力,弊端冷數(shù)據(jù)的處理)。

02 Redis實現(xiàn)特點

(1)單線程

Redis是通過單線程實現(xiàn)的,單線程避免了多線程的切換性能損耗問題,同時它所有的數(shù)據(jù)都在內(nèi)存中,所有的運算都是內(nèi)存級別的運算,所以即使是單線程redis還能這么快。但也正是因為使用的是單線程,所以要小心使用 Redis 指令,對于那些耗時的指令(比如keys),一定要謹慎使用,一不小心就可能會導致 Redis 卡頓。

(2)IO多路復用

Redis通過IO多路復用解決單線程下并發(fā)客戶端的訪問,redis利用epoll來實現(xiàn)IO多路復用,將連接信息和事件放到隊列中,依次放到文件事件分派器,事件分派器將事件分發(fā)給事件處理器。具體架構如下:

 

程序員必懂的Redis技術實戰(zhàn)

 

03 Redis集群方案比較

(1)哨兵模式

 

程序員必懂的Redis技術實戰(zhàn)

 

在redis3.0以前的版本要實現(xiàn)集群一般是借助哨兵sentinel工具來監(jiān)控master節(jié)點的狀態(tài),如果master節(jié)點異常,則會做主從切換,將某一臺slave作為master,哨兵的配置略微復雜,并且性能和高可用性等各方面表現(xiàn)一般,特別是在主從切換的瞬間存在訪問瞬斷的情況,而且哨兵模式只有一個主節(jié)點對外提供服務,沒法支持很高的并發(fā),且單個主節(jié)點內(nèi)存也不宜設置得過大,否則會導致持久化文件過大,影響數(shù)據(jù)恢復或主從同步的效率 。

(2)高可用集群模式

 

程序員必懂的Redis技術實戰(zhàn)

 

redis高可用集群是一個由多個主從節(jié)點群組成的分布式服務器群,它具有復制、高可用和分片特性。Redis集群不需要sentinel哨兵也能完成節(jié)點移除和故障轉(zhuǎn)移的功能。需要將每個節(jié)點設置成集群模式,這種集群模式?jīng)]有中心節(jié)點,可水平擴展,據(jù)官方文檔稱可以線性擴展到上萬個節(jié)點(官方推薦不超過1000個節(jié)點)。redis集群的性能和高可用性均優(yōu)于之前版本的哨兵模式,且集群配置非常簡單。

04 Redis集群部署常見問題

在了解Redis集群部署常見問題之前我們先來了解一下Redis集群的實現(xiàn)原理。Redis Cluster 將所有數(shù)據(jù)劃分為 16384 的 slots(槽位),每個節(jié)點負責其中一部分槽位。槽位的信息存儲于每個節(jié)點中,當 Redis Cluster 的客戶端來連接集群時,它也會得到一份集群的槽位配置信息并將其緩存在客戶端本地。這樣當客戶端要查找某個 key 時,可以直接定位到目標節(jié)點。同時因為槽位的信息可能會存在客戶端與服務器不一致的情況,還需要糾正機制來實現(xiàn)槽位信息的校驗調(diào)整。

(1)跳轉(zhuǎn)重定位問題

當客戶端向一個錯誤的節(jié)點發(fā)出了指令,該節(jié)點會發(fā)現(xiàn)指令的 key 所在的槽位并不歸自己管理,這時它會向客戶端發(fā)送一個特殊的跳轉(zhuǎn)指令攜帶目標操作的節(jié)點地址,告訴客戶端去連這個節(jié)點去獲取數(shù)據(jù)。客戶端收到指令后除了跳轉(zhuǎn)到正確的節(jié)點上去操作,還會同步更新糾正本地的槽位映射表緩存,后續(xù)所有 key 將使用新的槽位映射表。

(2)網(wǎng)絡抖動問題

在生產(chǎn)環(huán)境中網(wǎng)絡抖動問題不可避免,為解決這種問題,Redis Cluster 提供了一種選項cluster­node­timeout,表示當某個節(jié)點持續(xù) timeout 的時間失聯(lián)時,才可以認定該節(jié)點出現(xiàn)故障,需要進行主從切換。如果沒有這個選項,網(wǎng)絡抖動會導致主從頻繁切換 (數(shù)據(jù)的重新復制)。

05 代碼實現(xiàn)基于Redis的分布式鎖

在多個進程/線程對同一個共享資源讀寫場景下,會因為資源的爭奪而出現(xiàn)混亂,導致數(shù)據(jù)不一致。為了避免該問題我們可以在進程/線程在操作共享資源前獲取一個令牌(也就鎖),只有獲取了該令牌的進程/線程才可以操作資源,在操作完資源后釋放該令牌。這就實現(xiàn)了分布式鎖。

Redis的分布式鎖是基于Redis SETNX命令來實現(xiàn)的,在Redis中通過SETNX命令設置Key Value時有如下兩種結果:

1)返回1,表示為指定的key設置值成功,也即表示當前進程已經(jīng)獲取了鎖資源

2)返回0,表示為指定的key設置值失敗,因為當前已存在該key,也即表示其它進程獲取了鎖資源

下面我們就來看看怎么通過python實現(xiàn)分布式鎖吧

(1)首先我們創(chuàng)建一個不使用分布式鎖的示列,通過多線程對全局變量進行加1操作看看結果如何,具體代碼如下:

 

程序員必懂的Redis技術實戰(zhàn)

 

代碼運行結果如下,發(fā)現(xiàn)不是我們預期的值(預期值應為3+3=6)

 

程序員必懂的Redis技術實戰(zhàn)

 

(2)接著我們創(chuàng)建帶分布式鎖的示列,我們先來看看分布式鎖創(chuàng)建的方法,具體如下

 

  1. 1. import time   
  2. 2. import uuid   
  3. 3. from redis import StrictRedis, ConnectionPool   
  4. 4. import threading   
  5. 5.    
  6. 6. class CollectRedis:   
  7. 7.     # 創(chuàng)建redis操作類    
  8. 8.     def __init__(self):   
  9. 9.         self.host = "1.1.1.1"   
  10. 10.         self.port = 6379   
  11. 11.         self.db = 5   
  12. 12.   
  13. 13.     @property   
  14. 14.     def redis_session(self):   
  15. 15.         _session = getattr(self, "__redis_session", None)   
  16. 16.         if _session:   
  17. 17.             return _session   
  18. 18.         redis_pool = ConnectionPool(host=self.host, port=self.port, db=self.db)   
  19. 19.         _session = StrictRedis(connection_pool=redis_pool)   
  20. 20.         setattr(self, "__redis_session", _session)   
  21. 21.         return _session   
  22. 22.        
  23. 23.     # 獲取鎖   
  24. 24.     def get_lock(self, lock_key):   
  25. 25.         return self.redis_session.get(lock_key)   
  26. 26.        
  27. 27.     # 設置鎖    
  28. 28.     def set_lock(self, lock_key, value, timeout=300):   
  29. 29.         session = self.redis_session   
  30. 30.         tag = session.setnx(lock_key, value)   
  31. 31.         # 如果key能創(chuàng)建成功則為該key設置一個超時時間,這個相當于鎖的有效時間   
  32. 32.         # 如果沒有超時時間則會導致程序死鎖   
  33. 33.         if tag:   
  34. 34.             session.expire(lock_key, timeout)   
  35. 35.         return tag   
  36. 36.        
  37. 37.     # 刪除鎖也就是釋放鎖   
  38. 38.     def delete_lock(self, lock_key):   
  39. 39.         return self.redis_session.delete(lock_key)   
  40. 40.    
  41. 41. # 獲取鎖資源方法   
  42. 42. def acquire_lock(lock_name, time_out=300):   
  43. 43.     identifier = str(uuid.uuid4())   
  44. 44.     end = time.time() + time_out + 30   
  45. 45.     redis_connect = CollectRedis()   
  46. 46.     # 如果不能獲取鎖資源則線程一直掛起直到獲取鎖資源或者超時   
  47. 47.     while time.time() < end:   
  48. 48.         if redis_connect.set_lock(lock_name, identifier, timeout=time_out):   
  49. 49.             return identifier   
  50. 50.         time.sleep(0.01)   
  51. 51.     return False   
  52. 52.    
  53. 53. # 釋放鎖資源   
  54. 54. def release_lock(lock_name, identifier):   
  55. 55.     redis_connect = CollectRedis()   
  56. 56.     value = redis_connect.get_lock(lock_name)   
  57. 57.     if not value:   
  58. 58.         return True   
  59. 59.     if value == identifier:   
  60. 60.         redis_connect.delete_lock(lock_name)   
  61. 61.         return True   
  62. 62.     return False   
  63. 63.    
  64. 64.    
  65. 65. def resource_lock(lock_name, timeout=10):   
  66. 66.     """  
  67. 67.     并發(fā)鎖裝飾器函數(shù)  
  68. 68.     :param lock_name:  
  69. 69.     :param timeout:  
  70. 70.     :return:  
  71. 71.     """   
  72. 72.     def _outfunc(func):   
  73. 73.         def inner_func(*args, **kwargs):   
  74. 74.             identifier = acquire_lock(lock_name, time_out=timeout)   
  75. 75.             if not identifier:   
  76. 76.                 raise Exception("獲取({})鎖資源失敗".format(lock_name))   
  77. 77.             try:   
  78. 78.                 result = func(*args, **kwargs)   
  79. 79.                 release_lock(lock_name, identifier)   
  80. 80.             except Exception as e:   
  81. 81.                 # 程序出現(xiàn)異常時主動釋放鎖資源   
  82. 82.                 release_lock(lock_name, identifier)   
  83. 83.                 raise Exception(e.args)   
  84. 84.             return result   
  85. 85.         return inner_func   
  86. 86.     return _outfunc   

 

(3)最后我們在計算函數(shù)中增加分布式鎖裝飾器,然后查看程序運行結果是否符合預期,具體如下

 

程序員必懂的Redis技術實戰(zhàn)

 

 

程序員必懂的Redis技術實戰(zhàn)

 

06 總結

本篇文章主要帶大家了解了Redis的一些特點、部署方案、集群中容器遇到的問題及如何基于redis實現(xiàn)分布式鎖等內(nèi)容,如果喜歡本篇文章不要忘了點贊、關注與轉(zhuǎn)發(fā)哦!

責任編輯:華軒 來源: 今日頭條
相關推薦

2013-04-09 09:54:34

程序員

2025-05-08 08:20:42

2023-05-05 08:08:06

JavaRedis事務

2023-07-17 10:28:00

C/C++編程接口

2015-12-04 09:33:15

程序員前端演進史

2020-12-08 10:35:29

程序員IT數(shù)據(jù)分析

2019-01-30 14:14:16

LinuxUNIX操作系統(tǒng)

2020-12-11 07:10:03

程序員

2019-01-02 07:36:28

微軟 Windows 程序員

2023-09-12 11:25:15

2015-11-30 11:01:34

前端程序員歷史

2013-06-09 09:56:35

2017-08-07 10:53:57

程序員客戶項目

2009-06-22 09:06:57

程序員技術升級

2011-07-19 13:27:35

2023-10-26 18:05:37

Git命令差異

2017-08-03 14:25:13

Python陷阱與缺陷

2012-06-28 14:01:30

Java程序員排序

2018-08-02 17:00:15

Vue.js學習iOS開發(fā)

2019-05-20 10:28:16

定律原則GitHub
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩精品一区二区三区视频播放 | 欧美日韩黄色一级片 | 亚洲欧美精品在线 | 女同久久另类99精品国产 | 亚洲高清视频在线观看 | 影视一区| 男女爱爱福利视频 | 国产91丝袜在线18 | 成年人免费在线视频 | 亚洲福利视频一区二区 | 精品伊人 | 中文字幕 欧美 日韩 | 亚洲交性 | 一级在线| 国产精品永久免费观看 | 国产一区二区三区 | www.操.com| 欧美视频在线观看 | 中文字幕第90页 | 日韩在线播放第一页 | caoporon| 国产欧美视频一区 | 一区二区三区四区国产 | 亚洲精品专区 | 国产黄色大片在线观看 | 久久久久中文字幕 | 91在线观看网址 | 欧美日韩福利 | 一二三在线视频 | 99re在线 | 青青草免费在线视频 | 偷派自拍 | 日日摸夜夜爽人人添av | 日韩在线不卡视频 | 国产成人一区二区三区久久久 | 亚洲福利网站 | 99免费在线视频 | 天天天久久久 | 中国一级大毛片 | 亚洲精品视频二区 | 黄色骚片 |