閱讀284 返回首頁    go 阿裏雲 go 技術社區[雲棲]


MongoDB請求處理流程

Mongodb多存儲引擎支持機製介紹了Mongodb存儲層創建數據庫、創建集合、插入文檔等數據庫操作接口,本文將介紹mongodb處理客戶端請求的模型。

Mongod在啟動時會調用createServer創建一個PortMessageServer對象,其繼承MessageServer和Listener兩個類,並依賴MyMessageHandler來處理請求。

class PortMessageServer: public MessageServer, public Listener {
public:
    void accepted(boost::shared_ptr<Socket> psocket, long long connectionId );
    void setupSockets();
    void run();
private:
   MessageHandler* _handler;
};

PortMessageServer

  1. 調用setupSockets為mongod配置的每個地址創建一個socket,並調用bind綁定地址。
  2. 調用initAndListen監聽所有的地址,調用select等待監聽fd上發生連接事件,調用accept係統調用接受新的連接請求,並為每個新連接創建一個線程,該線程執行handleIncomingMsg方法,不斷處理該連接上的客戶端請求。

handleIncomingMsg

  1. 連接建立時,調用MyMessageHander::connected方法,初始化一個新的Client對象,Client對象包含DB操作的上下文。
  2. 不斷調用recv從連接上讀取請求,當讀取到一個完整請求時,其將請求反序列化為一個Message對象,並調用MyMessageHandler::process方法處理請求,處理完後給客戶端發送應答。
  3. 連接斷開時,調用MyMessageHander::disconnected方法停止該連接對應的線程,釋放Client對象。

MyMessageHandler::process

調用assembleResponse方法,從Message對象裏獲取請求類型(參考Mongdb協議),根據請求類型進行響應的處理。

  1. 如果為請求dbQuery,調用receivedQuery處理
  2. 如果為請求dbInsert,調用receivedInsert處理
  3. 如果為請求dbUpdate,調用receivedUpdate處理
  4. 如果為請求dbDelete,調用receivedDelete處理
  5. ......

上述各種請求最終會調用Database類的接口來處理;比如receivedInsert,會先根據Database回去對應的Collection對象,最後調用insertDocument往集合中插入文檔。請求處理完後,給客戶端發送應答消息。

問題分析

select的使用

mongod調用select時,fdset裏隻會加入監聽fd,而監聽的地址通常很少,故不存在效率問題。

thread per client模型

mongod為每個連接創建一個線程,創建時做了一定優化,將棧空間設置為1M,減少了線程的內存開銷。當線程太多時,線程切換的開銷也會變大,但因為mongdb後端是持久化的存儲,切換開銷相比IO的開銷還是要小得多。

最後更新:2017-04-01 13:37:08

  上一篇:go PostgreSQL 妙用explain Plan Rows快速估算結果集數量
  下一篇:go Greenplum 注意對其數據類型,否則優化器讓你好看