redis啟動流程(二)

foolbread發表於2016-09-27

在上一篇redis啟動流程(一)介紹了redis啟動過程中幾個主要的函式,預留了兩個函式initServer()aeMain()還沒有分析,因為這兩個函式做的事情比較多,要講的篇幅也比較大所以就新開一篇專門來講。

以下是initServer()aeMain()函式的執行流程圖,帶顏色的函式是比較重要的函式。 流程圖

initServer()

1.createSharedObjects()

這個函式主要是建立一些共享的全域性物件,我們平時在跟redis服務互動的時候,如果有遇到錯誤,會收到一些固定的錯誤資訊或者字串比如:-ERR syntax error-ERR no such key。這些字串物件都是在這個函式裡面進行初始化的。

2.adjustOpenFilesLimit()

該函式主要檢查下系統的可允許開啟檔案控制程式碼數,對於redis來說至少要32個檔案控制程式碼,如果檢測到環境不合適,會去修改環境變數,以適合redis的執行。

3.aeCreateEventLoop()

這個函式很重要,redis的事件物件就是在這個函式裡面建立的,包括一些高併發非同步機制物件也是在這裡面初始化的,對於非同步機制物件的選擇可以看到redis是這樣一個順序evport->epoll->kqueue->select,這裡我們只分析epoll的這個樣例其它樣例八九不離十。

4.listenToPort()

從函式名可以很清楚知道這個函式就是為redis啟動監聽TCP埠。

5.anetUnixServer()

這個函式則是啟動uinx socket的監聽。

6.aeCreateTimeEvent()

這個函式主要作為定時任務的註冊,在這裡redis註冊了serverCron()的定時任務,時間間隔是1毫秒,這個是首次,再執行一次之後就會對時間間隔進行重新設定。

7.aeCreateFileEvent()

這個函式主要作為事件任務的註冊,這裡首先對剛才監聽的socket控制程式碼的事件和unix socket控制程式碼的事件加入到事件連結串列當中,而且是隻讀事件。

aeMain()

1.aeProcessEvents()

這個函式讓redis進入了事件迴圈監聽,定時任務事件和讀寫事件都監聽,從程式碼上可以看出如果有讀寫事件則優先執行,然後才是執行定時任務事件。

2.acceptTcpHandler()

當有新的連線接入的時候,該函式就會被呼叫,在比較新的版本里面作者為了提高效率,在該函式中最多可以處理MAX_ACCEPTS_PER_CALL=1000次的連線接入。以前的版本是呼叫一次只處理一個新連線。處理完一個連線後,該函式會把readQueryFromClient這個函式和連線的socket關聯上然後註冊到事件佇列裡面。

3.acceptUnixHandler()

該函式執行的邏輯和acceptTcpHandler()函式差不多,唯一的區別就是從unix socket 來接收新連線,其它邏輯都一樣。

4.serverCron()

該函式是redis的定時任務,也是唯一的定時任務,第一次執行的時間間隔是1毫秒,我看了下程式碼後面按預設的配置是100毫秒執行一次,可是網上有文章說是10毫秒一次,這個就比較有意思了。這個定時任務執行的事情非常多,大致羅列下:

  • 更新了下cache的時間

  • 更新LRU鎖的值

  • 記錄記憶體使用最高值

  • 列印一些資料庫的資訊

  • 列印連線的客戶端資訊

  • 對客戶端一些狀態進行檢測

  • 對資料庫一些狀態進行檢測

  • 維護RDB檔案和AOF檔案

  • 按一定條件刪除一些客戶端

  • 主備資料同步

5.readQueryFromClient()

該函式就是處理從客戶端那邊讀到的請求,根據相應的請求做出相應處理,需要響應的話,填充好傳送緩衝區,然後把sendReplyToClient()加入到事件連結串列中。

6.sendReplyToClient()

該函式把傳送緩衝區的資料傳送到客戶端去,如果沒有任何可傳送的內容,就把自己從事件連結串列中刪除。

總結

上面的函式呼叫流程圖和函式功能解釋,基本把redis進行網路服務前的準備工作和服務流程介紹了個大概,讓我比較震撼的是redis是靠單執行緒在進行網路服務,依靠高效的非同步機制來提供高效能的服務,在它的任務裡面既要處理讀寫事件,又要執行定時任務,任何一環節的效率低下都會影響到整個服務的質量,所以每個環節都要儘量做到高效。對作者很是欽佩,redis原始碼也是一個很好的學習樣例。

相關文章