Redis事件redis
Redis的ae(Redis用的事件模型庫) ae.c數據庫
Redis服務器是一個事件驅動程序,服務器須要處理如下兩類事件:緩存
1、文件事件服務器
Redis基於Reactor模式(將消息放到了一個隊列中,經過異步線程池對其進行消費)開發了本身的網絡事件處理器,被稱爲文件事件處理器(file event handler):網絡
文件事件處理器使用I/O多路複用(multiplexing)程序來同時監聽多個套接字,並根據套接字目前執行的任務來爲套接字關聯不一樣的事件處理器。併發
當被監聽的套接字準備好執行鏈接應答(accept)、讀取(read)、寫入(write)、關閉(close)等操做時,與操做相對應的文件事件就會產生,這時文件事件處理器就會調用套接字以前關聯好的事件處理器來處理這些事件。異步
雖然文件事件處理器以單線程方式運行,但經過使用I/O多路複用程序來監聽多個套接字,文件事件處理器既實現了高性能的網絡通訊模型,又能夠很好地與Redis服務器中其餘一樣以單線程方式運行地模塊進行對接,這保持了Redis內部單線程設計地簡單性。函數
底層實現ae_epoll.c、ae_select.c、ae_kqueue.c、ae_evport.c多路複用程序oop
文件事件是對套接字操做的抽象,每當一個套接字準備好執行鏈接應答(accept),寫入,讀取,關閉等操做時,就會產生一個文件事件.由於一個服務器一般會鏈接多個套接字,因此多個文件事件有可能會併發地出現.性能
I/O多路複用程序負責監聽多個套接字,並向文件事件分派器傳送產生了事件地套接字。
儘管多個文件事件可能會併發地出現,但I/O多路複用程序老是會將全部產生事件地套接字都放到一個隊列裏面,而後經過這個隊列,以有序(sequentially)同步(synchronously),每次一個套接字的方式向文件事件分派器傳送套接字。當上一個套接字產生的事件被處理完畢以後(該套接字爲事件所關聯的事件處理器執行完畢),I/O多路複用程序纔會繼續向文件事件分派器傳送下一個套接字。
Redis的I/O多路複用程序的功能都是經過包裝常見的select,epoll,evport和kqueue這些I/O多路複用函數庫來實現的。
I/O多路複用程序能夠監聽多個套接字的ae.h/AE_READABLE事件和ae.h/AE_WRITEABLE事件,這兩類事件和套接字操做之間的對應關係以下:
2、時間事件
serverCron是redis裏主要的定時處理函數,在initServer中經過調用aeCreateTimeEvent,將serverCron作爲callback註冊到全局的eventLoop結構當中。
Redis服務器中的serverCron函數默認每一個100毫秒執行一次,這個函數負責管理服務器的資源,並保持服務器自身的良好運轉。
主要工做:
Redis服務器中有很多功能是須要獲取系統的當前時間,而每次獲取系統的當前時間都須要執行一次系統調用,爲了減小系統的執行次數,服務器狀態中的unixtime屬性和mstime屬性被用做當前時間的緩存
struct redisServer { // ... // 保存了秒級精度的系統當前UNIX時間戳 time_t unixtime; // 保存了毫秒級精度的系統當前UNIX時間戳 long long mstime; // ... };
服務器只會在打印日誌、更新服務器的LRU時鐘、決定是否執行持久化任務、計算服務器線上時間(uptime)這類對時間精確度要求不高的功能上"使用unixtime屬性和mstime屬性"。
爲鍵設置過時時間、添加慢查詢日誌這種須要高精確度時間的功能來講,服務器仍是會再次執行系統調用,從而得到最精確的系統當前時間。
lru記錄的是服務器最後一次被訪問的時間,是用於服務器的計算空轉時長,用屬性lruclock進行存儲。默認狀況下,每10秒更新一次。另外,每一個redis對象也存了一個lru,保存的是該對象最後一次被訪問的時間。當要計算redis對象的空轉時間,則會用服務器的lru減去redis對象的lru,得到的結果即對象的空轉時長。
在redis客戶端,用命令OBJECT IDLETIME <key>,能夠查看該key的空轉時長,返回結果是以秒爲單位。因爲redis每10秒更新一次服務器的最後訪問時間,所以不是很精確。lruclock時鐘的當前值能夠經過INFO server命令的lur_clock 域查看。
這個不是經過掃描所有的鍵,而是採用抽樣的方式肯定的結果。每100毫秒1次,隨機抽取一些鍵,查看最近1秒是否有操做,來肯定最近1秒的操做次數。接着,會將這個值,與上一次的結果,取平均值,做爲本次計算的每秒執行命令數。在存入結構體中,供下次取平均值使用。
redis服務器中,用stat_peak_memory記錄服務器內存峯值。每次執行serverCron函數,會查看當前內存使用量,而且與stat_peak_memory比較,若是超過這個值,就更新這個屬性。
redis服務器,用屬性shutdown_asap記錄當前的結果,0是不用進行操做,1的話是要求服務器儘快關閉。所以,服務器關閉命令shutdown執行,並不會當即關閉服務器,而是將服務器的shutdown_asap屬性置成1,當下一次serverCron讀取時,就會拒絕新的請求,完成當前正在執行的命令後,開始持久化相關的操做,結束持久化後纔會關閉服務器。
主要是會檢查客戶端的兩個內容:
客戶端很長時間沒有和服務器響應,服務器認爲該客戶端超時,則會斷開和該客戶端的鏈接。
當客戶端在上一次執行命令請求後,輸入緩衝區超過必定的長度,程序會釋放輸入緩衝區,並建立一個默認大小的緩衝區,防止緩衝區過度消耗。
主要是檢查鍵是否過時,而且按照配置的策略,刪除過時的鍵。如懶惰刪除、按期刪除等。
redis用屬性aof_rewrite_scheduled記錄是否有延遲的bgrewriteaof命令。當執行bgsave命令期間,若是接收到bgrewriteaof命令,不會當即執行該命令,而是會將屬性aof_rewrite_scheduled置成1。每次執行serverCron函數執行時,發現屬性aof_rewrite_scheduled是1,會檢查當前是否在執行bgsave命令或bgrewriteaof命令,若是沒有在執行這兩個命令,則會執行bgrewriteaof命令。
redis服務器分別用rdb_child_pid和aof_child_pid屬性,記錄rdb和aof的子進程號(即子進程pid),若是沒有在執行相應的持久化,則值是-1。
若是服務器開啓了AOF持久化功能,而且AOF緩衝區裏面還有待寫入的數據,那麼serverCron函數會調用相應的程序,將AOF緩衝區的內容寫入到AOF文件裏面。
服務器會關閉那些輸出緩衝區大小超出限制的客戶端。
redis用屬性cronloops保存serverCron函數執行的次數。當執行一次serverCron,則會將屬性值加1。這個值目前的做用,是在主從複製狀況下,會有一個條件是,每執行n次serverCron,則執行一次指定代碼。