Skip to main content

Ceph Network Architecture 研究(二)

延續上篇文章 (Ceph Network Architecture 研究(一))[https://www.hwchiu.com/ceph-network-i.html#more],本文將繼續探討 Async 這種網路類型底層真的架構與概念,所以本文章也不會有太硬的程式碼解讀,反而會比較偏向概念性的分析。

從上一篇文章中我們可知道,底層網路實現提供了包含 Messenger, Connection 等介面供上層應用層去使用。 接下來

AsyncConnection.cc
AsyncConnection.h
AsyncMessenger.cc
AsyncMessenger.h
Event.cc
Event.h
EventEpoll.cc
EventEpoll.h
EventKqueue.h
EventSelect.cc
EventSelect.h
PosixStack.cc
PosixStack.h
Stack.cc
Stack.h
net_handler.cc
net_handler.h

從上述的檔案來看,我們大致上可以猜到 AsyncMessenger 以及 AsyncConnection的涵義,而 Event 一系列的檔案應該就是最底層的 I/O 的處理。

Event​

這邊先從最底層開始看起,首先是 Event。 整個 Event 代表了底層 I/O 的處理,目前支援三種實作方式,分別是

  • Epool
  • Kqueue
  • Select

在這三種實作上面,又提供了三種 EventType 供上層使用,分別是

  • File_Event
  • Time_Event
  • External_Event

File_Event​

File event 是最常見也是最普遍使用的,針對每一個 file descriptor 進行設定,該 file descriptor 關注的是 read event 還是 write event 以及當該 event 發生時,應該要進行什麼樣的處理。

Time_Event​

Time event 本身跟 file descriptor 無關,單純的是依照時間來驅動的事件,對於每一種 Time Event 則會有兩個設定,一個是多久(ms)之後要執行該事件,以及該執行的事件是什麼,這邊都是使用 function pointer 來指向該事件。

External_Event​

External event 實際上跟 Time event 是相同的,可以視為時間是 0ms 的 Time event,就是馬上執行該事件。

整體架構如下圖,系統中會有一個 Event Center,底層支援各種 I/O 的實作,此外,本身會提供介面供上層使用,可以接受上述三種事件的註冊。 待一切都準備就緒後,就會開始透過底層 I/O 的事件去處理這三種事件,譬 如有封包到來的時候呼叫對應的函式處理,亦或是時間到的時候執行對應的 Time event。

Worker and Network Stack​

上述看完了 EventCenter的概念後,我們知道每個 EventCenter專門用來負責底層的 I/O 處理,那這邊為了提高整體的效率,採用了 ThreadPool的概念,事先根據系統上的能力創造一批固定數量的 Thread,這邊統稱為 Worker,這些 Worker 的數量可以動態的增加,減少。 然後每一個 Worker 都配上一個 EventCenter,盡可能的讓所有的 Worker去平均分擔所有的 Network I/O 負擔。 在這群 Worker 之上存在一層 Network Stack,此 Stack 會掌管所有的 Workers,包含其創建/增加/刪除等行為。

綜合以上概念,目前認知的架構圖如下。

AsyncConnection​

接下來看到 AsyncConnection ,此物件代表者任意兩個 ceph node之間的連線,可以是 osd<->osd,也可以是 mon<->mon亦或是 osd<->mon。 此物件本身除了代表連線外,跟網路傳輸相關的功能,如發送封包,接收封包等事情都會在這邊提供一個介面供更上層的應用(OSD)來使用。 不過這邊只是中介層而已,真正收送發包的還是上述提到 EventCenter 在處理。

由於系統上可以同時存在非常多條 connections,為了讓這些 connections能夠同時運作且不會互相影響,這邊配給每一個connection一個worker來處理。 由於 connection的數量基本上都會比worker還要多,因此在配對上就是盡量平均分擔下去,盡量讓每一個worker負擔相同數量的connection。

所以看到這邊已經可以大概理解,系統上每一條 connection 都配上一個 thread 來處理,而每一個 thread 實際上可能會負責不少條 connection,這邊採用數量的方式來分散這些 connection,若能夠根據實際負擔作為分散的權重也許可以讓每個 thread 的負擔更為平均。

因此看到這邊,目前的架構圖如下,圖中的 Async Connections只是一個抽象的概念,描述眾多的 Async Connection而已。

AsyncMessenger​

最後出場的就是 AsyncMessenger,其概念與之前講述過的 Messenger一樣,管理所有的 AsyncConnections,同時是最直接供上層應用程式的物件。 每個 AsyncMessenger都可以被註冊 Dispatcher,接者當底下的 connection 有收到來自遠方的封包(Messege)時,就呼叫對應的 Dispatcher 來處理。

所以整體架構如下圖。

Summary​

到這邊大致上已經對 Async 系列有一個基本的認識了,不過這基本上只局限於 async+poxis 類型而已,對於 RDMA 以及 DPDK 則因為這兩種運作方式的不同,其真正運作的方式又是截然不同的,這部分可以從原始碼中看到 RDMA/DPDK 都有額外的資料夾,且資料夾內又有為數不少的檔案可以大略猜測出來。

接下來的文章會比較偏技術性質,會直接看進這些程式碼內,透過這些程式碼能夠更瞭解整體的架構以及實作細節,順便學習增廣見聞。