Redis學習筆記(二十一) 事務

文章開始囉嗦兩句,寫到這裏共21篇關於redis的瑣碎知識,沒有過多的寫編程過程當中redis的應用,着重寫的是redis命令、客戶端、服務器以及生產環境搭建用到的主從、哨兵、集羣實現原理,若是你真的能看的進去,相信對你在之後用到redis時會有必定的幫助。java

寫到如今,redis相關的內容暫時告一段落了,之後可能更着重的去介紹c#相關的知識,包括用到IL、.net core底層、微服務等知識。redis

哎呀,寫着寫着忽然又想囉嗦幾句,最近幾年c#在國內式微java如日中天,好多微軟系的小夥伴或者各路大神都不看好c#,網上相關的帖子更是多如牛毛,另一個現象就是從職位到薪資被java、go等語言甩了n條街。數據庫

但我以爲拋開這些外界因素,單從技術或者說是語言上講c#其實很是優秀,雖然近幾年.net  core 有些不三不四、各類借鑑(抄襲)其餘語言的語法糖、各個大版本之間不兼容等問題一堆,可是這並不影響他的優秀,畢竟成長確實要走不少彎路,因此但願有興趣繼續搞搞.net 的童鞋能夠持續關注c#。編程


 

Redis經過MULTI、EXEC、WATCH等命令來實現事務,事務提供了一種將多個命令請求打包,而後一次性、按順序地執行多個命令的機制,而且在事務執行期間,服務器不會中斷事務而改去執行其餘客戶端命令請求,他會將事務中的全部命令執行完畢,而後採起處理其餘客戶端的命令請求。c#

一個事務從開始到結束一般會經歷如下三個階段:事務開始、命令入隊、事務執行。安全

1)事務開始服務器

MULTI命令的執行標誌是事務的開始,MULTI命令能夠將執行該命令的客戶端的從非事務狀態切換至事務狀態,這一切是經過在客戶端狀態的flags屬性中打開REDIS_MULTI標識來完成的。函數

2)命令入隊微服務

若是客戶端發送的命令爲EXEC、DISCARD、WATCH、MULTI四個命令的其中一個,那麼服務器當即執行這個命令,相反,服務器並不會當即執行這個命令,而是將命令放入到一個事務隊列中,然後向客戶端返回QUEUED回覆。學習

每一個Redis客戶端都有本身的事務狀態,這個事務狀態保存在客戶端狀態的mstate屬性裏面:

typedef struct redisClient{
    //事務狀態
    multiState mstate;
} redisClient;

事務狀態包含一個事務隊列,以及一個已入隊命令的計數器:

typedef struct multiState{
    //事務隊列,FIFO順序
    multiCmd *commands;
    ///已入隊列計數
    int count;
} multiState;
typedef struct multiCmd{
    //參數
    robj **argv;
    //參數數量
    int argc;
    //命令指針
    struct redisCommand *cmd;
} multiCmd;

事務隊列以先進先出的方式 保存入隊的命令。

3)執行事務

當一個處於事務狀態的客戶端向服務器發送EXEC命令時,這個EXEC命令將當即被服務器執行。服務器會遍歷這個客戶端的事務隊列,執行隊列中保存的全部命令,最後將執行命令所得的結果所有返回給客戶端。

WATCH命令

watch命令是一個樂觀鎖,它能夠在exec命令執行以前,監視任意數量的數據庫鍵,並在EXEC命令執行時,檢查被監視的鍵是否至少有一個已經被修改過,若是是的話,服務器將拒絕執行事務,並向客戶端返回標識事務執行失敗的空回覆。

每一個Redis數據庫都保存着一個watched_keys字典,這個鍵是某個被watch命令監視的數據數據庫鍵,而字典的值是一個鏈表,鏈表中記錄了全部被監視相應數據庫鍵的客戶端。

typedef struct redisDb{
    //正在被watch命令監視的鍵
    dict *watched_keys;
} redisDb;

監視機制的觸發:全部對數據庫進行修改的命令,在執行以後都會調用touchWatchKey函數對watched_keys字典進行檢查,查看是否在客戶端正在監視剛剛被命令修改過的數據庫鍵,若是有的話,那麼touchWatchKey函數會將監視被修改鍵的客戶端的REDIS_DIRTY_CAS標識打開,標識該客戶端的事務安全性已經被破壞。

 

判斷事務是否安全

當服務器接收到一個客戶端發來的EXEC命令時,服務器會根據客戶端是否打開REDIS_DIRTY_CAS標識來決定是否執行事務:若是客戶端的REDIS_DIRTY_CAS標識已經被打開,那麼說明客戶端所監視的鍵當中,至少有一個鍵已經被修改過了,在這種狀況下,客戶端提交的事務已經再也不安全,因此服務器會拒絕執行客戶端提交的事務;若是客戶端REDIS_DIRTY_CAS標識沒有被打開,那麼說明客戶端監視的全部鍵都沒有被修改過,事務仍然是安全的,服務器將執行客戶端提交的這個事務。

 

事務的ACID性質

原子性:Redis的事務和傳統的關係型數據庫事務最大的區別在於,Redis不支持事務回滾機制,事務隊列中的某個命令在執行期間出現錯誤,整個事務也會繼續執行下去,直到將事務隊列中的全部命令都執行完畢爲止。

一致性:

一、入隊錯誤,若是一個事務在入隊命令的過程當中,出現了命令不存在,或者命令的格式不正確的狀況那麼Redis將拒絕執行這個事務

二、執行錯誤:執行過程當中發生的錯誤都是一些不能再入隊時被服務器發現的錯誤,這些錯誤只會在命令實際執行時被觸發;即便在事務的執行過程當中發生了錯誤,服務器也不會中斷事務的執行,他會繼續執行事務中餘下的其餘命令,而且一致性的命令不會被出錯的命令影響。

三、服務器停機:若是服務器運行在無持久化的內存模式中,那麼重啓以後數據庫將是一片空白的,所以數據老是一致性的;若是服務器運行了RDB模式下,那麼事務中途停機不會致使不一致性,由於服務器能夠根據現有的RDB文件來恢復數據,從而將數據庫還原到一個一致性的狀態。若是服務器運行在APF模式下,那麼事務中途停機不會致使不一致性,由於服務器能夠根據現有的APF文件來恢復數據,從而將數據庫還原至一致的狀態。

隔離性:Redis使用單線程的方式執行事務,而且服務器保證,在執行事務期間不會對事務中斷,所以,redis的事務老是以串行的方式運行,而且事務也老是具備隔離性的。

耐久性:Redis事務的耐久性由Redis所使用的持久化模式決定的,(不論Redis在什麼模式下運行,在一個事務的最後加上SAVE命令總能夠保證事務的耐久性。)

 


天天學一點,總會有收穫。

 

說明:尊重做者知識產權,文中內容參考《Redis設計與實現》,僅在此作學習與你們分享。

 


 

相關文章
相關標籤/搜索