新聞中心
小編給大家分享一下redis事務支持ACID嗎,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
鷹手營子網(wǎng)站建設公司創(chuàng)新互聯(lián),鷹手營子網(wǎng)站設計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為鷹手營子成百上千提供企業(yè)網(wǎng)站建設服務。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設公司要多少錢,請找那個售后服務好的鷹手營子做網(wǎng)站的公司定做!
什么是事務的 ACID
鬼吹燈之《云南蟲谷》中的摸金校尉有句話叫「合則生,分則死」,為了尋找雮塵珠他們?nèi)朔止っ鞔_、齊心協(xié)力共進退方可成功。
事務(Transaction)是并發(fā)控制單位,一個操作序列組合而成,這些操作要么都執(zhí)行,要么都不執(zhí)行?!鞠嚓P推薦:Redis視頻教程】
「是一個不可分割的工作單位」。
事務在執(zhí)行時,會提供專門的屬性保證:
原子性(Atomicity):一個事務的多個操作必須完成,或者都不完成(ps:MySQL 的原子性靠什么實現(xiàn)呢?歡迎留言區(qū)評論);
一致性(Consistency):事務執(zhí)行結束后,數(shù)據(jù)庫的完整性約束沒有被破壞,事務執(zhí)行的前后順序都是合法數(shù)據(jù)狀態(tài)。
數(shù)據(jù)庫的完整性約束包括但不限于:
實體完整性(如行的主鍵存在且唯一);
列完整性(如字段的類型、大小、長度要符合要求)
外鍵約束;
用戶自定義完整性(如轉賬前后,兩個賬戶余額的和應該不變)。
隔離性(Isolation):事務內(nèi)部的操作與其他事務是隔離的,并發(fā)執(zhí)行的各個事務之間不能互相干擾。
講究的是不同事務之間的相互影響,嚴格的隔離性對應隔離級別中的可串行化(Serializable)。
持久性(Durability):事務一旦提交,所有的修改將永久的保存到數(shù)據(jù)庫中,即使系統(tǒng)崩潰重啟后數(shù)據(jù)也不會丟失。
碼哥,了解了 ACID 的具體要求后,Redis 是如何實現(xiàn)事務機制呢?
Redis 如何實現(xiàn)事務
MULTI、EXEC、DISCARD 和 WATCH 命令是 Redis 實現(xiàn)事務的的基礎。
Redis 事務的執(zhí)行過程包含三個步驟:
開啟事務;
命令入隊;
執(zhí)行事務或丟棄;
顯式開啟一個事務
客戶端通過 MULTI
命令顯式地表示開啟一個事務,隨后的命令將排隊緩存,并不會實際執(zhí)行。
命令入隊
客戶端把事務中的要執(zhí)行的一系列指令發(fā)送到服務端。
需要注意的是,雖然指令發(fā)送到服務端,但是 Redis 實例只是把這一系列指令暫存在一個命令隊列中,并不會立刻執(zhí)行。
執(zhí)行事務或丟棄
客戶端向服務端發(fā)送提交或者丟棄事務的命令,讓 Redis 執(zhí)行第二步中發(fā)送的具體指令或者清空隊列命令,放棄執(zhí)行。
Redis 只需在調(diào)用 EXEC 時,即可安排隊列命令執(zhí)行。
也可通過 DISCARD 丟棄第二步中保存在隊列中的命令。
Redis 事務案例
通過在線調(diào)試網(wǎng)站執(zhí)行我們的樣例代碼:try.redis.io
正常執(zhí)行
通過 MULTI
和 EXEC
執(zhí)行一個事務過程:
# 開啟事務 > MULTI OK # 開始定義一些列指令 > SET “公眾號:碼哥字節(jié)” "粉絲 100 萬" QUEUED > SET "order" "30" QUEUED > SET "文章數(shù)" 666 QUEUED > GET "文章數(shù)" QUEUED # 實際執(zhí)行事務 > EXEC 1) OK 2) OK 3) OK 4) "666"
我們看到每個讀寫指令執(zhí)行后的返回結果都是 QUEUED
,表示謝謝操作都被暫存到了命令隊列,還沒有實際執(zhí)行。
當執(zhí)行了 EXEC
命令,就可以看到具體每個指令的響應數(shù)據(jù)。
放棄事務
通過 MULTI
和 DISCARD
丟棄隊列命令:
# 初始化訂單數(shù) > SET "order:mobile" 100 OK # 開啟事務 > MULTI OK # 訂單 - 1 > DECR "order:mobile" QUEUED # 丟棄丟列命令 > DISCARD OK # 數(shù)據(jù)沒有被修改 > GET "order:mobile" "100"
碼哥,Redis 的事務能保證 ACID 特性么?
這個問題問得好,我們一起來分析下。
Redis 事務滿足 ACID?
Redis 事務可以一次執(zhí)行多個命令, 并且?guī)в幸韵氯齻€重要的保證:
批量指令在執(zhí)行 EXEC 命令之前會放入隊列暫存;
收到 EXEC 命令后進入事務執(zhí)行,事務中任意命令執(zhí)行失敗,其余的命令依然被執(zhí)行;
事務執(zhí)行過程中,其他客戶端提交的命令不會插入到當前命令執(zhí)行的序列中。
原子性
碼哥,如果事務執(zhí)行過程中發(fā)生錯誤了,原子性能保證么?
在事務期間,可能遇到兩種命令錯誤:
在執(zhí)行
EXEC
命令前,發(fā)送的指令本身就錯誤。如下:參數(shù)數(shù)量錯誤;
命令名稱錯誤,使用了不存在的命令;
內(nèi)存不足(Redis 實例使用
maxmemory
指令配置內(nèi)存限制)。在執(zhí)行
EXEC
命令后,命令可能會失敗。例如,命令和操作的數(shù)據(jù)類型不匹配(對 String 類型 的 value 執(zhí)行了 List 列表操作);在執(zhí)行事務的
EXEC
命令時。 Redis 實例發(fā)生了故障導致事務執(zhí)行失敗。
EXEC 執(zhí)行前報錯
在命令入隊時,Redis 就會報錯并且記錄下這個錯誤。
此時,我們還能繼續(xù)提交命令操作。
等到執(zhí)行了 EXEC
命令之后,Redis 就會拒絕執(zhí)行所有提交的命令操作,返回事務失敗的結果。
這樣一來,事務中的所有命令都不會再被執(zhí)行了,保證了原子性。
如下是指令入隊發(fā)生錯誤,導致事務失敗的例子:
#開啟事務 > MULTI OK #發(fā)送事務中的第一個操作,但是Redis不支持該命令,返回報錯信息 127.0.0.1:6379> PUT order 6 (error) ERR unknown command `PUT`, with args beginning with: `order`, `6`, #發(fā)送事務中的第二個操作,這個操作是正確的命令,Redis把該命令入隊 > DECR b:stock QUEUED #實際執(zhí)行事務,但是之前命令有錯誤,所以Redis拒絕執(zhí)行 > EXEC (error) EXECABORT Transaction discarded because of previous errors.
EXEC 執(zhí)行后報錯
事務操作入隊時,命令和操作的數(shù)據(jù)類型不匹配,但 Redis 實例沒有檢查出錯誤。
但是,在執(zhí)行完 EXEC 命令以后,Redis 實際執(zhí)行這些指令,就會報錯。
敲黑板了:Redis 雖然會對錯誤指令報錯,但是事務依然會把正確的命令執(zhí)行完,這時候事務的原子性就無法保證了!
碼哥,為什么 Redis 不支持回滾?
其實,Redis 中并沒有提供回滾機制。雖然 Redis 提供了 DISCARD 命令。
但是,這個命令只能用來主動放棄事務執(zhí)行,把暫存的命令隊列清空,起不到回滾的效果。
EXEC 執(zhí)行時,發(fā)生故障
如果 Redis 開啟了 AOF 日志,那么,只會有部分的事務操作被記錄到 AOF 日志中。
我們需要使用 redis-check-aof 工具檢查 AOF 日志文件,這個工具可以把未完成的事務操作從 AOF 文件中去除。
這樣一來,我們使用 AOF 恢復實例后,事務操作不會再被執(zhí)行,從而保證了原子性。
簡單總結:
命令入隊時就報錯,會放棄事務執(zhí)行,保證原子性;
命令入隊時沒報錯,實際執(zhí)行時報錯,不保證原子性;
EXEC 命令執(zhí)行時實例故障,如果開啟了 AOF 日志,可以保證原子性。
一致性
一致性會受到錯誤命令、實例故障發(fā)生時機的影響,按照命令出錯實例故障兩個維度的發(fā)生時機,可以分三種情況分析。
EXEC 執(zhí)行前,入隊報錯
事務會被放棄執(zhí)行,所以可以保證一致性。
EXEC 執(zhí)行后,實際執(zhí)行時報錯
有錯誤的執(zhí)行不會執(zhí)行,正確的指令可以正常執(zhí)行,一致性可以保證。
EXEC 執(zhí)行時,實例故障
實例故障后會進行重啟,這就和數(shù)據(jù)恢復的方式有關了,我們要根據(jù)實例是否開啟了 RDB 或 AOF 來分情況討論下。
如果我們沒有開啟 RDB 或 AOF,那么,實例故障重啟后,數(shù)據(jù)都沒有了,數(shù)據(jù)庫是一致的。
如果我們使用了 RDB 快照,因為 RDB 快照不會在事務執(zhí)行時執(zhí)行。
所以,事務命令操作的結果不會被保存到 RDB 快照中,使用 RDB 快照進行恢復時,數(shù)據(jù)庫里的數(shù)據(jù)也是一致的。
如果我們使用了 AOF 日志,而事務操作還沒有被記錄到 AOF 日志時,實例就發(fā)生了故障,那么,使用 AOF 日志恢復的數(shù)據(jù)庫數(shù)據(jù)是一致的。
如果只有部分操作被記錄到了 AOF 日志,我們可以使用 redis-check-aof 清除事務中已經(jīng)完成的操作,數(shù)據(jù)庫恢復后也是一致的。
隔離性
事務執(zhí)行又可以分成命令入隊(EXEC 命令執(zhí)行前)和命令實際執(zhí)行(EXEC 命令執(zhí)行后)兩個階段。
所以在并發(fā)執(zhí)行的時候我們針對這兩個階段分兩種情況分析:
并發(fā)操作在
EXEC
命令前執(zhí)行,隔離性需要通過WATCH
機制保證;并發(fā)操作在
EXEC
命令之后,隔離性可以保證。
碼哥,什么是 WATCH 機制?
我們重點來看第一種情況:一個事務的 EXEC 命令還沒有執(zhí)行時,事務的命令操作是暫存在命令隊列中的。
此時,如果有其它的并發(fā)操作,同樣的 key 被修改,需要看事務是否使用了 WATCH
機制。
WATCH 機制的作用是:在事務執(zhí)行前,監(jiān)控一個或多個鍵的值變化情況,當事務調(diào)用 EXEC 命令執(zhí)行時,WATCH 機制會先檢查監(jiān)控的鍵是否被其它客戶端修改了。
如果修改了,就放棄事務執(zhí)行,避免事務的隔離性被破壞。
同時,客戶端可以再次執(zhí)行事務,此時,如果沒有并發(fā)修改事務數(shù)據(jù)的操作了,事務就能正常執(zhí)行,隔離性也得到了保證。
沒有 WATCH
如果沒有 WATCH 機制, 在 EXEC 命令執(zhí)行前的并發(fā)操作對數(shù)據(jù)讀寫。
當執(zhí)行 EXEC 的時候,事務內(nèi)部要操作的數(shù)據(jù)已經(jīng)改變,Redis 并沒有做到事務之間的隔離。
并發(fā)操作在 EXEC 之后接收執(zhí)行
至于第二種情況,因為 Redis 是用單線程執(zhí)行命令,而且,EXEC 命令執(zhí)行后,Redis 會保證先把命令隊列中的所有命令執(zhí)行完再執(zhí)行之后的指令。
所以,在這種情況下,并發(fā)操作不會破壞事務的隔離性。
持久性
如果 Redis 沒有使用 RDB 或 AOF,那么事務的持久化屬性肯定得不到保證。
如果 Redis 使用了 RDB 模式,那么,在一個事務執(zhí)行后,而下一次的 RDB 快照還未執(zhí)行前,如果發(fā)生了實例宕機,數(shù)據(jù)丟失,這種情況下,事務修改的數(shù)據(jù)也是不能保證持久化的。
如果 Redis 采用了 AOF 模式,因為 AOF 模式的三種配置選項 no、everysec 和 always 都會存在數(shù)據(jù)丟失的情況。
所以,事務的持久性屬性也還是得不到保證。
不管 Redis 采用什么持久化模式,事務的持久性屬性是得不到保證的。
總結
Redis 具備了一定的原子性,但不支持回滾。
Redis 不具備 ACID 中一致性的概念。(或者說 Redis 在設計時就無視這點)
Redis 具備隔離性。
Redis 無法保證持久性。
Redis 的事務機制可以保證一致性和隔離性,但是無法保證持久性。
不過,因為 Redis 本身是內(nèi)存數(shù)據(jù)庫,持久性并不是一個必須的屬性,我們更加關注的還是原子性、一致性和隔離性這三個屬性。
原子性的情況比較復雜,當事務中使用的命令語法有誤時,原子性得不到保證,在其它情況下,事務都可以原子性執(zhí)行。
以上是“Redis事務支持ACID嗎”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
分享標題:Redis事務支持ACID嗎
文章路徑:http://www.dlmjj.cn/article/gjpsse.html