標籤:redis 高效能分布式緩衝 發布訂閱 事務 nosql
發布與訂閱Redis通過發布訂閱提供一對多甚至是多對多的節點訊息通訊,發布訂閱由PUBLISH、SUBSCRIBE、PSUBSCRIBE、PUBSUB等命令組成。
- SUBSCRIBE命令:訂閱某頻道,在redisServer結構中通過pubsub_channels字典屬性儲存當前伺服器所有頻道的訂閱關係,字典鍵時頻道名稱,字典值是一個鏈表,記錄了所有訂閱這個頻道的用戶端。
- UNSUBSCRIBE命令:退訂頻道,調用該命令之後,會把訂閱關係從pubsub_channels中刪掉,如果鍵對應的鏈表為空白了,則把鍵從字典中刪除。
- PSUBSCRIBE命令:訂閱模式,伺服器將所有的模式訂閱關係儲存在redisServer結構的pubsub_patterns屬性中,該屬性是一個鏈表,每個鏈表節點包含一個pubsubPattern結構,該結構記錄了被訂閱的模式和訂閱該模式的用戶端。
- PUNSUBSCRIBE命令:退訂模式,調用該命令之後,伺服器會遍曆pubsub_patterns鏈表,把用戶端和模式都匹配的那個節點刪除。
- PUBLISH命令:發送訂閱訊息,伺服器接收到該命令之後,先遍曆pubsub_channels找出頻道訂閱者,把訊息發送給所有頻道訂閱者,然後遍曆pubsub_patterns找出與channel匹配的模式,並將訊息發送給訂閱了這些模式的用戶端。
- PUBSUB命令,查看訂閱資訊包含下面三個子命令:
- PUBSUB CHANNLES [pattern]:返回當前伺服器被訂閱的頻道,如指定pattern,則返回與模式比對的頻道
- PUBSUB NUMSUB [channel-1 ... channel-n]:返回指定頻道的訂閱者數量
- PUBSUB NUMPAT:返回伺服器當前被訂閱模式的數量
事務Redis通過MULTI、EXEC、WATCH等命令來實現事務功能,實現將多個命令打包然後一次性順序執行。事務以MULTI命令開始,EXEC命令結束。在執行MULTI命令之後執行的命令不立刻執行,而是向用戶端返回一個QUEUED,等執行EXEC命令之後再執行。
事務的實現事務開始
執行MULTI命令之後,伺服器把用戶端從非事務態切換到事務態,通過設定redisClient的flags標識,把REDIS_MULTI標識開啟。
命令入隊
用戶端處於非事務態時,用戶端發送的命令立刻執行,當處於事務態時:
如果用戶端發送的命令為EXEC、DISCARD、WATCH、MULTI其中的一個時,伺服器立即執行。
如果用戶端發送的命令是其它的命令,伺服器不會立刻執行這個命令,而是把命令放到事務隊列中,然後向用戶端返回QUEUED。
redisClient中有個multiState結構的屬性mstate記錄用戶端的事務狀態,在multiState結構中有個commands列表屬性,它記錄了調用MULTI之後該用戶端入隊的命令,count屬性記錄入隊命令的數量。multiCmd結構記錄命令實現函數指標,命令的參數,已經參數的數量。事務隊列以FIFO的方式儲存入隊命令,先入隊的命令先執行。
執行事務
執行EXEC命令提交事務,伺服器接收該命令之後:
- 遍曆client.mstate.commands,擷取已入隊的命令並且挨個執行,把命令的返回值添加到回複隊列尾部。
- 清空用戶端的事務狀態,包括清零入隊命令計數器,釋放事務隊列。
- 把執行結果返回給用戶端。
WATCH命令實現WATCH命令是一個樂觀鎖,在執行EXEC之前監視制定的資料庫鍵,在執行EXEC命令執行時檢查被監視的鍵是否至少有一個已經被修改過,如果是的話,伺服器拒絕執行命令,並向用戶端返回代表事務執行失敗的空回複。
Redis資料庫的redisDb結構儲存了一個watched_keys字典,字典的鍵時某個被WATCH命令監視的鍵,值是一個鏈表,鏈表中記錄了所有監視相應資料庫鍵的用戶端。
在執行對資料庫修改的命令時,執行之後會調用multi.c/touchWatchKey函數對watched_keys字典進行檢查,查看是否有用戶端正在監視剛剛被命令修改過的資料庫鍵,如果有的話,touchWatchKey函數將監視被修改鍵的用戶端的REDIS_DIRTY_CAS標識開啟,表示該用戶端的事務安全性已經被破壞。當伺服器接收到一個用戶端發來的EXEC命令時,伺服器根據這個用戶端是否開啟了REDIS_DIRTY_CAS標識來決定是否執行事務。
事務的ACID原子性:對Redis事務來說,事務中的多個命令被當做一個整體,事務隊列中的命令要麼全部被執行,要麼都不執行,Redis事務時具有原子性的,但是Redis事務部支援復原,即使隊列中某個命令執行出現了錯誤也不影響後面的命令,整個事務會繼續執行。
一致性:在命令入隊錯誤、執行錯誤、伺服器停機時都不會影響資料庫的一致性。ps:當入隊錯誤時對2.6.5之前的版本事務會繼續執行,2.6.5之後事務會被拒絕執行
隔離性:Redis事務執行期間不會被其它命令中斷,以串列的方式運行,Redis事務是具有隔離性的
持久性:
- 當伺服器運行在無持久化的記憶體模式下時,事務不具有持久性:一旦伺服器停機,所有資料都會丟失
- 當伺服器運行在RDB持久化模式下時,當伺服器停機時會有一段時間的資料會丟失,事務不具有持久性
- 當伺服器運行在AOF持久化模式下,並且appendsync選項值為always時,資料會被及時儲存到硬碟中,此時事務具有持久性(前提是沒有開啟no-appendfsync-on-rewrite選項,開啟該選項之後,為了儘可能的減少IO操作,當伺服器執行BGSAVE或BGREWRITEAOF時,會停止AOF檔案同步,所以此時事務也不具有持久性)
- 當伺服器運行在AOF持久化模式下,並且appendsync選項值為everysec時,可能會丟失1秒的資料,此時事務不具有持久性
- 當伺服器運行在AOF持久化模式下,並且appendsync選項值為no,伺服器停機時資料會丟失,此時事務不具有持久性
《Redis設計與實現》學習筆記-發布訂閱與事務