首頁  >  文章  >  資料庫  >  一起聊聊redis文件事件和時間事件

一起聊聊redis文件事件和時間事件

WBOY
WBOY轉載
2022-03-08 17:20:171932瀏覽

這篇文章為大家帶來了關於Redis的相關知識,其中主要介紹了文件事件與時間事件的相關問題,文件事件就是伺服器對套接字操作的抽象,時間事件就是伺服器對這類定時操作的抽象,希望對大家有幫助。

一起聊聊redis文件事件和時間事件

推薦學習:Redis教學

#Redis在6.0以前是單執行緒的,在6.0之後可以透過設定檔開啟多線程,6.0之後的多線程是指在io方面使用多線程來執行以加快I/O的速度。

Redis伺服器是一個事件驅動程序,伺服器需要處理以下兩類事件:

  • 檔案事件(file event)
    Redis伺服器透過套接字與用戶端(或其他Redis伺服器)進行連接,而檔案事件就是伺服器對套接字操作的抽象化。伺服器與客戶端(或其他伺服器)的通訊會產生相應的文件事件,而伺服器則透過監聽並處理這些事件來完成一系列網路通訊操作。檔案事件處理器使用I/O多路復用(multiplexing)程式來同時監聽多個套接字,並根據套接字目前執行的任務來為套接字關聯不同的事件處理器。當被監聽的套接字準備好執行連接應答(accept)、讀取(read)、寫入(write)、關閉(close)等操作時,與操作相對應的文件事件就會產生,這時文件事件處理器就會呼叫套接字之前關聯好的事件處理器來處理這些事件。
  • 時間事件(time event)
    Redis伺服器中的一些操作(例如serverCron函數)需要在給定的時間點執行,而時間事件就是伺服器對這類定時操作的抽象。時間事件分成兩類第一類是定時事件(讓一段程式在指定的時間之後執行一次)另一類是週期性事件(讓一段程式每隔指定時間就執行一次)。

一、檔案事件

1、檔案事件處理器

檔案事件處理器是由四個部分組成的分別是套接字、I/O多工程式、檔案事件分派器、事件處理器。
一起聊聊redis文件事件和時間事件
I/O多工程式負責監聽多個套接字,並向檔案事件分派器傳送那些產生了事件的套接字。儘管多個文件事件可能並發的出現,單I/O多路復用程序總是會將所有產的事件的套接字都放到一個隊列裡面,然後通過這個隊列,以有序的、同步的、每次一個套接字的方式向文件事件分派傳送套接字。當上一個套接字產生的事件被處理完畢之後(此套接字所關聯的事件處理執行完畢),I/O多路復用程式才會繼續傳送下一個套接字,檔案事件分派器接收I/O多工程式傳來的套接字,並根據套接字產生的事件的類型條用對應的事件處理器,伺服器會執行不同人物的套接字關聯不同的事件處理器,這些處理器定義了某個事件發生時伺服器該執行的動作。

2、I/O多路復用

Redis的多路復用程式的所有功能都是透過包裝select、epoll、evport、kqueue這些I/O多路復用函數庫來實現的

3、檔案事件類型

  • AE_READABLE事件
    當套接字變得可讀時(客戶端執行write或close操作)或有新的可應答的套接字出現時套接字將會產生AE_READABLE事件。

  • AE_WAITABLE事件
    當套接字變成可寫時(客戶端執行read操作)將產生AE_WAITABLE事件
    I/O多路復用程式會同時監聽AE_READABLE事件和AE_WAITABLE事件,如果一個套接字同時產生了這兩種事件,那麼事件分派器會優先處理AE_READABLE事件,也即是說伺服器將先讀套接字後寫套接字。

4、檔案事件的處理器

  • 連接應答處理器
    連接應答處理器,這個處理器用來對連接伺服器監聽套接字的客戶端進行應答,當Redis伺服器進行初始化的時候,程式會將這個連接應答處理器和伺服器監聽套接字的AE_READABLE事件關聯起來,當客戶端連接伺服器監聽套接字的時候,套接字就會產生AE_READABLE事件,引發連線應答處理器執行,並執行對應的套接字應答操作。
  • 指令請求處理器
    當一個客戶端透過連線應答處理器成功連接到伺服器之後,服務端會將套接字的AE_READABLE事件和指令請求處理器關聯起來,當客戶端向服務端發送指令請求的時候,套接字就會產生AE_READABLE事件,引發指令請求處理器執行,並執行套接字讀入等操作。在客戶端連接伺服器的整個過程中,伺服器都會一直為客戶端套接字的AE_READABEL事件關聯命令請求處理器。
  • 命令回覆處理器
    當伺服器有命令回覆需要傳送給客戶端的時候,伺服器會將客戶端套接字的AE_WRITABLE事件和命令回復處理器關聯起來,當客戶端準備好接收伺服器回傳的命令回覆時,就會產生AE_WAITABEL事件,引發命令回覆處理器執行,並執行對應的套接字寫入操作。當命令回復發送完畢之後,伺服器就會解除命令回復處理器與客戶端套接字的AE_WAITABLE事件之間的關聯。

5、一次完成的客戶端與伺服器連接事件實例

首先Redis客戶端向伺服器發起連接,那麼監聽套接字將產生AE_READABEL事件,觸發連線應答處理器執行,處理器會對客戶端的連接請求進行應答,然後創建客戶端套接字,以及客戶端狀態,並將客戶端套接字的AE_READABEL事件與命令請求處理器進行關聯,使得客戶端可以向主伺服器發送命令請求。

