目錄
- 文件事件處理
- 事件類型
- 客戶端和服務端的通信過程
- 時間事件處理
- 執行器執行
- 周期性事件作用
- 事件的調度與執行
文件事件處理
Redis基于Reactor模式開發了文件事件處理器。文件事件處理器以單線程方式運行,通過IO多路復用程序監聽多個套接字,實現了高性能網絡通信模型,又可以很好的與Redis服務器中同樣以單線程運行的模塊進行對接,保證了設計的簡單性。
文件事件處理器的構成:套接字、I/O多路復用程序、文件事件分派器、事件處理器
每當一個套接字準備好執行連接應答、寫入、讀取、關閉操作時就會產生一個文件事件。一個服務器通常會連接多個套接字,所以多個文件事件有可能并發出現。
I/O多路復用程序負責監聽多個套接字,并向文件事件分派器傳送產生了事件的套接字。
I/O復用程序總是將所有產生事件的套接字放在一個隊列里,通過這個隊列以有序、同步、每次一個套接字的方式向文件事件分派器傳送套接字。
事件類型
- 當套接字可讀(客戶端對套接字執行write操作,或者執行close操作),或者有新的可應答套接字出現(客戶端對服務器的監聽套接字執行connect操作),套接字產生
AE_READABLE
事件 - 當套接字可寫(客戶端對套接字執行read操作),套接字產生
AE_WRITABLE
如果一個套接字同時產生了這兩種事件,那么事件分派器會優先處理讀套接字,后處理寫套接字。
客戶端和服務端的通信過程
時間事件處理
一個時間事件主要由三個屬性組成:
1、id:全局唯一id,新事件的id比老事件的id大
2、when:記錄時間事件的到達時間(ms級別)
3、timeProc:時間時間處理器,表示事件到達,服務器會調用相應的函數
時間事件分為定時事件與周期性事件,區別在于定時事件在到達一次之后就會被刪除,之后不再到達。而周期性事件在到達一次之后會對when屬性更新值,表示在一段時間后再次到達。
Redis的實現原理是將所有的時間事件放在一個無序鏈表中,每當時間事件執行器運作,遍歷鏈表,查找所有已達到時間時間,并調用相應的事件處理器。新的時間時間總是插入鏈表頭部,所以往往是按照ID逆序排列的,這里無序表示不按照when屬性大小排序。
由于時間事件個數較少,所以無序鏈表并不影響時間事件處理器的性能。
執行器執行
執行器具體執行步驟如下:
遍歷服務器中的所有時間事件
for (time_event : list)
{檢查該事件是否已經到達if (time_event <= now_time) {已到達,執行事件處理器,獲取返回值retval = time_event.timeProc()如果是一個定時事件,將事件從服務器中刪除if (retval == AE_NOMORE) delete_time_event(time_event)else否則更新when,讓該事件在指定時間后再次到達update_when(time_event, retval )}
}
周期性事件作用
Redis服務器需要定期對自身的資源和狀態進行檢查和調整,此時就會用到serverCron
函數,該函數就是以周期性事件觸發的。默認是每秒運行10次。
主要作用為:
1、更新服務器各類統計信息,如時間、內存占用、數據庫占用情況
2、清理數據庫中過期鍵值對
3、關閉和清理連接失效的客戶端
4、嘗試進行AOF或RDB持久化操作
5、如果是主服務器還需要對從服務器定期同步
6、如果處于集群模式,還需要對集群定期同步和連接測試
事件的調度與執行
文件事件與時間事件之間是合作關系,服務器會輪流處理兩種事件,并且處理的過程中也不會進行在·搶占,所以時間時間的實際處理時間通常回避設定到達時間晚一些。
事件處理角度下的服務器運行流程:
需要注意的點:
1、為了避免服務器對時間時間進行頻繁輪詢(忙等待),也為了避免阻塞過長時間,每次最大阻塞時間由到達時間最接近當前時間的時間事件決定。
2、文件事件是隨機出現的,所以等處理完一個文件事件之后如果還沒有時間事件到達,則服務器再次等待并處理文件事件,隨著文件事件不斷執行,逐漸接近時間事件設置的到達時間。
3、由于文件處理時同步、有序、原子執行,所以服務器不會中斷事件處理,也不會對事件進行搶占。所以不管是那種事件的處理都需要盡可能減少程序阻塞時間。將耗時的操作放到子線程或者子進程中處理