redis事務執行

事務提供了一種將多個命令打包,一次性按順序執行的機制,並且事務在執行期間不會主動中斷(服務段在執行完事務中的所有命令之後纔會執行其他客戶端的其他命令),redis通過MUTIL、DISCARD、EXEC和WATCH四個命令實現事務操作。

事務執行:

開啓事務

multi,這個命令唯一做的是將客戶端的REDIS_MUTIL選項打開,讓客戶端從非事務狀態進入事務狀態

寫入命令

當客戶端進入事務狀態之後,服務端收到客戶端的命令不會立即執行,而是將命令放到事務隊列當中,然後返回QUEUED,表示命令已進入隊。

事務隊列是一個數組,每個數組項都包含三個屬性:①要執行的命令②命令的參數③參數的個數

執行事務

前面所說當客戶端進入事務狀態後,客戶端發送的命令將會放到隊列當中,但是EXEC、DISCARD、MULTI、WATCH這四個命令例外,服務端遇到這四個命令會立即執行

EXEC、MULTI、DISCARD、WATCH命令

EXEC

如果客戶端正處於事務狀態、那麼當exec命令執行時,服務端會根據事務隊列中的命令,FIFO的執行命令,執行事務中命令的結果會以FIFO的順序保存到一個回覆隊列當中,等整個事務完成之後將回復隊列返回給客戶端。

redis的事務是不可能嵌套的,當客戶端處於事務狀態,客戶端繼續發送multi命令,服務端給客戶端發送一個簡單的錯誤,然後繼續等待客戶端的其他命令入隊,multi不會造成整個事務的失敗,也不會修改事務隊列中的數據

DISCARD

discard命令取消一個事務,它清空客戶端整個事務隊列,然後將客戶端從事務狀態變爲非事務狀態,最後返回OK給客戶端,說明事務已經取消。

WATCH

watch命令只能在客戶端進去事務狀態之前執行,在事務狀態下發送watch命令得到一個錯誤的信息,但不會造成事務的失敗,也不會修改事務隊列中的數據。

帶WATCH的事務

WATCH命令用於在事務開始之前監控任意數量的key,當客戶端發送exec命令執行事務時,如果被監控的任意一個鍵的值被其他客戶端修改了,那麼整個事務不再執行,直接返回失敗。

WATCH原理

在每個代表數據庫的結構類型中,都保存了一個watched_keys字典,字典的將時這個數據庫被監視的key,而字典的值是一個鏈表,鏈表中保存了所有監控這個將的客戶端。

WATCH命令的作用就是將客戶端和要監控的鍵在watched_keys中進行關聯。如果程序想檢查某個鍵是否被監控,只要查watched_keys字典是否有這個key即可,如果先知道一個鍵被哪些客戶端監控,那隻要取出鏈表,對鏈表進行遍歷即可。

WATCH的觸發

在任何對數據庫進行修改命令執行之後,都會檢查數據庫的watched_keys字典,看是否有客戶端監控已經被修改的key,如果有的話,程序鍵所有監控這個key的客戶端的REDIS_DIRTY_CAS選項打開,當客戶端發送exec命令觸發事務執行時,服務端會對客戶端的REDIS_DIRTY_CAS選項是否打開,如果 打開,服務器放棄執行這個事務,直接先客戶端返回空回覆,表示事務執行失敗。

redis中的ACID

redis事務保證的事務的一致性(C)和隔離性(I),但並不保證原子性(A)和持久性(D)

原子性

單個 Redis 命令的執行是原子性的,但 Redis 沒有在事務上增加任何維持原子性的機制,所以Redis 事務的執行並不是原子性的。如果一個事務隊列中的所有命令都被成功地執行,那麼稱這個事務執行成功。另一方面,如果 Redis 服務器進程在執行事務的過程中被停止——比如接到 KILL 信號、宿主機器停機,等等,那麼事務執行失敗。當事務失敗時,Redis 也不會進行任何的重試或者回滾動作。

一致性

Redis 的一致性問題可以分爲三部分來討論:入隊錯誤、執行錯誤、Redis 進程被終結。

