偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

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

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

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

01 Redis簡(jiǎn)介

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

02 Redis實(shí)現(xiàn)特點(diǎn)

(1)單線程

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

(2)IO多路復(fù)用

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

 

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

 

03 Redis集群方案比較

(1)哨兵模式

 

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

 

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

(2)高可用集群模式

 

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

 

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

04 Redis集群部署常見(jiàn)問(wèn)題

在了解Redis集群部署常見(jiàn)問(wèn)題之前我們先來(lái)了解一下Redis集群的實(shí)現(xiàn)原理。Redis Cluster 將所有數(shù)據(jù)劃分為 16384 的 slots(槽位),每個(gè)節(jié)點(diǎn)負(fù)責(zé)其中一部分槽位。槽位的信息存儲(chǔ)于每個(gè)節(jié)點(diǎn)中,當(dāng) Redis Cluster 的客戶(hù)端來(lái)連接集群時(shí),它也會(huì)得到一份集群的槽位配置信息并將其緩存在客戶(hù)端本地。這樣當(dāng)客戶(hù)端要查找某個(gè) key 時(shí),可以直接定位到目標(biāo)節(jié)點(diǎn)。同時(shí)因?yàn)椴畚坏男畔⒖赡軙?huì)存在客戶(hù)端與服務(wù)器不一致的情況,還需要糾正機(jī)制來(lái)實(shí)現(xiàn)槽位信息的校驗(yàn)調(diào)整。

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

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

(2)網(wǎng)絡(luò)抖動(dòng)問(wèn)題

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

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

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

Redis的分布式鎖是基于Redis SETNX命令來(lái)實(shí)現(xiàn)的,在Redis中通過(guò)SETNX命令設(shè)置Key Value時(shí)有如下兩種結(jié)果:

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

2)返回0,表示為指定的key設(shè)置值失敗,因?yàn)楫?dāng)前已存在該key,也即表示其它進(jìn)程獲取了鎖資源

下面我們就來(lái)看看怎么通過(guò)python實(shí)現(xiàn)分布式鎖吧

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

 

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

 

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

 

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

 

(2)接著我們創(chuàng)建帶分布式鎖的示列,我們先來(lái)看看分布式鎖創(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操作類(lèi)    
  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.     # 設(shè)置鎖    
  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設(shè)置一個(gè)超時(shí)時(shí)間,這個(gè)相當(dāng)于鎖的有效時(shí)間   
  32. 32.         # 如果沒(méi)有超時(shí)時(shí)間則會(huì)導(dǎo)致程序死鎖   
  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.     # 如果不能獲取鎖資源則線程一直掛起直到獲取鎖資源或者超時(shí)   
  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)異常時(shí)主動(dòng)釋放鎖資源   
  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)最后我們?cè)谟?jì)算函數(shù)中增加分布式鎖裝飾器,然后查看程序運(yùn)行結(jié)果是否符合預(yù)期,具體如下

 

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

 

 

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

 

06 總結(jié)

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

責(zé)任編輯:華軒 來(lái)源: 今日頭條
相關(guān)推薦

2013-04-09 09:54:34

程序員

2025-05-08 08:20:42

2023-07-17 10:28:00

C/C++編程接口

2023-05-05 08:08:06

JavaRedis事務(wù)

2015-12-04 09:33:15

程序員前端演進(jìn)史

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 程序員

2017-08-07 10:53:57

程序員客戶(hù)項(xiàng)目

2023-09-12 11:25:15

2015-11-30 11:01:34

前端程序員歷史

2013-06-09 09:56:35

2009-06-22 09:06:57

程序員技術(shù)升級(jí)

2011-07-19 13:27:35

2019-05-20 10:28:16

定律原則GitHub

2018-08-02 17:00:15

Vue.js學(xué)習(xí)iOS開(kāi)發(fā)

2023-10-26 18:05:37

Git命令差異

2017-08-03 14:25:13

Python陷阱與缺陷

2012-06-28 14:01:30

Java程序員排序
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)