之後假設客戶端向主伺服器發送一個命令請求,那麼客戶端套接字將產生AE_READABEL事件,引發命令請求處理器執行,處理器讀取客戶端的命令,然後傳給相關聯的程式去執行。

執行指令將產生對應的指令回复,為了將這行指令回復傳送回給客戶端,伺服器會將AE_WAITABLE事件和指令回復處理器進行關聯。當客戶端嘗試讀取命令回覆的時候客戶端會產生AE_WAITABLE事件,觸發命令回復處理器執行,當命令回復處理器將命令回復全服寫入套接字之後,伺服器就會解除客戶端套接字的AE_WAITABLE事件與命令回覆處理器執行的關聯。

二、時間事件

1、時間事件的組成

  • id
    伺服器為時間事件建立全域唯一ID。 ID號碼從小到大順序遞增。
  • when
    毫秒精確度的UNIX時間戳,記錄了時間事件的到達時間。
  • timeProc
    時間事件處理器,一個函數。當時間事件到達時,伺服器就會呼叫對應的處理器來處理事件。

一個時間事件是定時事件還是週期性事件取決於時間事件處理器的回傳值,如果事件處理器回傳ae.h/AE_NOMORE,那麼這個事件為定時事件,該事件在到達一次後就會刪除,之後不再到達。如果事件處理器回傳一個非AE_NOMORE的整數值,那麼這個事件就是週期性事件,當一個時間事件達到後,伺服器會根據事件處理器的回傳值,對事件的when屬性進行更新,讓這個事件在一段時間後再次到達,並以這種方式一直更新並運行下去。

實作

伺服器將所有時間事件都放在一個無序鍊錶中(無序的並不是指id字段,而是when字段所以每次執行都要遍歷完真個鍊錶。),每當時間事件執行器運作時,它就會遍歷整個鍊錶,查找到所有已經到達的事件,並呼叫對應的事件處理器。
這裡要說明的是雖然是無序鍊錶但是由於鍊錶的長度不會很長正常模式下Redis伺服器只使用serverCron一個時間事件所以這個地方機會退化成了指針的作用,而benchmark模式下,伺服器也只使用兩個時間事件,所以全遍歷對效能影響可以忽略。

serverCron函數

持續運行的Redis伺服器需要定期對自身的資源和狀態進行檢查和調整,從而確保伺服器可以長期、穩定地運行,這些定期操作由redis.c/ serverCron函式負責執行,它的主要工作包括:

  • 更新伺服器的各類統計信息,例如時間、記憶體佔用、資料庫佔用等情況。
  • 清理資料庫中過期的鍵值對。
  • 關閉和清理連線失效的客戶端。
  • 嘗試進行AOF或RDB持久化操作。
  • 如果伺服器是主伺服器,那麼對從伺服器進行定期同步
  • 如果處於叢集模式,對叢集進行定期同步和連接測試。

事件的調度與執行

因為伺服器中同時存在檔案事件和時間事件兩種事件類型,所以伺服器必須對這兩個事件進行調度,決定何時應該處理文件事件,何時又應該處理時間事件,以及花多少時間來處理它們等等。
處理過程的偽代碼如下:

def aeProcessEvents():
	# 获取到达时间离当前最近的时间事件
	tem_event = aeSearchNearestTimer()
	
	# 计算上一步获得到的事件 距离到达还有多少秒
	remaind_ms = time_event.when - unix_ts_now()
	
	# 如果事件已经到达, 那么remaind_ms的值可能为负数,设置为0
	remaind_ms = max(remaind_ms, 0)
	
	# 阻塞并等待文件事件产生,最大阻塞时间由timeval结构决定,
	# 如果remaind_ms的值为0,那么aeAPiPoll调用之后马上返回,不阻塞
	aeApiPoll(timeval)
	# 处理所有已经产生的文件事件
	processFileEvents()
	# 处理所有已经到达的时间事件
	proccessTimeEvents()

事件的調度和執行規則:
1)aeApiPoll函數的最大阻塞時間由到達時間最接近當前時間的時間事件決定,這個方法既可以避免伺服器對時間事件進行頻繁的輪詢(忙等待),也可以確保aeApiPoll函數不會阻塞過長時間。

2)因為檔案事件是隨機出現的,如果等待並處理完一次檔案事件之後,仍未有任何時間事件到達,那麼伺服器將再次等待並處理檔案事件。隨著檔案事件的不斷執行,時間會逐漸向時間事件所設定的到達時間逼近,並最終來到到達時間,這時伺服器就可以開始處理到達的時間事件了。

3)對檔案事件和時間事件的處理都是同步、有序、原子地執行的,伺服器不會中途中斷事件處理,也不會對事件進行搶佔,因此,不管是檔案事件的處理器,還是時間事件的處理器,它們都會盡可能地減少程式的阻塞時間,並在有需要時主動讓出執行權,從而降低造成事件飢餓的可能性。比如說,在命令回復處理器將一個命令回复寫人到客戶端套接字時,如果寫人字節數超過了一個預設常數的話,命令回復處理器就會主動用break跳出寫入循環,將剩餘的資料留到下次再寫;另外,時間事件也會將非常耗時的持久化操作放到子執行緒或子程序執行。

4)因為時間事件在檔案事件之後執行,且事件之間不會出現搶佔,所以時間事件的實際處理時間,通常會比時間事件設定的到達時間稍晚。

檔案事件和時間事件之間是合作關係,伺服器會輪流處理這兩種事件,處理事件的過程中也不會進行搶佔。時間事件的實際處理時間通常會比設定的到達時間晚一些。

推薦學習:Redis學習教學

#

以上是一起聊聊redis文件事件和時間事件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除