Redis學(xué)習(xí)筆記

一尔艇、Redis事務(wù)

Redis實現(xiàn)了基本的事務(wù)功能受葛,但是不具有回滾功能。Redis通過使用 MULTIEXEC兩個命令來開啟事務(wù)株搔,Redis會先緩存所有包圍在事務(wù)中的命令,直到EXEC被調(diào)用才會將所有的命令一起發(fā)送給Redis服務(wù)榄笙。Redis保證事務(wù)的原子性和隔離性邪狞,也就是說事務(wù)中的命令要么全部執(zhí)行祷蝌,要么全部不執(zhí)行茅撞,一但事務(wù)開始執(zhí)行Redis服務(wù)會暫停其它客戶單發(fā)送的請求,也就是事務(wù)中的命令按順序執(zhí)行并且不會被其它客戶端打擾巨朦。
由于Redis事務(wù)執(zhí)行過程中不加鎖米丘,所以多線程或者多客戶單執(zhí)行過程中會出現(xiàn)競爭條件。比如一個客戶端A通過查詢發(fā)現(xiàn)庫存還有1個可用糊啡,于是下單拄查,但是命令還未發(fā)往Redis服務(wù),于此同時客戶端B通過查詢也發(fā)現(xiàn)庫存還有1個可用棚蓄,于是也下單堕扶,因為緩存或者網(wǎng)絡(luò)等各種原因客戶端B的命令可能會先于客戶端A到達Redis服務(wù)碍脏,于是客戶端B事務(wù)執(zhí)行成功,客戶端A產(chǎn)生了錯誤(但是它并沒有意識到這點稍算,也就是庫存現(xiàn)在是負的)典尾。為了解決這個問題,Redis使用了一個叫check-and-setWATCH命令糊探,也就是樂觀鎖钾埂。沿用上面的例子,但是這次在使用事務(wù)之前先用WATCH命令監(jiān)視庫存科平,然后按照順序執(zhí)行褥紫,客戶端B事務(wù)執(zhí)行成功,客戶端A事務(wù)執(zhí)行失數苫邸(通過WATCH命令可以在執(zhí)行事務(wù)的時候意識到庫存已經(jīng)被修改)髓考,此時客戶端A可以重新執(zhí)行事務(wù),然后查詢得知庫存為0弃酌,于是放棄事務(wù)并通知用戶绳军。WATCH命令雖然可以保證數(shù)據(jù)正確,但是缺點是效率低矢腻,因為一但Redis負載高的話门驾,沖突會指數(shù)上升,客戶端需要不斷的重復(fù)執(zhí)行事務(wù)才有可能成功多柑。

二奶是、Redis鎖

WATCH命令雖然可以保證數(shù)據(jù)的正確性,但是效率實在是不高竣灌,所以使用鎖(排它性鎖)將獲得更高的效率聂沙。Redis并沒有打算實現(xiàn)這種鎖,不過好在通過Redis的相關(guān)命令也是可以自己實現(xiàn)鎖功能(通過Redis中的key來實現(xiàn)初嘹,成功獲取鎖設(shè)置一個key及汉,釋放鎖刪除那個key,通過判斷key是否存在來確定是否可以獲取鎖)屯烦。自己實現(xiàn)鎖功能需要注意的是鎖的釋放坷随,比如客戶端A獲取了庫存鎖,但是突然宕機了驻龟,這樣其它客戶端就無法獲取鎖了温眉。所以在自定義鎖的時候,可以通過Redis的key過期功能翁狐,給鎖(一般就是Redis中的key)添加一個過期時間类溢,這樣就算客戶端宕機了鎖也能自動釋放。另外需要注意的是鎖的過期時間露懒,因為不是所有的操作都是簡單的闯冷,有些客戶端可能需要花很長的時間才能完成事務(wù)砂心,如果客戶端在事務(wù)完成前,鎖就自動釋放了蛇耀,這樣會造成數(shù)據(jù)錯誤计贰。一般解決方法是在鎖快要釋放之前,重新刷新鎖的過期時間蒂窒,也就是續(xù)約鎖躁倒。自己實現(xiàn)鎖還需要考慮很多東西,好在redisson這個開源庫實現(xiàn)了Redis鎖洒琢,可以直接參考或者使用秧秉。

三、Redis分布式鎖

