Redis事務

Redis通過MULTIEXECWATCH等命令來實現事務(transaction)功能。事務提供了一種將多個命令請求打包,然后一次性、按順序地執行多個命令的機制,并且在事務執行期間,服務器不會中斷事務而去執行其他客戶端命令。

1 事務的實現

??一個事務從開始到結束通常經歷三個階段:

(1) 事務開始

(2) 命令入隊

(3) 事務執行

??1.1 事務開始

MULTI命令的執行標志著事務的開始:

127.0.0.1:6379> MULTIOK

MULTI命令可以將執行該命令的客戶端從非事務狀態切換至事務狀態。

??1.2 命令入隊

??當一個客戶端處于非事務狀態時,這個客戶端的命令會立即被服務器執行。與此不同的是,當一個客戶端切換到事務狀態之后,服務器會根據這個客戶端發來的不同的命令執行不同的操作:

(1) 如果客戶端發送的命令為EXECDISCARDWATCHMULTI四個命令中的其中一個,那么服務器會立即執行這個命令。

(2) 如果客戶端發送的命令是EXECDISCARDWATCHMULTI四個命令以為的其他命令,那么服務器不會立即執行這個命令,而是將這個命令放在一個事務隊列中,然后向客戶端返回QUEUED回復。

服務器判斷命令是該入隊還是該執行的過程

??1.3 事務隊列

??事務隊列是一個以先進先出(FIFO)的方式保存入隊的命令,較先入隊的命令會被放到數組的前面,而較后入隊的命令則會被放到數組的后面。例如:

127.0.0.1:6379>> MULTIOK127.0.0.1:6379>> set name Redis;

127.0.0.1:6379>> get name;

127.0.0.1:6379>> set author"Peter Seibei";

127.0.0.1:6379>> get author;

那么服務器器將會為客戶端創建一個事務隊列,將上面4條命令入隊,最先入隊的SET命令放在事務隊列的最前面……:

事務隊列

??1.4 執行事務

當一個處于事務狀態的客戶端向服務器發送EXEC命令時,這個EXEC命令將立即被服務器執行。服務器會遍歷這個客戶端的事務隊列,執行隊列中保存的所有的命令,最后將執行命令所得的結果返回給客戶端。對于上例子:

127.0.0.1:6379> EXEC1)

OK2)

"Redis"3)

OK4)

"Peter Seibei"

2 WATCH命令的實現

WATCH命令是一個樂觀所(optimistic locking),它可以在EXEC命令執行前,監視任意數量的數據庫鍵,并在EXEC命令執行時,檢查監視的鍵是否至少有一個已經被修改過了,如果修改過了,服務器將拒絕執行事務,并向客戶端返回代表事務執行失敗的空回復。例如,下面的事務將會執行失敗:

127.0.0.1:6379>> WATCH

?nameOK

127.0.0.1:6379>> MULTI

OK

127.0.0.1:6379>> set"name""Peter"

127.0.0.1:6379>> EXEC(nil)

時間客戶端A客戶端B

T1WATCH "name"

T2MULTI

T3SET "name" "Peter"

T4SET "name" "jack"

T5EXEC

在時間T4,客戶端B修改了"name"鍵的值,當客戶端A在T5執行EXEC命令時,服務器會發現WATCH監視的鍵“name”已經被修改,因此服務器拒絕執行客戶端A的事務,并向客戶端A返回空回復。

??2.1使用WATCH命令監視數據庫鍵

每個Redis數據庫保存著一個watched_keys字典,這個字典的鍵是某個被WATCH命令監視的數據庫鍵,而字典的值是一個鏈表,鏈表記錄了所有監視相應數據庫鍵的客戶端。

一個watched_keys字典

上圖表明:

(1) 客戶端c1和c2正在監視鍵“name”。

(2) 客戶端c3正在監視鍵“age”。

(3) 客戶端c2和c4正在監視鍵“address”。

??2.2 監視機制的觸發

