天天看點

Redis的單線程模型、為什麼redis單線程模型卻可以支援高并發

1、單線程模型

      redis 内部使用檔案事件處理器,這個檔案事件處理器是單線程的,是以才稱redis是單線程的。它采用 IO 多路複用機制同時監聽多個 socket,将産生事件的 socket 壓入記憶體隊列中,事件分派器根據 socket 上的事件類型來選擇對應的事件處理器進行處理。

      檔案事件處理器的結構包含 4 個部分:

  • 多個 socket
  • IO 多路複用程式
  • 檔案事件分派器
  • 事件處理器(連接配接應答處理器、指令請求處理器、指令回複處理器)

2、幾個概念

(1)檔案事件

      a、含義

      是對套接字操作的抽象, 每當一個套接字準備好執行連接配接應答(accept)、寫入、讀取、關閉等操作時, 就會産生一個相應的檔案事件。也即檔案事件是對套接字操作的映射,套接字的不同操作可産生對應的檔案事件。

      b、種類

            AE_READABLE事件:當socket變得可讀時(比如用戶端對Redis執行write操作或者close操作),或者有新的可以應答的socket出現時(用戶端對Redis執行connect操作),socket就會産生一個

"AE_READABLE"

事件

            AE_WRITABLE事件:當socket變得可寫的時候(用戶端對Redis執行read操作),socket就會産生一個

"AE_WRITABLE"

事件

(2)IO 多路複用程式:用來監聽多個socket是否産生了事件,并把産生了事件的socket放入到記憶體隊列中

(3)檔案事件分派器:依次從記憶體隊列中取socket,然後根據socket産生的檔案事件類型,把該事件傳遞給相應的事件處理器來執行和處理

(4)事件處理器:連接配接應答處理器、指令請求處理器、指令回複處理器

3、用戶端與Redis通信的一次流程

(1)在Redis啟動及初始化的時候,Redis預先将連接配接應答處理器跟"AE_READABLE"事件關聯起來。接着如果一個用戶端向Redis發起連接配接,此時server socket 就會産生一個"AE_READABLE"事件,IO 多路複用程式監聽到 server socket 産生的事件後,将該 socket 壓入隊列中。檔案事件分派器從隊列中擷取 socket,交給連接配接應答處理器,由連接配接應答處理器來處理進而與用戶端建立連接配接,并建立用戶端對應的socket,同時将這個socket的"AE_READABLE"事件跟指令請求處理器關聯起來

(2)當用戶端向Redis發起請求的時候(不管是讀請求還是寫請求,都一樣),首先就會在之前建立的用戶端對應的socket上産生一個"AE_READABLE"事件,然後IO多路複用程式會監聽到在之前建立的用戶端對應的socket上産生了一個"AE_READABLE"事件,接着把這個socket放入一個隊列中排隊,然後由檔案事件分派器從隊列中擷取socket交給對應的指令請求處理器來處理(因為之前在Redis啟動并進行初始化的時候就已經預先将"AE_READABLE"事件跟指令請求處理器關聯起來了)。之後指令請求處理器就會從之前建立的用戶端對應的socket中讀取請求相關的資料,然後在自己的記憶體中進行執行和處理

(3)當用戶端請求處理完成後,Redis這邊也準備好了給用戶端的響應資料之後,就會(預先)将socket的"AE_WRITABLE"事件跟指令回複處理器關聯起來,當用戶端這邊準備好讀取響應資料時,就會在之前建立的用戶端對應的socket上産生“AE_WRITABLE”事件,然後IO多路複用程式會監聽到在之前建立的用戶端對應的socket上産生了一個"AE_WRITABLE"事件,接着把這個socket放入一個隊列中排隊,然後由檔案事件分派器從隊列中擷取socket交給對應的指令回複處理器來處理(因為之前在Redis這邊準備好給用戶端的響應資料之後就已經預先将"AE_WRITABLE"事件跟指令回複處理器關聯起來了),之後指令回複處理器就會向之前建立的用戶端對應的socket輸出/寫入準備好的響應資料,最終傳回給用戶端,供用戶端來讀取

(4)當指令回複處理器将準備好的響應資料寫完之後,就會删除之前建立的用戶端對應的socket上的"AE_WRITABLE"事件和指令回複處理器的關聯關系

Redis的單線程模型、為什麼redis單線程模型卻可以支援高并發

4、支援高并發

  • 純記憶體操作。
  • 核心是基于非阻塞的 IO 多路複用機制。
  • C 語言實作,一般來說,C 語言實作的程式“距離”作業系統更近,執行速度相對會更快。
  • 單線程反而避免了多線程的頻繁上下文切換問題,預防了多線程可能産生的競争問題。
  • Redis為了高效的處理用戶端的事件,并沒有将持久化檔案放在主線程裡面進行處理,而是Redis在适當的時機fork子程序來異步的處理這種任務,Redis會fork子程序進行處理持久化檔案操作(将資料寫到RDB 檔案中)。Redis還有一組異步任務處理線程,用于處理不需要主線程同步處理的工作,即處理一些低級别的事件(AOF檔案重寫)。

參考:

(1)https://blog.csdn.net/qq_38601777/article/details/91325622

(2)https://blog.csdn.net/y277an/article/details/98342442?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2

(3)https://blog.csdn.net/xp_xpxp/article/details/100999825