redis的線程模型

衆所周知,redis是單線程的。但是官方提供的壓測數據,redis每秒可以支持10萬的QPS,這個數據很驚人。但是redis的單線程不是說redis內部就只有一條線程。而是說redis處理請求的線程是單線程。像刷盤這種操作,有另外的線程去做的。
redis能支持如此之高的併發量,其原因有二:
1 .純內存操作
2 .IO多路複用
1 .多路複用
關於IO多路複用,涉及到兩個詞。多路和複用
多路:多路socket連接
複用:多個socket連接使用的是一個線程
redis的多路複用依賴的是事件輪詢機制。
事件輪詢機制有幾個API,select、epoll、kqueue、evport。
在linux系統上,redis採用的是epoll函數。
在macos、FreeBSD系統上採用的是kqueue函數
在solaries系統上,redis採用的是evport函數
如果以上函數,操作系統均不支持,此時採用select函數。select在所有操作系統上都會存在。
以上描述,使得redis做到了跨平臺性
此處,我們只介紹一下select函數,其實本質上和其他幾個API差不多
當客戶端socket發起讀寫請求時,redis服務端程序調用系統內核的select函數,傳入當前socket的文件讀寫描述符以及一個超時時間timeout。當文件描述符處於可讀/可寫的狀態時。select函數會將該事件立即返回。另外,當timeout到達後,select函數也會立即返回。客戶端的整個請求鏈路,只有在調用select函數時阻塞,其他時候不阻塞
select函數僞代碼如下:
read_events,write_events = select (read_fds,write_fds,timeout)
for event in read_events:
handle_read(event.fd)
for event in write_events:
handle_write(event.fd)
handle_others( ) #處理其他事情,如定時任務等
由上可以看出,select返回的是一系列的事件,然後循環處理。此時就達到了複用線程的目的。
拿到事件後,redis的那條單線程就會開始處理這個事件,處理完後。繼續過來輪詢,於是線程進入了一個死循環,我們把這個死循環稱爲時間循環。一個循環爲一個週期
2 .事件分派器
IO多路複用模塊會將已經處於讀寫就緒狀態的事件壓入隊列。然後事件分派器從隊列中挨個取出事件,根據事件的不同類型分配不同的事件處理器(連接應答處理器,命令請求處理器,命令回覆處理器)。事件分派器自己不幹活,交給別人幹活
這個事件分派器的工作模式有一個專有的名詞,叫做Reactor模式。和tomcat的處理連接的過程是非常相似的,tomcat內部也採用了Reactor模式
3 .redis工作流程圖
在這裏插入圖片描述
原圖出處:https://zhuanlan.zhihu.com/p/65013389
4 .完整的redis請求
我們把以上的知識點,串起來說一下總的流程
客戶端socket發起對redis服務端的連接請求,將自己的文件描述符提交給redis的多路複用模塊。多路複用模塊監聽該描述符的狀態,一旦該描述符就緒,就會返回描述符對應的事件。然後多路複用模塊將事件壓入一個隊列中。事件分派器從隊列中取出事件交給事件處理器進行處理,然後將執行結果返回給socket客戶端。
以上,是自己的一點琢磨。應該會有描述欠妥的地方,希望路過的大神能給予批評指正,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章