作者 | Video++極鏈科后端Team劉聰
整理 | 包包
所謂事務(wù)(Transaction) ,是指作為單個(gè)邏輯工作單元執(zhí)行的一系列操作。事務(wù)必須滿足ACID原則(原子性、一致性、隔離性和持久性)。簡(jiǎn)單來說事務(wù)其實(shí)就是打包一組操作(或者命令)作為一個(gè)整體,在事務(wù)處理時(shí)將順序執(zhí)行這些操作,并返回結(jié)果,如果其中任何一個(gè)環(huán)節(jié)出錯(cuò),所有的操作將被回滾。
在Redis中實(shí)現(xiàn)事務(wù)主要依靠以下幾個(gè)命令來實(shí)現(xiàn):
Redis事務(wù)從開始到結(jié)束通常會(huì)通過三個(gè)階段:
1.事務(wù)開始
2.命令入隊(duì)
3.事務(wù)執(zhí)行
以下是一個(gè)最簡(jiǎn)單的Redis事務(wù)流程:
第一步跟其他的關(guān)系型數(shù)據(jù)庫類似,也是需要開啟一個(gè)事務(wù),在Redis中的命令如下:
Redis中使用MULTI命令標(biāo)記事務(wù)的開始,可以理解為在傳統(tǒng)關(guān)系型數(shù)據(jù)庫中的BEGIN TRANCATION語句,Redis將執(zhí)行該命令的客戶端從非事務(wù)狀態(tài)切換成事務(wù)狀態(tài),這一切換是通過在客戶端狀態(tài)的flags屬性中打開REDIS_MULTI標(biāo)識(shí)完成, 我們看下Redis中對(duì)應(yīng)部分的源碼實(shí)現(xiàn):
在打開事務(wù)標(biāo)識(shí)的客戶端里,這些命令都會(huì)被暫存到一個(gè)命令隊(duì)列里,不會(huì)因?yàn)橛脩魰?huì)的輸入而立即執(zhí)行。
第二步就是執(zhí)行事務(wù)內(nèi)路基,即真正的業(yè)務(wù)邏輯:
最后一個(gè)階段是提交事務(wù)(或者回滾事務(wù)):
這兩個(gè)命令可被視為等同于關(guān)系型數(shù)據(jù)庫中的COMMIT/ROLLBACK語句。
這里需要注意的是,在客戶端打開了事務(wù)標(biāo)識(shí)后,只有命令:EXEC,DISCARD,WATCH,MULTI命令會(huì)被立即執(zhí)行,其它命令服務(wù)器不會(huì)立即執(zhí)行,而是將這些命令放入到一個(gè)事務(wù)隊(duì)列里面,然后向客戶端返回一個(gè)QUEUED回復(fù) ;Redis客戶端有自己的事務(wù)狀態(tài),這個(gè)狀態(tài)保存在客戶端狀態(tài)mstate屬性中,mstate的結(jié)構(gòu)體類型是multiState,我們看下multiState的定義:
我們?cè)倏聪陆Y(jié)構(gòu)體類型multiCmd的結(jié)構(gòu):
事務(wù)隊(duì)列以先進(jìn)先出的保存方法,較先入隊(duì)的命令會(huì)被放到數(shù)組的前面,而較后入隊(duì)的命令則會(huì)被放到數(shù)組的后面。
當(dāng)開啟事務(wù)標(biāo)識(shí)的客戶端發(fā)送EXEC命令的時(shí)候,服務(wù)器就會(huì)執(zhí)行,客戶端對(duì)應(yīng)的事務(wù)隊(duì)列里的命令,我們來看下EXEC 的實(shí)現(xiàn)細(xì)節(jié):
最后我們?cè)倩仡櫼幌率聞?wù)本身的特性, 在傳統(tǒng)關(guān)系型數(shù)據(jù)庫中的事務(wù)必須依靠ACID來保證事務(wù)的可靠性和安全性,在Redis中事務(wù)總是具有一致性(Consistency)和隔離性(Isolation),并且當(dāng)Redis運(yùn)行在某種特定的持久化模式下,事務(wù)也具有耐久性(Durability); 但是并不總是能夠保證原子性(Atomicity),在正常狀態(tài)下一個(gè)事務(wù)的所有命令是能按照原子性的原則執(zhí)行的,但是執(zhí)行的中途遇到錯(cuò)誤,不會(huì)回滾,而是繼續(xù)執(zhí)行后續(xù)命令, 如下:
如果在set k2 v2處失敗,set k1已成功不會(huì)回滾,set k3還會(huì)繼續(xù)執(zhí)行;Redis的事務(wù)和傳統(tǒng)的關(guān)系型數(shù)據(jù)庫事務(wù)的最大區(qū)別在于,Redis不支持事務(wù)的回滾機(jī)制,即使事務(wù)隊(duì)列中的某個(gè)命令在執(zhí)行期間出現(xiàn)錯(cuò)誤,整個(gè)事務(wù)也會(huì)繼續(xù)執(zhí)行下去,直到將事務(wù)隊(duì)列中的所有命令都執(zhí)行完畢為止,我們看下面的例子:
Redis的作者在事務(wù)功能的文檔中解釋說,不支持事務(wù)回滾是因?yàn)檫@種復(fù)雜的功能和Redis追求的簡(jiǎn)單高效的設(shè)計(jì)主旨不符合,并且他認(rèn)為,Redis事務(wù)的執(zhí)行時(shí),錯(cuò)誤通常都是編程錯(cuò)誤造成的,這種錯(cuò)誤通常只會(huì)出現(xiàn)在開發(fā)環(huán)境中,而很少會(huì)在實(shí)際的生產(chǎn)環(huán)境中出現(xiàn),所以他認(rèn)為沒有必要為Redis開發(fā)事務(wù)回滾功能。所以我們?cè)谟懻揜edis事務(wù)回滾的時(shí)候,一定要區(qū)分命令發(fā)生錯(cuò)誤的時(shí)候。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論