文章開始啰嗦兩句,寫到這裡共21篇關於redis的瑣碎知識,沒有過多的寫編程過程中redis的應用,著重寫的是redis命令、客戶端、伺服器以及生產環境搭建用到的主從、哨兵、集群實現原理,如果你真的能看的進去,相信對你在以後用到redis時會有一定的幫助。 寫到現在,redis相關的內容暫時告一段落 ...
文章開始啰嗦兩句,寫到這裡共21篇關於redis的瑣碎知識,沒有過多的寫編程過程中redis的應用,著重寫的是redis命令、客戶端、伺服器以及生產環境搭建用到的主從、哨兵、集群實現原理,如果你真的能看的進去,相信對你在以後用到redis時會有一定的幫助。
寫到現在,redis相關的內容暫時告一段落了,以後可能更著重的去介紹c#相關的知識,包括用到IL、.net core底層、微服務等知識。
哎呀,寫著寫著突然又想啰嗦幾句,最近幾年c#在國內式微java如日中天,好多微軟系的小伙伴或者各路大神都不看好c#,網上相關的帖子更是多如牛毛,另外一個現象就是從職位到薪資被java、go等語言甩了n條街。
但我覺得拋開這些外界因素,單從技術或者說是語言上講c#其實非常優秀,雖然近幾年.net core 有些不倫不類、各種借鑒(抄襲)其他語言的語法糖、各個大版本之間不相容等問題一堆,但是這並不影響他的優秀,畢竟成長確實要走很多彎路,所以希望有興趣繼續搞搞.net 的童鞋可以持續關註c#。
Redis通過MULTI、EXEC、WATCH等命令來實現事務,事務提供了一種將多個命令請求打包,然後一次性、按順序地執行多個命令的機制,並且在事務執行期間,伺服器不會中斷事務而改去執行其他客戶端命令請求,他會將事務中的所有命令執行完畢,然後採取處理其他客戶端的命令請求。
一個事務從開始到結束通常會經歷以下三個階段:事務開始、命令入隊、事務執行。
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不支持事務回滾機制,事務隊列中的某個命令在執行期間出現錯誤,整個事務也會繼續執行下去,直到將事務隊列中的所有命令都執行完畢為止。
一致性:
1、入隊錯誤,如果一個事務在入隊命令的過程中,出現了命令不存在,或者命令的格式不正確的情況那麼Redis將拒絕執行這個事務
2、執行錯誤:執行過程中發生的錯誤都是一些不能再入隊時被伺服器發現的錯誤,這些錯誤只會在命令實際執行時被觸發;即使在事務的執行過程中發生了錯誤,伺服器也不會中斷事務的執行,他會繼續執行事務中餘下的其他命令,並且一致性的命令不會被出錯的命令影響。
3、伺服器停機:如果伺服器運行在無持久化的記憶體模式中,那麼重啟之後資料庫將是一片空白的,因此數據總是一致性的;如果伺服器運行了RDB模式下,那麼事務中途停機不會導致不一致性,因為伺服器可以根據現有的RDB文件來恢複數據,從而將資料庫還原到一個一致性的狀態。如果伺服器運行在APF模式下,那麼事務中途停機不會導致不一致性,因為伺服器可以根據現有的APF文件來恢複數據,從而將資料庫還原至一致的狀態。
隔離性:Redis使用單線程的方式執行事務,並且伺服器保證,在執行事務期間不會對事務中斷,因此,redis的事務總是以串列的方式運行,並且事務也總是具有隔離性的。
耐久性:Redis事務的耐久性由Redis所使用的持久化模式決定的,(不論Redis在什麼模式下運行,在一個事務的最後加上SAVE命令總可以保證事務的耐久性。)
每天學一點,總會有收穫。
說明:尊重作者知識產權,文中內容參考《Redis設計與實現》,僅在此做學習與大家分享。