所有對數據庫進行修改命令,如SET、LPUSH、SADD、ZREM、DEL等,在執行后都會對watched_keys字典進行檢查,查看被修改的數據庫鍵是否是被客戶端所監視的鍵,如果有的話,客戶端REDIS_DIRTY_CAS標識將會被打開,表示該客戶端的事務安全性已經被破壞。

??2.3 判斷事務是否安全

當服務器接收到一個客戶端發來的EXEC命令,服務器會根據這個客戶端是否打開了REDIS_DIRTY_CAS標識來決定是否執行事務:

(1) 如果客戶端的REDIS_DIRTY_ CAS標識已經被打開,那么說明客戶端所監視的鍵當中,至少有一個鍵已經被修改過了,在這種情況下,客戶端提交的事務已經不再安全,所以服務器拒絕執行客戶端提交的事務。

(2) 如果客戶端的REDIS_DIRTY_CAS標識沒有被打開,那么說明客戶端監視的所有鍵都沒有被修改過(或者客戶端沒有監視任何鍵),事務仍然是安全的,服務器將執行客戶端提交的這個事務。

3 事務的ACID性質

??在Redis中,事務總是具有原子性(Atomicity)、一致性(Consistency)和隔離性(Isolation),并且當Redis運行在某種特定的持久化模式下,事務也具有耐久性(Durability)。

??3.1 原子性

事務具有原子性指的是, 數據庫將事務中的多個操作當作一個整體來執行,服務器要么就執行事務中的所有操作, 要么就一個操作也不執行。

對于Redis的事務功能來說,事務隊列中的命令要么就全部都執行,要么就一個都不執行,因此, Redis的事務是具有原子性的。

下面是一個執行失敗的事務,這個事務因為命令入隊出錯而被服務器拒絕執行:

127.0.0.1:6379>multi

OK

127.0.0.1:6379>set msg hello

127.0.0.1:6379>get(error)ERRwrong number of argumentsfor'get'command

127.0.0.1:6379>get msg

127.0.0.1:6379>exec

(error) EXEC ABORT Transactiondiscarded because of previous errors.

Redis的事務和傳統的關系型數據庫事務的最大區別在于,Redis不支持事務回滾機制(rollback), 即使事務隊列中的某個命令在執行期間出現了錯誤,整個事務也會繼續執行下去,直到將事務隊列中的所有命令都執行完畢為止。

下面展示了即使RPUSH命令在執行期間出現了錯誤,事務的后續命令也會繼續執行下去, 并且之前執行的命令也不會有任何影響:

127.0.0.1:6379> set msg hello

OK

127.0.0.1:6379> multi

OK

127.0.0.1:6379> sadd fruit apple banana cherry

127.0.0.1:6379> rpush msg bye redis

127.0.0.1:6379> sadd alphabet a b c

127.0.0.1:6379> exec

1)(integer)3

2)(error)WRONGTYPE Operation against a key holding the wrong kind of value

3)(integer)3

??Redis為什么不支持回滾:不支持事務回滾是因為這種復雜的功能和Redis追求簡單高效的設計主旨不相符,并且Redis事務的執行時錯誤通常都是編程錯誤產生的, 這種錯誤通常只會出現在開發環境中, 而很少會在實際的生產環境中出現。

??3.2 一致性

??事務的一致性是指,如果數據庫執行前是一致的,那么在事務執行后,無論事務是否執行成功,數據庫也應該是一致的。

??3.2.1入隊錯誤

如果一個事務在入隊命令的過程中,出現了命令不存在,或者命令的格式不正確等情況, 那么Redis將拒絕執行這個事務。因為服務器會拒絕執行人隊過程中出現錯誤的事務, 所以Redis事務的一致性不會被帶有入隊錯誤的事務影響。

127.0.0.1:6379>multi

OK

127.0.0.1:6379>set msg?

hello

127.0.0.1:6379>YAHOOO

(error)ERRunknown command'YAHOOO'

127.0.0.1:6379>get msg

127.0.0.1:6379>exec

(error)EXECABORTTransactiondiscarded because of previous errors.

