天天看點

《Redis設計與實作》學習筆記-釋出與訂閱、事務、慢查詢日志釋出與訂閱 事務

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指令是一個樂觀鎖,在執行exec之前監視制定的資料庫鍵,在執行exec指令執行時檢查被監視的鍵是否至少有一個已經被修改過,如果是的話,伺服器拒絕執行指令,并向用戶端傳回代表事務執行失敗的空回複。

redis資料庫的redisdb結構儲存了一個watched_keys字典,字典的鍵時某個被watch指令監視的鍵,值是一個連結清單,連結清單中記錄了所有監視相應資料庫鍵的用戶端。

在執行對資料庫修改的指令時,執行之後會調用multi.c/touchwatchkey函數對watched_keys字典進行檢查,檢視是否有用戶端正在監視剛剛被指令修改過的資料庫鍵,如果有的話,touchwatchkey函數将監視被修改鍵的用戶端的redis_dirty_cas辨別打開,表示該用戶端的事務安全性已經被破壞。當伺服器接收到一個用戶端發來的exec指令時,伺服器根據這個用戶端是否打開了redis_dirty_cas辨別來決定是否執行事務。

原子性:對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 的慢查詢日志功能用于記錄執行時間超過給定時長的指令請求, 使用者可以通過這個功能産生的日志來監視和優化查詢速度。

伺服器配置有兩個和慢查詢日志相關的選項:

<code>slowlog-log-slower-than</code> 選項指定執行時間超過多少微秒(<code>1</code> 秒等于 <code>1,000,000</code> 微秒)的指令請求會被記錄到日志上。

舉個例子, 如果這個選項的值為 <code>100</code> , 那麼執行時間超過 <code>100</code> 微秒的指令就會被記錄到慢查詢日志; 如果這個選項的值為 <code>500</code> , 那麼執行時間超過 <code>500</code> 微秒的指令就會被記錄到慢查詢日志; 諸如此類。

<code>slowlog-max-len</code> 選項指定伺服器最多儲存多少條慢查詢日志。

伺服器使用先進先出的方式儲存多條慢查詢日志: 當伺服器儲存的慢查詢日志數量等于 <code>slowlog-max-len</code> 選項的值時, 伺服器在添加一條新的慢查詢日志之前, 會先将最舊的一條慢查詢日志删除。

舉個例子, 如果伺服器 <code>slowlog-max-len</code> 的值為 <code>100</code> , 并且假設伺服器已經儲存了 <code>100</code> 條慢查詢日志, 那麼如果伺服器打算添加一條新日志的話, 它就必須先删除目前儲存的最舊的那條日志, 然後再添加新日志。

原文連結:[http://wely.iteye.com/blog/2361639]