Redis分布式鎖基本上就是上面所說的自定義實現(xiàn)的鎖衰抑,因為Redis可以被多個應(yīng)用訪問象迎,所以通過Redis鎖就可以讓多個應(yīng)用通過鎖來訪問資源。但是一般的Redis分布式鎖都存在一個問題呛踊,就是對于故障轉(zhuǎn)移的能力不夠砾淌。比如Redis主服務(wù)A和從服務(wù)A1組成了一個Redis服務(wù),客戶端C申請了鎖谭网,但是在A向A1同步數(shù)據(jù)前(相對客戶端來說A和A1之間同步數(shù)據(jù)是異步的)宕機了汪厨,然后根據(jù)故障轉(zhuǎn)移規(guī)則A1升級成了主服務(wù),但是這時A1是沒有C所申請的鎖的信息愉择,如果這時其它客戶端申請相同的鎖劫乱,那么它就能獲取鎖,此時兩個客戶端都擁有了相同的鎖锥涕。
針對這種情況Redis官方開發(fā)了一種叫Redlock的分布式鎖衷戈,相對于前面所說的實現(xiàn)(單臺Redis主服務(wù)),Redlock使用多臺Redis主服務(wù)的方式來實現(xiàn)层坠。簡單來說如果有N臺主服務(wù)殖妇,那么在指定時間范圍內(nèi)獲取到N/2+1臺主服務(wù)中的鎖,那么就獲取鎖成功破花。也就是如果現(xiàn)在有5臺主服務(wù)谦趣,那么至少要在3臺主服務(wù)中獲取到鎖,Redlock才算獲取成功旧乞。這么做主要是為了防止某一臺服務(wù)宕機后蔚润,其它服務(wù)還能正常運行磅氨。
Redlock算法原理可以參考https://redis.io/topics/distlock
redisson這個開源庫實現(xiàn)了Redlock

四尺栖、Redis分片

Redis實現(xiàn)了主從服務(wù),但是這種方式只是擴展了讀請求烦租,對于寫請求依然是單服務(wù)延赌。為了擴展寫請求需要一組相互獨立Redis主服務(wù)除盏,并且客戶端需要自行將數(shù)據(jù)分片到不同的Redis主服務(wù)中。Redis分片的原理基本上就是crc32(key) mod N挫以,其中N表示主服務(wù)的個數(shù)者蠕。
分片在不同軟件層次中實現(xiàn):
1、客戶端分片掐松,由客戶端實現(xiàn)將數(shù)據(jù)分片到哪個服務(wù)中
2踱侣、代理分片,由代理決定將數(shù)據(jù)分片到哪個服務(wù)中
3大磺、查詢路由抡句,客戶端隨機訪問一臺服務(wù),由服務(wù)決定是自己處理還是路由到其它服務(wù)器杠愧。Redis Cluster實現(xiàn)了混合形式的查詢路由待榔,也就是在查詢路由的基礎(chǔ)上,添加一個緩存表流济,這張表會逐步記錄key與服務(wù)器之間的關(guān)系锐锣。比如客戶端首先將key1發(fā)往服務(wù)器A,然后服務(wù)器A發(fā)現(xiàn)key1應(yīng)該由服務(wù)器B處理绳瘟,它會將這個路由信息告訴客戶端雕憔,客戶端緩存表會記錄key1由服務(wù)器B處理,當(dāng)?shù)诙尾樵僰ey1的時候糖声,客戶端會直接請求服務(wù)器B橘茉。
分片實現(xiàn)方案:
1、一致性哈希算法姨丈,這個算法在分布式應(yīng)用中比較廣泛畅卓,可以動態(tài)擴容和縮容。但是這個算法不太適合將Redis用來存儲持久化數(shù)據(jù)蟋恬,主要是因為這個算法沒有數(shù)據(jù)遷移功能翁潘。比如原本key1存儲在服務(wù)器A,擴容后key1需要存儲在服務(wù)器B歼争,這時key1的數(shù)據(jù)在邏輯上已經(jīng)丟失了拜马。這個算法最適合將Redis用來緩存數(shù)據(jù),第一個是因為這個算法在擴容和縮容時只會影響一部分key的映射沐绒,第二個受影響的key就算丟失了數(shù)據(jù)也不會對應(yīng)用造成影響俩莽,第三個通過對key設(shè)置過期時間,那些受影響的key的老數(shù)據(jù)會自動刪除乔遮。
2扮超、預(yù)分片,這個方案比較適合將Redis用來存儲持久化數(shù)據(jù)。預(yù)分片的原理就是提前預(yù)測好未來需要多少臺Redis服務(wù)出刷。假設(shè)未來最多需要10臺服務(wù)器璧疗,那么在一開始的時候就在一臺服務(wù)器上開啟10個Redis服務(wù)。等到內(nèi)存不夠的時候馁龟,準(zhǔn)備一臺新的服務(wù)器崩侠,將5個Redis服務(wù)遷移到新的服務(wù)器中,通過Redis的數(shù)據(jù)備份坷檩、主從復(fù)制等功能這個方案完全可以實現(xiàn)却音。一致性哈希算法也可以用作預(yù)分片的哈希算法,只要限制它擴容或縮容矢炼。
分片缺點:
1僧家、涉及多個key的操作通常不允許,比如集合的交集裸删、差集等操作八拱。主要是分片后多個key不在同一服務(wù)中,分片之間也不可能移動數(shù)據(jù)涯塔。
2肌稻、同時操作多個key,則不能使用Redis事務(wù)匕荸。
3爹谭、數(shù)據(jù)備份會比較復(fù)雜,因為現(xiàn)在數(shù)據(jù)分散在各個分片中榛搔。
4诺凡、不太支持動態(tài)擴容或縮容,只能在一定條件下使用践惑。

四腹泌、Redis Cluster

