Redis系列1:深刻理解高效能Redis的本質
Redis系列2:資料持久化提高可用性
Redis系列3:高可用之主從架構
Redis系列4:高可用之Sentinel(哨兵模式)
Redis系列5:深入分析Cluster 叢集模式
追求效能極致:Redis6.0的多執行緒模型
追求效能極致:使用者端快取帶來的革命
Redis系列8:Bitmap實現億萬級資料計算
Redis系列9:Geo 型別賦能億級地圖位置計算
Redis系列10:HyperLogLog實現海量資料基數統計
Redis系列11:記憶體淘汰策略
Transaction(事務)是計算機的特有術語,它一般指單個邏輯工作單位,由一系列的操作組合而成,在這些操作執行的時候,要麼都執行成功,要麼都不執行,防止資料結果的不一致性。
簡而言之,事務是一個不可分割的工作邏輯單位。為了衡量工作單元是否具備事務能力,需要滿足四個特徵:ACID,即 原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、永續性(Durability)。
Redis 支援事務機制,他實現事務的關鍵命令包括:
MULTI、EXEC、DISCARD 、 WATCH
根據上述命令,Redis 事務的執行過程包含三個步驟:
Client 通過 MULTI 命令顯式開啟一個事務,隨後執行的操作將會暫時快取在Queue中,實際並沒有立即執行。
Client 端 把事務中的要執行的一系列操作指令傳送到Service 端。 Redis伺服器端 範例接收到指令之後,並不是馬上執行,而是暫存在命令佇列中。
當Client端向Service端傳送的命令都Ready了之後,可以傳送提交執行或者丟棄事務的命令,如果是執行則操作佇列中的具體指令,如果是丟棄則是清空佇列命令。
通過 MULTI 和 EXEC 執行一個事務過程:
#開啟事務
> MULTI
OK
# 定義一系列指令
> set 'name' 'brand'
QUEUED
> set 'age' 18
QUEUED
> INCR 'age'
QUEUED
> GET 'name'
QUEUED
> GET 'age'
QUEUED
# 實際執行事務
> EXEC
# 獲取執行結果
1) OK
2) OK
3) 19
4) "brand"
5) "19"
從上面可以看出來,每個讀寫指令執行後的返回結果都是 QUEUED,代表這些操作只是暫存在指令佇列中,並沒有實際執行。
當傳送了 EXEC 命令之後,才真正執行並獲取結果。
通過 MULTI 和 DISCARD 丟棄執行,清空指令佇列:
# 初始化訂資料
> SET 'name' 'brand'
OK
> SET 'age' 18
OK
# 開啟事務
> MULTI
OK
# 資料增量1
> INCR 'age'
QUEUED
# 丟棄
> DISCARD
OK
# 執行結果是增量前的資料
> get 'age'
"18"
體現原子性,再發生故障的時候,要麼執行都成功,要麼執行都失敗
# 開啟事務
> MULTI
OK
# 初始一個資料
> SET 'age' 18
OK
# 對該資料進行更新,但Redis不支援該命令,返回報錯資訊
> UPD 'age' 17
(error) ERR unknown command `UPD`, with args beginning with: `age`, `17`,
# 繼續傳送一個指令 ,降低age的值,該指令是正確的
> DECR 'age'
QUEUED
# 執行exec,但是之前有錯誤,所以Redis放棄了事務,不再執行
> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
類似MySQL的事務,Redis 事務一次性可以執行多個指令, 而這多個指令通過以下的方式來保證:
在事務執行的過程中,可能遇到這幾種命令執行錯誤:
執行前錯誤是指命令入隊(Queue)時,Redis 就會發現並記錄報錯。
即使執行了 EXEC命令之後,Redis也會拒絕執行指令佇列中的所有指令,返回事務失敗的結果。
這樣一來,所有的指令都不會被執行,保持了原子性。下面是指令入佇列的報錯的範例,跟上面的舉例一致:
# 開啟事務
> MULTI
OK
# 初始一個資料
> SET 'age' 18
OK
# 對該資料進行更新,但Redis不支援該命令,返回報錯資訊
> UPD 'age' 17
(error) ERR unknown command `UPD`, with args beginning with: `age`, `17`,
# 繼續傳送一個指令 ,降低age的值,該指令是正確的
> DECR 'age'
QUEUED
# 執行exec,但是之前有錯誤,所以Redis放棄了事務,不再執行
> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
這個跟上面的情況正好相反,指令入Queue時,命令的型別雖然不匹配,但是並沒有在預編譯的時候檢查出。
只有在EXEC 命令之後,實際執行指令的時候才會報錯。其他正確的指令還是會執行成功,不保證原子性。 參考下面:
# 開啟事務
> MULTI
OK
> set age 18
QUEUED
> set name 'brand'
QUEUED
> INCR age
QUEUED
# 這邊對String型別進行DECR,沒有報錯,但是在執行指令的時候會報錯誤
> DECR name
QUEUED
# 執行,會發現其他三條執行執行成功,只有一條執行失敗,返回報錯資訊
> EXEC
1) OK
2) OK
3) 19
4) ERR value is not an integer or out of range
# 檢視結果
> get name
"brand"
> get age
"19"
可以使用AOF紀錄檔,把未完成的事務操作從AOF紀錄檔中去除,之後使用AOF進行恢復時就不會被再次執行,以此保證整個操作的原子性。
這個需要Redis啟用AOF紀錄檔這個持久化能力。
跟原子性類似,一致性會受到錯誤指令、執行異常、Redis故障等情況的影響,主要有如下幾種情況:
從隔離性這個角度,事務執行的時機可以分成兩種:
如果前後有變化,說明被修改了,這時就放棄事務執行,避免事務的隔離性被破壞。
Redis 操作命令是單執行緒執行的,所以在EXEC 命令執行後,不會亂入其他操作,Redis 會保證把指令佇列中的所有指令都操作完成之後。
在執行後續的命令,所以,這種模式並行操作不會破壞事務的隔離性。它具有天然的隔離能力。
因為Redis的持久化特性,所以有如下三種可能性: