Redis實(shí)例發(fā)生故障,而Redis使用RDB機(jī)制,事務(wù)的原子性能否得到保證?

宮粽號(hào):堆棧future

Redis實(shí)例發(fā)生故障,而Redis使用的RDB機(jī)制,事務(wù)的原子性還能否得到保證?


干貨:[公粽號(hào):堆棧future]

Redis事務(wù)講解

Redis原子性保證


當(dāng)Redis采用RDB機(jī)制保證數(shù)據(jù)可靠性時(shí),Redis會(huì)按照一定的周期執(zhí)行內(nèi)存快照。

一個(gè)事務(wù)在執(zhí)行過程中,事務(wù)操作對(duì)數(shù)據(jù)所做的修改并不會(huì)實(shí)時(shí)地記錄到RDB中,而且,Redis也不會(huì)創(chuàng)建RDB快照。我們可以根據(jù)故障發(fā)生的時(shí)機(jī)以及RDB是否生成,分成三種情況來討論事務(wù)的原子性保證。

  1. 假設(shè)事務(wù)在執(zhí)行到一半時(shí),實(shí)例發(fā)生了故障,在這種情況下,上一次RDB快照中不會(huì)包含事務(wù)所做的修改,而下一次RDB快照還沒有執(zhí)行。所以,實(shí)例恢復(fù)后,事務(wù)修改的數(shù)據(jù)會(huì)丟失,事務(wù)的原子性能得到保證。

  2. 假設(shè)事務(wù)執(zhí)行完成后,RDB快照已經(jīng)生成了,如果實(shí)例發(fā)生了故障,事務(wù)修改的數(shù)據(jù)可以從RDB中恢復(fù),事務(wù)的原子性也就得到了保證。

  3. 假設(shè)事務(wù)執(zhí)行已經(jīng)完成,但是RDB快照還沒有生成,如果實(shí)例發(fā)生了故障,那么,事務(wù)修改的數(shù)據(jù)就會(huì)全部丟失,也就談不上原子性了。

Redis的事務(wù)到底是什么? Redis提供了MULTI、EXEC兩個(gè)命令來完成這三個(gè)步驟。下面我們來分析下。

  • 第一步,客戶端要使用一個(gè)命令顯式地表示一個(gè)事務(wù)的開啟。在Redis中,這個(gè)命令就是MULTI。
  • 第二步,客戶端把事務(wù)中本身要執(zhí)行的具體操作(例如增刪改數(shù)據(jù))發(fā)送給服務(wù)器端。這些操作就是Redis本身提供的數(shù)據(jù)讀寫命令,例如GET、SET等。不過,這些命令雖然被客戶端發(fā)送到了服務(wù)器端,但Redis實(shí)例只是把這些命令暫存到一個(gè)命令隊(duì)列中,并不會(huì)立即執(zhí)行。
  • 第三步,客戶端向服務(wù)器端發(fā)送提交事務(wù)的命令,讓數(shù)據(jù)庫實(shí)際執(zhí)行第二步中發(fā)送的具體操作。Redis 提供的EXEC命令就是執(zhí)行事務(wù)提交的。當(dāng)服務(wù)器端收到EXEC命令后,才會(huì)實(shí)際執(zhí)行命令隊(duì)列中的所有命令。

了解了Redis的事務(wù)之后我們看下它如何滿足ACID特性之一:原子性的(A)。

  1. 第一種情況是,在執(zhí)行EXEC命令前,客戶端發(fā)送的操作命令本身就有錯(cuò)誤(比如語法錯(cuò)誤,使用了不存在的命令),在命令入隊(duì)時(shí)就被Redis實(shí)例判斷出來了。等到執(zhí)行了EXEC命令之后,Redis就會(huì)拒絕執(zhí)行所有提交的命令操作,返回事務(wù)失敗的結(jié)果。這樣一來,事務(wù)中的所有命令都不會(huì)再被執(zhí)行了,保證了原子性。
#開啟事務(wù)
127.0.0.1:6379> MULTI
OK
#發(fā)送事務(wù)中的第一個(gè)操作,但是Redis不支持該命令,返回報(bào)錯(cuò)信息
127.0.0.1:6379> PUT a:stock 5
(error) ERR unknown command `PUT`, with args beginning with: `a:stock`, `5`, 
#發(fā)送事務(wù)中的第二個(gè)操作,這個(gè)操作是正確的命令,Redis把該命令入隊(duì)
127.0.0.1:6379> DECR b:stock
QUEUED
#實(shí)際執(zhí)行事務(wù),但是之前命令有錯(cuò)誤,所以Redis拒絕執(zhí)行
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
  1. 第一種情況是,事務(wù)操作入隊(duì)時(shí),命令和操作的數(shù)據(jù)類型不匹配,但Redis實(shí)例沒有檢查出錯(cuò)誤。但是,在執(zhí)行完EXEC命令以后,Redis實(shí)際執(zhí)行這些事務(wù)操作時(shí),就會(huì)報(bào)錯(cuò)。不過,需要注意的是,雖然Redis 會(huì)對(duì)錯(cuò)誤命令報(bào)錯(cuò),但還是會(huì)把正確的命令執(zhí)行完。在這種情況下,事務(wù)的原子性就無法得到保證了。
#開啟事務(wù)
127.0.0.1:6379> MULTI
OK
#發(fā)送事務(wù)中的第一個(gè)操作,LPOP命令操作的數(shù)據(jù)類型不匹配,此時(shí)并不報(bào)錯(cuò)
127.0.0.1:6379> LPOP a:stock
QUEUED
#發(fā)送事務(wù)中的第二個(gè)操作
127.0.0.1:6379> DECR b:stock
QUEUED
#實(shí)際執(zhí)行事務(wù),事務(wù)第一個(gè)操作執(zhí)行報(bào)錯(cuò)
127.0.0.1:6379> EXEC
1) (error) WRONGTYPE Operation against a key holding the wrong kind of value
2) (integer) 8
  1. 最后,我們?cè)賮砜聪碌谌N情況:在執(zhí)行事務(wù)的EXEC命令時(shí),Redis實(shí)例發(fā)生了故障,導(dǎo)致事務(wù)執(zhí)行失敗。 在這種情況下,如果Redis開啟了AOF日志,那么,只會(huì)有部分的事務(wù)操作被記錄到AOF日志中。我們需要使用redis-check-aof工具檢查AOF日志文件,這個(gè)工具可以把未完成的事務(wù)操作從AOF文件中去除。這樣一來,我們使用AOF恢復(fù)實(shí)例后,事務(wù)操作不會(huì)再被執(zhí)行,從而保證了原子性。當(dāng)然,如果AOF日志并沒有開啟,那么實(shí)例重啟后,數(shù)據(jù)也都沒法恢復(fù)了,此時(shí),也就談不上原子性了。

總結(jié)下Redis原子性保證情況如下

  • 命令入隊(duì)時(shí)就報(bào)錯(cuò),會(huì)放棄事務(wù)執(zhí)行,保證原子性;
  • 命令入隊(duì)時(shí)沒報(bào)錯(cuò),實(shí)際執(zhí)行時(shí)報(bào)錯(cuò),不保證原子性;
  • EXEC命令執(zhí)行時(shí)實(shí)例故障,如果開啟了AOF日志,可以保證原子性。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容