Redis Cluster是官方實現(xiàn)的一種分片方案。它沒有使用一致性哈希算法尔觉,而是使用了一種叫哈希槽的概念凉袱。Redis Cluster一共有16384個哈希槽,然后使用CRC16(key) mod 16384來計算每個key所對應(yīng)的哈希槽侦铜。Redis Cluster中的每個節(jié)點(redis服務(wù))都會負責(zé)維護一部分哈希槽专甩,比如你的集群中有3個節(jié)點,那么:

  • Node A contains hash slots from 0 to 5500.
  • Node B contains hash slots from 5501 to 11000.
  • Node C contains hash slots from 11001 to 16383.

假如你通過CRC16(key) mod 16384算出來的結(jié)果是5501钉稍,那么當(dāng)你第一次查詢的時候客戶端會隨機訪問一個節(jié)點涤躲,比如Node A,它會首先查看5501是否由自己負責(zé)贡未,如果是就直接處理种樱,如果不是就告訴客戶端Node B負責(zé)處理蒙袍,客戶端需要重新向Node B發(fā)送請求。
Redis Cluster相比之前的分片方案缸托,它具有高擴展性和伸縮性左敌,一致性哈希算法也可以擴展和伸縮但是它無法遷移數(shù)據(jù)瘾蛋。比如現(xiàn)在有A俐镐、B、C三個節(jié)點哺哼,你需要添加D佩抹,那么首先將D添加到集群中,然后從A取董、B棍苹、C中分別遷移一部分哈希槽到D(哈希槽所關(guān)聯(lián)的數(shù)據(jù)會一同轉(zhuǎn)移)。如果要刪除節(jié)點A茵汰,首先需要將A負責(zé)的哈希槽移動到B 枢里、C,然后就可以關(guān)閉節(jié)點A蹂午。
Redis Cluster允許你在一定范圍內(nèi)執(zhí)行涉及多個key的操作栏豺,包括交集、差集豆胸、事務(wù)等操作奥洼,只要你所操作的key都關(guān)聯(lián)到同一哈希槽。這個可以通過hash tags的技術(shù)強制將不同的key映射到同一哈希槽晚胡。比如hello{word}灵奖、say{word}、test{word}這3個key用來計算哈希槽的部分不是整體估盘,而是包圍在花括號中的word瓷患,這樣它們所關(guān)聯(lián)的哈希槽就是同一個。
Redis Cluster使用主從模式來備份數(shù)據(jù)和提供可靠性遣妥,假設(shè)有A尉尾、B、C三個主節(jié)點燥透,以及A1沙咏、B1、C1三個從節(jié)點班套,那么每個節(jié)點都有一個備份從節(jié)點肢藐,如果A節(jié)點宕機了,那么A1會被推選為新的主節(jié)點替換A節(jié)點吱韭。當(dāng)然如果A1也宕機了吆豹,那么集群將停止工作鱼的。
Redis Cluster無法保證數(shù)據(jù)的強一致性,也就是說在一些條件下集群已經(jīng)對客戶端確認的寫入依然會丟失痘煤。假設(shè)有A凑阶、B、C三個主節(jié)點衷快,以及A1宙橱、B1、C1三個從節(jié)點蘸拔,A接收寫入并且向客戶端確認师郑,在A向A1同步數(shù)據(jù)前宕機了,然后A1被推選為新的主節(jié)點替換A调窍,那么剛剛的寫入數(shù)據(jù)將丟失宝冕。類似的情況也會發(fā)生在網(wǎng)絡(luò)分區(qū)階段,主節(jié)點少部分的分區(qū)一般也會丟失一部分數(shù)據(jù)邓萨。不過集群對數(shù)據(jù)丟失會限制在一定時間窗口內(nèi)地梨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市缔恳,隨后出現(xiàn)的幾起案子宝剖,更是在濱河造成了極大的恐慌,老刑警劉巖褐耳,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诈闺,死亡現(xiàn)場離奇詭異,居然都是意外死亡铃芦,警方通過查閱死者的電腦和手機雅镊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刃滓,“玉大人仁烹,你說我怎么就攤上這事∵只ⅲ” “怎么了卓缰?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長砰诵。 經(jīng)常有香客問我征唬,道長,這世上最難降的妖魔是什么茁彭? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任总寒,我火速辦了婚禮,結(jié)果婚禮上理肺,老公的妹妹穿的比我還像新娘摄闸。我一直安慰自己善镰,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布年枕。 她就那樣靜靜地躺著炫欺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熏兄。 梳的紋絲不亂的頭發(fā)上品洛,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音霍弹,去河邊找鬼毫别。 笑死娃弓,一個胖子當(dāng)著我的面吹牛典格,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播台丛,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耍缴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挽霉?” 一聲冷哼從身側(cè)響起防嗡,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侠坎,沒想到半個月后蚁趁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡实胸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年他嫡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庐完。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡钢属,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出门躯,到底是詐尸還是另有隱情淆党,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布讶凉,位于F島的核電站染乌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏懂讯。R本人自食惡果不足惜荷憋,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望域醇。 院中可真熱鬧台谊,春花似錦蓉媳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盐须,卻和暖如春玩荠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贼邓。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工阶冈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人塑径。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓女坑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親统舀。 傳聞我的和親對象是個殘疾皇子匆骗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容