Redis 2.6.5以前的入隊錯誤處理:Redis會忽略錯誤的命令,而正確的命令如上面的SETGET仍然會被執行。

??3.2.2 執行錯誤

執行錯誤通常都是一些不能在入隊時被服務器發現的錯誤, 這些錯誤只會在命令實際執行時被觸發。即使在事務的執行過程中發生了錯誤, 服務器也不會中斷事務的執行, 它會繼續執行事務中余下的其他命令, 并且已執行的命令(包括執行命令所產生的結果)不會被出錯的命令影響。

因為在事務執行的過程中, 出錯的命令會被服務器識別出來, 并進行相應的錯誤處理, 所以這些出錯命令不會對數據庫做任何修改, 也不會對事務的一致性產生任何影響。

127.0.0.1:6379> set msg hello

OK

127.0.0.1:6379> multi

OK

127.0.0.1:6379> sadd fruit apple banana cherryQUEUED127.0.0.1:6379> rpush msg bye redis

QUEUED

127.0.0.1:6379> sadd alphabet a b c

QUEUED

127.0.0.1:6379> exec

1)(integer)3

2)(error)WRONGTYPE Operation against a key holding the wrong kind of value

3)(integer)3

??3.2.3 服務器停機

(1) 如果服務器運行在無持久化的內存模式下,那么重啟之后的數據庫將是空白的, 因此數據總是一致的。

(2) 如果服務器運行在RDB模式或AOF模式下, 那么在事務中途停機不會導致不一致,因為服務器可以根據RDB文件或AOF文件來回復數據,從而將數據庫還原到一個一致的狀態。

??3.3 隔離性

事務的隔離性指的是,即使數據庫中有多個事務并發地執行,各個事務之間也不會互相 影響,并且在并發狀態下執行的事務和串行執行的事務產生的結果完全相同。

因為Redis使用單線程的方式來執行事務(以及事務隊列中的命令),并且服務器保證, 在執行事務期間不會對事務進行中斷,因此,Redis的事務總是以串行的方式運行的,并且 事務也總是具有隔離性的。

??3.4 耐久性

事務的耐久性指的是,當一個事務執行完畢時,執行這個事務所得的結果巳經被保存到 永久性存儲介質(比如硬盤)里面了, 即使服務器在事務執行完畢 之后停機, 執行事務所得的結果也不會丟失。Redis事務的耐久性由服務器所使用持久化模式決定的:

(1) 當服務器在無持久化的內存模式下運作時,事務不具有耐久性。因為一旦服務器停機,

服務器所有的數據都將丟失。

(2) 當服務器在ROB持久化模式下運作時,事務同樣不具有耐久性。因為服務器只會在特定的保存條件下才會執行BGSAVE命令,并且異步執行的BGSAVE命令不能保證事務的數據第一時間被保存到硬盤上。

(3) 當服務器運行在AOF持久化模式下,并且appendfsync選項的值為always時,程序總會在執行命令之后調用同步(sync)函數,將命令數據真正地保存到硬盤里。

4 小結

(1) 事務提供了一種將多個命令打包,然后一次性、有序地執行的機制。

(2) 多個命令會被人隊到事務隊列中, 然后按先進先出(FIFO)的順序執行。

(3) 事務在執行過程中不會被中斷,當事務隊列中的所有命令都被執行完畢之后,事務

才會結束。

(4) 帶有WATCH命令的事務會將客戶端和被監視的鍵在數據庫的watched_keys字典關聯,當鍵被修改時,程序會將所有監視被修改鍵的客戶端的REDIS_DIRTY_CAS標識打開,服務只有在REDIS_DIRTY_CAS標識沒有打開時,才會執行客戶端提交的事務,否則服務器拒絕執行事務。

(5) Redis事務不支持回滾機制。

(6) Redis的事務總是具有ACID中的原子性、一致性和隔離性,當服務器運行在AOF持久化模式下,并且appendfsync選項的值為always時,事務也具有耐久性。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容