Redis服務器是一個事件驅動程序,服務器需要處理一下兩類事件
- 文件事件:Redis服務器通過套接字與客戶端進行連接,而文件事件就是服務器對套接字操作的抽象
- 時間事件:Redis服務器中的一些操作需要在給定時間點執行,而時間事件就是這類定時操作的抽象
文件事件
Redis基於Reactor模式開發了自己的網絡事件處理器:這個處理器被稱爲文件事件處理器。
- 文件事件處理器使用I/O多路複用程序來同時監聽多個套接字,並根據套接字目前執行的任務來關聯不同事件處理器
- 當被監聽的套接字準備好執行連接應答、讀取、寫入、關閉等操作時,相應文件事件就會產生。這時就會調用相應事件處理器來處理這些事件。
雖然文件事件處理器以單線程方式運行,但通過使用I/O多路複用既實現了高性能的網絡通信模型。又可以與Redis其他同樣以單線程方式運行的模塊進行對接,保持了Redis內部單線程設計的簡單性。
文件事件處理的構成
儘管多個文件事件可能會併發的出現,但I/O多路複用程序總是會將所有產生事件的套接字都放在一個隊列裏面,然後通過這個隊列以有序同步的執行。
事件的類型
- AE_READABLE事件:套接字可讀
- AE_WRITABLE事件:套接字可寫
一個套接字又可讀又可寫時,服務器先讀套接字,後寫套接字
文件事件的處理器
- 連接應答處理器
- 命令請求處理器
- 命令回覆處理器
- 複製處理器
- .......
客戶端和服務端的通信過程
時間事件
- 定時執行:在指定時間之後執行一次
- 週期性執行:每隔指定時間執行一次
目前版本的Redis只使用週期性事件,而沒有使用定時事件
實現
- id:服務器爲時間事件創建的全局唯一ID,從小到大順序遞增
- when:毫秒精度的unix時間戳,記錄時間事件到達時間(週期性時間事件,根據處理器返回值,更新該值)
- timeProc:時間處理器,當時間事件到達時,服務器會調用相應處理器來處理事件
服務器所有時間事件都放在一個無序列表(指沒有按when屬性排序)中,每當時間事件執行器運行時,遍歷整個鏈表,查找到所有已到達的時間事件,並調用相應的事件處理器。
ServerCron函數
-
更新服務器各類統計信息,時間,內存佔用、數據庫佔用等
-
清理數據過期鍵值對
-
關閉清理連接失效的客戶端
-
嘗試進行AOF或RDB持久化操作
-
如果是主服務器,對從服務器進行定期同步
-
如果處於集羣模式,對集羣進行定期同步和連接測試
Redis2.8開始,可以通過修改hz選項調整serverCron每秒執行次數。
事件的調度與執行
- 等待文件事件產生的最大阻塞時間由到達時間最接近當前時間的時間事件決定,既避免服務器對時間事件進行頻繁的輪詢,也可以確保函數不會阻塞過長時間。
- 文件事件和時間事件的處理都是同步、有序、原子的執行的,服務器不會中途中斷事件處理,也不會對事件進行搶佔。因此,不管文件事件處理器、還是時間事件處理器,它們都會儘可能的減少程序阻塞時間,並在有需要的時,主動讓出執行權,降低造成事件飢餓的可能性。比如:命令回覆處理,如果寫入字節數超過預設常量,命令回覆處理器會主動break跳出寫入循環,將餘下的數據留到下次在寫。時間事件也會將非常耗時的持久化操作放到子線程或者子進程執行(Bgsave命令)
- 通常時間事件實際處理時間比設定時間稍晚執行