Mongodb多儲存引擎支援機制介紹了Mongodb儲存層建立資料庫、建立集合、插入文件等資料庫操作介面,本文將介紹mongodb處理客戶端請求的模型。
Mongod在啟動時會呼叫createServer建立一個PortMessageServer物件,其繼承MessageServer和Listener兩個類,並依賴MyMessageHandler來處理請求。
1 2 3 4 5 6 7 8 |
class PortMessageServer: public MessageServer, public Listener { public: void accepted(boost::shared_ptr psocket, long long connectionId ); void setupSockets(); void run(); private: MessageHandler* _handler; }; |
PortMessageServer
- 呼叫setupSockets為mongod配置的每個地址建立一個socket,並呼叫bind繫結地址。
- 呼叫initAndListen監聽所有的地址,呼叫select等待監聽fd上發生連線事件,呼叫accept系統呼叫接受新的連線請求,併為每個新連線建立一個執行緒,該執行緒執行handleIncomingMsg方法,不斷處理該連線上的客戶端請求。
handleIncomingMsg
- 連線建立時,呼叫MyMessageHander::connected方法,初始化一個新的Client物件,Client物件包含DB操作的上下文。
- 不斷呼叫recv從連線上讀取請求,當讀取到一個完整請求時,其將請求反序列化為一個Message物件,並呼叫MyMessageHandler::process方法處理請求,處理完後給客戶端傳送應答。
- 連線斷開時,呼叫MyMessageHander::disconnected方法停止該連線對應的執行緒,釋放Client物件。
MyMessageHandler::process
呼叫assembleResponse方法,從Message物件裡獲取請求型別(參考Mongdb協議),根據請求型別進行響應的處理。
- 如果為請求dbQuery,呼叫receivedQuery處理
- 如果為請求dbInsert,呼叫receivedInsert處理
- 如果為請求dbUpdate,呼叫receivedUpdate處理
- 如果為請求dbDelete,呼叫receivedDelete處理
- ……
上述各種請求最終會呼叫Database類的介面來處理。比如receivedInsert,會先根據Database回去對應的Collection物件,最後呼叫insertDocument往集合中插入文件。請求處理完後,給客戶端傳送應答訊息。
問題分析
select的使用
mongod呼叫select時,fdset裡只會加入監聽fd,而監聽的地址通常很少,故不存在效率問題。
thread per client模型
mongod為每個連線建立一個執行緒,建立時做了一定優化,將棧空間設定為1M,減少了執行緒的記憶體開銷。當執行緒太多時,執行緒切換的開銷也會變大,但因為mongdb後端是持久化的儲存,切換開銷相比IO的開銷還是要小得多。