入隊錯誤

在命令入隊的過程中,如果客戶端向服務器發送了錯誤的命令,比如命令的參數數量不對,等等,那麼服務器將向客戶端返回一個出錯信息,並且將客戶端的事務狀態設爲REDIS_DIRTY_EXEC 。當客戶端執行 EXEC 命令時,Redis 會拒絕執行狀態爲 REDIS_DIRTY_EXEC 的事務,並返回失敗信息。

執行錯誤

如果命令在事務執行的過程中發生錯誤,比如說,對一個不同類型的 key 執行了錯誤的操作,那麼 Redis 只會將錯誤包含在事務的結果中,這不會引起事務中斷或整個失敗,不會影響已執行事務命令的結果,也不會影響後面要執行的事務命令,所以它對事務的一致性也沒有影響。

Redis 進程被終結

如果 Redis 服務器進程在執行事務的過程中被其他進程終結,或者被管理員強制殺死,那麼根據 Redis 所使用的持久化模式,可能有以下情況出現:
①內存模式:如果 Redis 沒有采取任何持久化機制,那麼重啓之後的數據庫總是空白的,所
以數據總是一致的。
②RDB 模式:在執行事務時,Redis 不會中斷事務去執行保存 RDB 的工作,只有在事務執行之後,保存 RDB 的工作纔有可能開始。所以當 RDB 模式下的 Redis 服務器進程在事務中途被殺死時,事務內執行的命令,不管成功了多少,都不會被保存到 RDB 文件裏。恢復數據庫需要使用現有的 RDB 文件,而這個 RDB 文件的數據保存的是最近一次的數據庫快照(snapshot),所以它的數據可能不是最新的,但只要 RDB 文件本身沒有因爲其他問題而出錯,那麼還原後的數據庫就是一致的。
③AOF 模式:因爲保存 AOF 文件的工作在後臺線程進行,所以即使是在事務執行的中途,保存 AOF 文件的工作也可以繼續進行,因此,根據事務語句是否被寫入並保存到 AOF文件,有以下兩種情況發生:1)如果事務語句未寫入到 AOF 文件,或 AOF 未被 SYNC 調用保存到磁盤,那麼當進程被殺死之後,Redis 可以根據最近一次成功保存到磁盤的 AOF 文件來還原數據庫,只
要 AOF 文件本身沒有因爲其他問題而出錯,那麼還原後的數據庫總是一致的,但其中的數據不一定是最新的。2)如果事務的部分語句被寫入到 AOF 文件,並且 AOF 文件被成功保存,那麼不完整的事務執行信息就會遺留在 AOF 文件裏,當重啓 Redis 時,程序會檢測到 AOF 文件並不完整,Redis 會退出,並報告錯誤。需要使用 redis-check-aof 工具將部分成功的事務命令移除之後,才能再次啓動服務器。還原之後的數據總是一致的,而且數據也是最新的(直到事務執行之前爲止)。

隔離性(Isolation)

Redis 是單進程程序,並且它保證在執行事務時,不會對事務進行中斷,事務可以運行直到執行完所有事務隊列中的命令爲止。因此,Redis 的事務是總是帶有隔離性的。

持久性(Durability)

因爲事務不過是用隊列包裹起了一組 Redis 命令,並沒有提供任何額外的持久性功能,所以事務的持久性由 Redis 所使用的持久化模式決定:
①在單純的內存模式下,事務肯定是不持久的。
②在 RDB 模式下,服務器可能在事務執行之後、RDB 文件更新之前的這段時間失敗,所以 RDB 模式下的 Redis 事務也是不持久的。
③在 AOF 的“總是 SYNC ”模式下,事務的每條命令在執行成功之後,都會立即調用 fsync或 fdatasync 將事務數據寫入到 AOF 文件。但是,這種保存是由後臺線程進行的,主線程不會阻塞直到保存成功,所以從命令執行成功到數據保存到硬盤之間,還是有一段非常小的間隔,所以這種模式下的事務也是不持久的。其他 AOF 模式也和“總是 SYNC ”模式類似,所以它們都是不持久的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章