mongodb核心原始碼實現、效能調優、最佳運維實踐系列-網路傳輸層模組原始碼實現二
mongodb 網路傳輸層模組原始碼實現二
關於作者
前滴滴出行技術專家,現任OPPO 文件資料庫 mongodb 負責人,負責 oppo 千萬級峰值 TPS/ 十萬億級資料量文件資料庫 mongodb 核心研發及運維工作,一直專注於分散式快取、高效能服務端、資料庫、中介軟體等相關研發。後續持續分享《 MongoDB 核心原始碼設計、效能最佳化、最佳運維實踐》, Github 賬號地址 :
1. 說明
在之前的 <<Mongodb 網路傳輸處理原始碼實現及效能調優 - 體驗核心效能極致設計 >> 一文中分析瞭如何閱讀百萬級大工程原始碼、Asio 網路庫實現、 transport 傳輸層網路模組中執行緒模型實現,但是由於篇幅原因,傳輸層網路模組中的以下模組實現原理沒有分析,本文降將繼續分析遺留的以下子模組:
l transport_layer 套接字處理及傳輸層管理子模組
l session 會話子模組
l Ticket 資料收發子模組
l service_entry_point 服務入口點子模組
l service_state_machine 狀態機子模組 ( 該《模組在網路傳輸層模組原始碼實現三》中分析 )
l service_executor 執行緒模型子模組 ( 該《模組在網路傳輸層模組原始碼實現四》中分析 )
2. transport_layer 套接字處理及傳輸層管理子模組
transport_layer 套接字處理及傳輸層管理子模組功能包括套接字相關初始化處理、結合 asio 庫實現非同步 accept 處理、不同執行緒模型管理及初始化等,該模組的原始碼實現主要由以下幾個檔案實現:
上圖是套接字處理及傳輸層管理子模組原始碼實現的相關檔案,其中mock 和 test 檔案主要用於模擬測試等,所以真正核心的程式碼實現只有下表的幾個檔案,對應原始碼檔案功能說明如下表所示:
檔名 |
功能 |
transport_layer.h transport_layer.cpp |
該子模組基類,透過該類把本模組和 Ticket 資料分發模組銜接起來,具體類實現在 transport_layer_legacy.cpp 和 transport_layer_asio.cpp 中 |
transport_layer_legacy.h transport_layer_legacy.cpp |
早期的傳輸模組實現方式,現在已淘汰,不在分析 |
transport_layer_asio.h transport_layer_asio.cpp |
傳輸模組 Asio 網路 IO 處理實現,同時銜接 ServiceEntryPoint 服務入口模組和 Ticket 資料分發模組 |
2.1 核心程式碼實現
該子模組核心程式碼主要由 TransportLayerManager 類和TransportLayerASIO 類相關介面實現。
2.1.1 TransportLayerManager 類核心程式碼實現
TransportLayerManager 類主要成員及介面如下:
1. //網路會話連結,訊息處理管理相關的類,在createWithConfig構造該類存入_tls 2. class TransportLayerManager final : public TransportLayer { 3. //以下四個介面真正實現在TransportLayerASIO類中具體實現 4. Ticket sourceMessage(...) override; 5. Ticket sinkMessage(...) override; 6. Status wait(Ticket&& ticket) override; 7. void asyncWait(...) override; 8. //配置初始化實現 9. std::unique_ptr<TransportLayer> createWithConfig(...); 10. 11. //createWithConfig中賦值,對應TransportLayerASIO, 12. //實際上容器中就一個成員,就是TransportLayerASIO 13. std::vector<std::unique_ptr<TransportLayer>> _tls; 14. };
TransportLayerManager 類包含一個 _tls 成員,該類最核心的 createWithConfig 介面程式碼實現如下:
1. //根據配置構造相應類資訊 _initAndListen中呼叫 2. std::unique_ptr<TransportLayer> TransportLayerManager::createWithConfig(...) { 3. std::unique_ptr<TransportLayer> transportLayer; 4. //服務型別,也就是本例項是mongos還是mongod 5. //mongos對應ServiceEntryPointMongod,mongod對應ServiceEntryPointMongos 6. auto sep = ctx->getServiceEntryPoint(); 7. //net.transportLayer配置模式,預設asio, legacy模式已淘汰 8. if (config->transportLayer == "asio") { 9. //同步方式還是非同步方式,預設synchronous 10. if (config->serviceExecutor == "adaptive") { 11. //動態執行緒池模型,也就是非同步模式 12. opts.transportMode = transport::Mode::kAsynchronous; 13. } else if (config->serviceExecutor == "synchronous") { 14. //一個連結一個執行緒模型,也就是同步模式 15. opts.transportMode = transport::Mode::kSynchronous; 16. } 17. //如果配置是asio,構造TransportLayerASIO類 18. auto transportLayerASIO = stdx::make_unique<transport::TransportLayerASIO>(opts, sep); 19. if (config->serviceExecutor == "adaptive") { //非同步方式 20. //構造動態執行緒模型對應的執行器ServiceExecutorAdaptive 21. ctx->setServiceExecutor(stdx::make_unique<ServiceExecutorAdaptive>( 22. ctx, transportLayerASIO->getIOContext())); 23. } else if (config->serviceExecutor == "synchronous") { //同步方式 24. //構造一個連結一個執行緒模型對應的執行器ServiceExecutorSynchronous 25. ctx->setServiceExecutor(stdx::make_unique<ServiceExecutorSynchronous>(ctx)); 26. } 27. //transportLayerASIO轉換為transportLayer類 28. transportLayer = std::move(transportLayerASIO); 29. } 30. //transportLayer轉存到對應retVector陣列中並返回 31. std::vector<std::unique_ptr<TransportLayer>> retVector; 32. retVector.emplace_back(std::move(transportLayer)); 33. return stdx::make_unique<TransportLayerManager>(std::move(retVector)); 34. }
createWithConfig 函式根據配置檔案來確定對應的TransportLayer ,如果 net.transportLayer 配置為 ” asio ” ,則選用TransportLayerASIO 類來進行底層的網路 IO 處理,如果配置為 ” legacy ” ,則選用TransportLayerLegacy 。 ” legacy ” 模式當前已淘汰,本文只分析 ” asio ” 模式實現。
“ asio ” 模式包含兩種執行緒模型: adaptive ( 動態執行緒模型 ) 和 synchronous ( 同步執行緒模型 ) 。 adaptive 模式執行緒設計採用動態執行緒方式,執行緒數和 mongodb 壓力直接相關,如果 mongodb 壓力大,則執行緒數增加;如果 mongodb 壓力變小,則執行緒數自動減少。同步執行緒模式也就是一個連結一個執行緒模型,執行緒數的多少和連結數的多少成正比,連結數越多則執行緒數也越大。
Mongodb 核心實現中透過 opts.transportMode 來標記asio 的執行緒模型,這兩種模型對應標記如下:
執行緒模型 |
核心 transportMode 標記 |
說明 |
對應執行緒模型由那個類實現 |
adaptive |
KAsynchronous( 非同步 ) |
adaptive 模型也可以稱為非同步模型 |
ServiceExecutorAdaptive |
synchronous |
KSynchronous( 同步 ) |
synchronous 模型也可以稱為同步模型 |
ServiceExecutorSynchronous |
說明:adaptive 執行緒模型被標記為 KAsynchronous , synchronous 被標記為 KSynchronous 是有原因的, adaptive 動態執行緒模型網路 IO 處理藉助 epoll 非同步實現,而 synchronous 一個連結一個執行緒模型網路IO 處理是同步讀寫操作。 Mongodb 網路執行緒模型具體實現及各種優缺點可以參考: Mongodb 網路傳輸處理原始碼實現及效能調優 - 體驗核心效能極致設計
2.1.2 TransportLayerASIO 類核心程式碼實現
TransportLayerASIO 類核心成員及介面如下:
1. class TransportLayerASIO final : public TransportLayer { 2. //以下四個介面主要和套接字資料讀寫相關 3. Ticket sourceMessage(...); 4. Ticket sinkMessage(...); 5. Status wait(Ticket&& ticket); 6. void asyncWait(Ticket&& ticket, TicketCallback callback); 7. void end(const SessionHandle& session); 8. //新連結處理 9. void _acceptConnection(GenericAcceptor& acceptor); 10. 11. //adaptive執行緒模型網路IO上下文處理 12. std::shared_ptr<asio::io_context> _workerIOContext; 13. //accept接收客戶端連結對應的IO上下文 14. std::unique_ptr<asio::io_context> _acceptorIOContext; 15. //bindIp配置中的ip地址列表,用於bind監聽,accept客戶端請求 16. std::vector<std::pair<SockAddr, GenericAcceptor>> _acceptors; 17. //listener執行緒負責接收客戶端新連結 18. stdx::thread _listenerThread; 19. //服務型別,也就是本例項是mongos還是mongod 20. //mongos對應ServiceEntryPointMongod,mongod對應ServiceEntryPointMongos 21. ServiceEntryPoint* const _sep = nullptr; 22. //當前執行狀態 23. AtomicWord<bool> _running{false}; 24. //listener處理相關的配置資訊 25. Options _listenerOptions; 26. } 從上面的類結構可以看出,該類主要透過listenerThread執行緒完成bind繫結及listen監聽操作,同時部分介面實現新連線上的資料讀寫。 套接字初始化程式碼實現如下: 1. Status TransportLayerASIO::setup() { 2. std::vector<std::string> listenAddrs; 3. //如果沒有配置bindIp,則預設監聽"127.0.0.1:27017" 4. if (_listenerOptions.ipList.empty()) { 5. listenAddrs = {"127.0.0.1"}; 6. } else { 7. //配置檔案中的bindIp:1.1.1.1,2.2.2.2,以逗號分隔符獲取ip列表存入ipList 8. boost::split(listenAddrs, _listenerOptions.ipList, boost::is_any_of(","), boost::token_compress_on); 9. } 10. //遍歷ip地址列表 11. for (auto& ip : listenAddrs) { 12. //根據IP和埠構造對應SockAddr結構 13. const auto addrs = SockAddr::createAll( 14. ip, _listenerOptions.port, _listenerOptions.enableIPv6 ? AF_UNSPEC : AF_INET); 15. ...... 16. //根據addr構造endpoint 17. asio::generic::stream_protocol::endpoint endpoint(addr.raw(), addr.addressSize); 18. //_acceptorIOContext和_acceptors關聯 19. GenericAcceptor acceptor(*_acceptorIOContext); 20. //epoll註冊,也就是fd和epoll關聯 21. //basic_socket_acceptor::open 22. acceptor.open(endpoint.protocol()); 23. //SO_REUSEADDR配置 basic_socket_acceptor::set_option 24. acceptor.set_option(GenericAcceptor::reuse_address(true)); 25. //非阻塞設定 basic_socket_acceptor::non_blocking 26. acceptor.non_blocking(true, ec); 27. //bind繫結 28. acceptor.bind(endpoint, ec); 29. if (ec) { 30. return errorCodeToStatus(ec); 31. } 32. } 33. }
從上面的分析可以看出,程式碼實現首先解析出配置檔案中bindIP 中的 ip:port 列表,然後遍歷列表繫結所有服務端需要監聽的 ip:port ,每個 ip:port 對應一個 GenericAcceptor ,所有 acceptor 和全域性accept IO 上下文 _acceptorIOContext 關聯,同時 bind() 繫結所有 ip:port 。
Bind() 繫結所有配置檔案中的 Ip:port 後,然後透過 TransportLayerASIO::start() 完成後續處理,該介面程式碼實現如下:
1. //_initAndListen中呼叫執行 2. Status TransportLayerASIO::start() { //listen執行緒處理 3. ...... 4. //這裡專門起一個執行緒做listen相關的accept事件處理 5. _listenerThread = stdx::thread([this] { 6. //修改執行緒名 7. setThreadName("listener"); 8. //該函式中迴圈處理accept事件 9. while (_running.load()) { 10. asio::io_context::work work(*_acceptorIOContext); 11. try { 12. //accept事件排程處理 13. _acceptorIOContext->run(); 14. } catch (...) { //異常處理 15. severe() << "Uncaught exception in the listener: " << exceptionToStatus(); 16. fassertFailed(40491); 17. } 18. } 19. }); 20. 遍歷_acceptors,進行listen監聽處理 21. for (auto& acceptor : _acceptors) { 22. acceptor.second.listen(serverGlobalParams.listenBacklog); 23. //非同步accept回撥註冊在該函式中 24. _acceptConnection(acceptor.second); 25. } 26. }
從上面的 TransportLayerASIO::start() 介面可以看出,mongodb 特地建立了一個 listener 執行緒用於客戶端accept 事件處理,然後藉助 ASIO 網路庫的 _acceptorIOContext->run() 介面來排程,當有新連結到來的時候,就會執行相應的accept 回撥處理, accept 回撥註冊到 io_context 的流程由 acceptConnection () 完成,該介面核心原始碼實現如下:
1. //accept新連線到來的回撥註冊 2. void TransportLayerASIO::_acceptConnection(GenericAcceptor& acceptor) { 3. //新連結到來時候的回撥函式,服務端接收到新連線都會執行該回撥 4. //注意這裡面是遞迴執行,保證所有accept事件都會一次處理完畢 5. auto acceptCb = [this, &acceptor](const std::error_code& ec, GenericSocket peerSocket) mutable { 6. if (!_running.load()) 7. return; 8. 9. ...... 10. //每個新的連結都會new一個新的ASIOSession 11. std::shared_ptr<ASIOSession> session(new ASIOSession(this, std::move(peerSocket))); 12. //新的連結處理ServiceEntryPointImpl::startSession, 13. //和ServiceEntryPointImpl服務入口點模組關聯起來 14. _sep->startSession(std::move(session)); 15. //遞迴,直到處理完所有的網路accept事件 16. _acceptConnection(acceptor); 17. }; 18. //accept新連線到來後服務端的回撥處理在這裡註冊 19. acceptor.async_accept(*_workerIOContext, std::move(acceptCb)); }
TransportLayerASIO::_acceptConnection 的新連線處理過程藉助ASIO 庫實現,透過 acceptor.async_accept 實現所有監聽的 acceptor 回撥非同步註冊。
當服務端接收到客戶端新連線事件通知後,會觸發執行 acceptCb () 回撥,該回撥中底層 ASIO 庫透過 epoll_wait 獲取到所有的 accept 事件,每獲取到一個 accept 事件就代表一個新的客戶端連結,然後呼叫 ServiceEntryPointImpl::startSession () 介面處理這個新的連結事件,整個過程遞迴執行,保證一次可以處理所有的客戶端 accept 請求資訊。
每個連結都會構造一個唯一的session 資訊,該 session 就代表一個唯一的新連線,連結和 session 一一對應。此外,最終會呼叫 ServiceEntryPointImpl::startSession () 進行真正的 accept() 處理,從而獲取到一個新的連結。
注意 : TransportLayerASIO::_acceptConnection () 中實現了 TransportLayerASIO 類和 ServiceEntryPointImpl 類的關聯,這兩個類在該介面實現了關聯。
此外,從前面的 TransportLayerASIO 類結構中可以看出,該類還包含如下四個介面:sourceMessage(...) 、 sinkMessage(...) 、 wait(Ticket&& ticket) 、 asyncWait(Ticket&& ticket, TicketCallback callback) ,這四個介面入參都和 Ticket 資料分發子模組相關聯,具體核心程式碼實現如下:
1. //根據asioSession, expiration, message三個資訊構造資料接收類ASIOSourceTicket 2. Ticket TransportLayerASIO::sourceMessage(...) { 3. ...... 4. auto asioSession = checked_pointer_cast<ASIOSession>(session); 5. //根據asioSession, expiration, message三個資訊構造ASIOSourceTicket 6. auto ticket = stdx::make_unique<ASIOSourceTicket>(asioSession, expiration, message); 7. return {this, std::move(ticket)}; 8. } 9. 10. //根據asioSession, expiration, message三個資訊構造資料傳送類ASIOSinkTicket 11. Ticket TransportLayerASIO::sinkMessage(...) { 12. auto asioSession = checked_pointer_cast<ASIOSession>(session); 13. auto ticket = stdx::make_unique<ASIOSinkTicket>(asioSession, expiration, message); 14. return {this, std::move(ticket)}; 15. } 16. 17. //同步接收或者傳送,最終呼叫ASIOSourceTicket::fill 或者 ASIOSinkTicket::fill 18. Status TransportLayerASIO::wait(Ticket&& ticket) { 19. //獲取對應Ticket,接收對應ASIOSourceTicket,傳送對應ASIOSinkTicket 20. auto ownedASIOTicket = getOwnedTicketImpl(std::move(ticket)); 21. auto asioTicket = checked_cast<ASIOTicket*>(ownedASIOTicket.get()); 22. ...... 23. //呼叫對應fill介面 同步接收ASIOSourceTicket::fill 或者 同步傳送ASIOSinkTicket::fill 24. asioTicket->fill(true, [&waitStatus](Status result) { waitStatus = result; }); 25. return waitStatus; 26. } 27. //非同步接收或者傳送,最終呼叫ASIOSourceTicket::fill 或者 ASIOSinkTicket::fill 28. void TransportLayerASIO::asyncWait(Ticket&& ticket, TicketCallback callback) { 29. //獲取對應資料收發的Ticket,接收對應ASIOSourceTicket,傳送對應ASIOSinkTicket 30. auto ownedASIOTicket = std::shared_ptr<TicketImpl>(getOwnedTicketImpl(std::move(ticket))); 31. auto asioTicket = checked_cast<ASIOTicket*>(ownedASIOTicket.get()); 32. 33. //呼叫對應ASIOTicket::fill 34. asioTicket->fill( 35. false, [ callback = std::move(callback), 36. ownedASIOTicket = std::move(ownedASIOTicket) ](Status status) { callback(status); }); 37. }
上面四個介面中的前兩個介面主要透過 Session, expiration, message 這三個引數來獲取對應的 Ticket 資訊,實際上mongodb 核心實現中把接收資料的 Ticket 和傳送資料的 Ticket 分別用不同的繼承類ASIOSourceTicket 和 ASIOSinkTicket 來區分,三個引數的作用如下表所示:
引數名 |
作用 |
Session |
代表一個連結,一個 session 和一個連結意義對應 |
expiration |
資料收發超時相關設定 |
message |
資料內容 |
資料收發包括同步收發和非同步收發,同步收發透過 TransportLayerASIO::wait () 實現,非同步收發透過 TransportLayerASIO::asyncWait () 實現。
注意: 以上四個介面把 TransportLayerASIO 類和 Ticket 資料收發類的關聯。
2.2
總結
transport_layer
套接字處理及傳輸層管理子模組主要由
transport_layer_manager
和
transport_layer_asio
兩個核心類組成,這兩個類的核心介面功能總結如下表所示:
類命 |
介面名 |
功能說明 |
transport_layer_manager |
TransportLayerManager::createWithConfig() |
根據配置檔案選擇不同的 TransportLayer 和 serviceExecutor |
TransportLayerManager::setup() |
已廢棄 | |
TransportLayerManager::start() |
已廢棄 | |
TransportLayerASIO |
TransportLayerASIO::Options::Options() |
Net 相關配置 |
TransportLayerASIO::TransportLayerASIO() |
初始化構造 | |
TransportLayerASIO::sourceMessage() |
獲取資料接收的 Ticket | |
TransportLayerASIO::sinkMessage() |
獲取資料傳送的 Ticket | |
TransportLayerASIO::wait() |
同步傳送接收或者傳送資料 | |
TransportLayerASIO::asyncWait() |
非同步方式傳送接收或者傳送資料 | |
TransportLayerASIO::end() |
關閉連結 | |
TransportLayerASIO::setup() |
建立套接字並 bind 繫結 | |
TransportLayerASIO::start() |
建立 listener 執行緒做監聽操作,同時註冊 accept 回撥 | |
TransportLayerASIO::shutdown() |
shutdown 處理及資源回收 | |
TransportLayerASIO::_acceptConnection() |
Accept 回撥註冊 |
T ransport_layer_manager 中初始化TransportLayer 和 serviceExecutor , net.TransportLayer 配置可以為 legacy 和 asio ,其中 legacy 已經淘汰,當前核心只支援 asio 模式。 asio 配置對應的 TransportLayer 由 TransportLayerASIO 實現,對應的 serviceExecutor 執行緒模型可以是 adaptive 動態執行緒模型,也可以是 synchronous 同步執行緒模型。
套接字建立、bind() 繫結、 listen() 監聽、 accept 事件註冊等都由本類實現,同時資料分發 Ticket 模組也與本模組關聯,一起配合完成整個後續 Ticket 模組模組的同步及非同步資料讀寫流程。此外,本模組還透過 ServiceEntryPoint 服務入口子模組聯動,保證了套接字初始化、accept 事件註冊完成後,服務入口子模組能有序的進行新連線接收處理。
接下來繼續分析本模組相關聯的 ServiceEntryPoint 服務入口子模組和 Ticket 資料分發子模組實現。
3. service_entry_point 服務入口點子模組
service_entry_point 服務入口點子模組主要負責如下功能:新連線處理、 Session 會話管理、接收到一個完整報文後的回撥處理 ( 含報文解析、認證、引擎層處理等 ) 。
該模組的原始碼實現主要包含以下幾個檔案:
service_entry_point 開頭的程式碼檔案都和本模組相關,其中 service_entry_point_utils* 負責工作執行緒建立, service_entry_point_impl* 完成新連結回撥處理及 sesseion 會話管理。
3.1 核心原始碼實現
服務入口子模組相關程式碼實現比較簡潔,主要由ServiceEntryPointImpl 類和 service_entry_point_utils 中的執行緒建立函式組成。
3.1.1 ServiceEntryPointImpl 類核心程式碼實現
ServiceEntryPointImpl 類主要成員和介面如下:
1. class ServiceEntryPointImpl : public ServiceEntryPoint { 2. MONGO_DISALLOW_COPYING(ServiceEntryPointImpl); 3. public: 4. //建構函式 5. explicit ServiceEntryPointImpl(ServiceContext* svcCtx); 6. //以下三個介面進行session會話處理控制 7. void startSession(transport::SessionHandle session) final; 8. void endAllSessions(transport::Session::TagMask tags) final; 9. bool shutdown(Milliseconds timeout) final; 10. //session會話統計 11. Stats sessionStats() const final; 12. ...... 13. private: 14. //該list結構管理所有的ServiceStateMachine資訊 15. using SSMList = stdx::list<std::shared_ptr<ServiceStateMachine>>; 16. //SSMList對應的迭代器 17. using SSMListIterator = SSMList::iterator; 18. //賦值ServiceEntryPointImpl::ServiceEntryPointImpl 19. //對應ServiceContextMongoD(mongod)或者ServiceContextNoop(mongos)類 20. ServiceContext* const _svcCtx; 21. //該成員變數在程式碼中沒有使用 22. AtomicWord<std::size_t> _nWorkers; 23. //鎖 24. mutable stdx::mutex _sessionsMutex; 25. //一個新連結對應一個ssm儲存到ServiceEntryPointImpl._sessions中 26. SSMList _sessions; 27. //最大連結數控制 28. size_t _maxNumConnections{DEFAULT_MAX_CONN}; 29. //當前的總連結數,不包括關閉的連結 30. AtomicWord<size_t> _currentConnections{0}; 31. //所有的連結,包括已經關閉的連結 32. AtomicWord<size_t> _createdConnections{0}; };
該類的幾個介面主要是session 相關控制處理,該類中的變數成員說明如下:
成員名 |
功能說明 |
_svcCtx |
服務上下文, mongod 例項對應 ServiceContextMongoD 類, mongos 代理例項對應 ServiceContextNoop 類 |
_sessionsMutex |
_sessions 鎖保護 |
_sessions |
一個新連結對應一個 ssm 儲存到 ServiceEntryPointImpl._sessions 中 |
_maxNumConnections |
最大連結數,預設 1000000 ,可以透過 maxConns 配置 |
_currentConnections |
當前的線上連結數,不包括以前關閉的連結 |
_createdConnections |
所有的連結,包括已經關閉的連結 |
ServiceEntryPointImpl 類最核心的 startSession () 介面負責每個新連線到來後的內部回撥處理,具體實現如下:
1. //新連結到來後的回撥處理 2. void ServiceEntryPointImpl::startSession(transport::SessionHandle session) { 3. //獲取該新連線對應的服務端和客戶端地址資訊 4. const auto& remoteAddr = session->remote().sockAddr(); 5. const auto& localAddr = session->local().sockAddr(); 6. //服務端和客戶端地址記錄到session中 7. auto restrictionEnvironment = stdx::make_unique<RestrictionEnvironment>(*remoteAddr, *localAddr); 8. RestrictionEnvironment::set(session, std::move(restrictionEnvironment)); 9. ...... 10. 11. //獲取transportMode,kAsynchronous或者kSynchronous 12. auto transportMode = _svcCtx->getServiceExecutor()->transportMode(); 13. //構造ssm 14. auto ssm = ServiceStateMachine::create(_svcCtx, session, transportMode); 15. {//該{}體內實現連結計數,同時把ssm統一新增到_sessions列表管理 16. stdx::lock_guard<decltype(_sessionsMutex)> lk(_sessionsMutex); 17. connectionCount = _sessions.size() + 1; //連線數自增 18. if (connectionCount <= _maxNumConnections) { 19. //新來的連結對應的session儲存到_sessions連結串列 20. //一個新連結對應一個ssm儲存到ServiceEntryPointImpl._sessions中 21. ssmIt = _sessions.emplace(_sessions.begin(), ssm); 22. _currentConnections.store(connectionCount); 23. _createdConnections.addAndFetch(1); 24. } 25. } 26. //連結超限,直接退出 27. if (connectionCount > _maxNumConnections) { 28. ...... 29. return; 30. } 31. //連結關閉的回收處理 32. ssm->setCleanupHook([ this, ssmIt, session = std::move(session) ] { 33. ...... 34. }); 35. //獲取transport模式為同步模式還是非同步模式,也就是adaptive執行緒模式還是synchronous執行緒模式 36. auto ownership = ServiceStateMachine::Ownership::kOwned; 37. if (transportMode == transport::Mode::kSynchronous) { 38. ownership = ServiceStateMachine::Ownership::kStatic; 39. } 40. //ServiceStateMachine::start,這裡和服務狀態機模組銜接起來 41. ssm->start(ownership); 42. }
該介面拿到該連結對應的服務端和客戶端地址後,記錄到該連結對應session 中,然後根據該 session 、 transportMode 、 _svcCtx 構建一個服務狀態機 ssm(ServiceStateMachine) 。一個新連結對應一個唯一 session ,一個 session 對應一個唯一的服務狀態機 ssm ,這三者保持唯一的一對一關係。
最終, startSession () 讓服務入口子模組、 session 會話子模組、 ssm 狀態機子模組關聯起來。
3.1.2 service_entry_point_utils 核心程式碼實現
service_entry_point_utils 原始碼檔案只有 launchServiceWorkerThread 一個介面,該介面主要負責工作執行緒建立,並設定每個工作執行緒的執行緒棧大小,如果系統預設棧大於 1M ,則每個工作執行緒的執行緒棧大小設定為 1M ,如果系統棧大小小於 1M ,則以系統堆疊大小為準,同時 warning 列印提示。該函式實現如下:
1. Status launchServiceWorkerThread(stdx::function<void()> task) { 2. static const size_t kStackSize = 1024 * 1024; //1M 3. struct rlimit limits; 4. //或者系統堆疊大小 5. invariant(getrlimit(RLIMIT_STACK, &limits) == 0); 6. //如果系統堆疊大小大於1M,則預設設定執行緒棧大小為1M 7. if (limits.rlim_cur > kStackSize) { 8. size_t stackSizeToSet = kStackSize; 9. int failed = pthread_attr_setstacksize(&attrs, stackSizeToSet); 10. if (failed) { 11. const auto ewd = errnoWithDescription(failed); 12. warning() << "pthread_attr_setstacksize failed: " << ewd; 13. } 14. } else if (limits.rlim_cur < 1024 * 1024) { 15. //如果系統棧大小小於1M,則已係統堆疊為準,同時給出告警 16. warning() << "Stack size set to " << (limits.rlim_cur / 1024) << "KB. We suggest 1MB"; 17. }} 18. ...... 19. //task引數傳遞給新建執行緒 20. auto ctx = stdx::make_unique<stdx::function<void()>>(std::move(task)); 21. int failed = pthread_create(&thread, &attrs, runFunc, ctx.get()); 22. ...... 23. }
3.2 總結
service_entry_point 服務入口點子模組主要負責新連線後的回撥處理及工作執行緒建立,該模組和後續的 session 會話模組、 SSM 服務狀態機模組銜接配合,完成資料收發的正常邏輯轉換處理。上面的分析只列出了服務入口點子模組的核心介面實現,下表總結該模組所有的介面功能:
類 |
介面 |
功能說明 |
ServiceEntryPointImpl |
ServiceEntryPointImpl::ServiceEntryPointImpl() |
構造初始化,最大連結數限制 |
ServiceEntryPointImpl::startSession() |
新連結的回撥處理 | |
ServiceEntryPointImpl::endAllSessions() |
Ssm 服務狀態機及 session 會話回收處理 | |
ServiceEntryPointImpl::shutdown() |
例項下線處理 | |
ServiceEntryPointImpl::sessionStats() |
獲取連結統計資訊 | |
service_entry_point_utils |
launchServiceWorkerThread |
建立工作執行緒,同時限制每個執行緒對應執行緒棧大小 |
3. Ticket 資料收發子模組
Ticket 資料收發子模組主要功能如下:呼叫 session 子模組進行底層 asio 庫處理、拆分資料接收和資料傳送到兩個類、完整 mongodb 報文讀取 、接收或者傳送 mongodb 報文後的回撥處理。
3.1 ASIOTicket 類核心程式碼實現
Ticket 資料收發模組相關實現主要由 ASIOTicket 類完成,該類結構如下:
1. //下面的ASIOSinkTicket和ASIOSourceTicket繼承該類,用於控制資料的傳送和接收 2. class TransportLayerASIO::ASIOTicket : public TicketImpl { 3. public: 4. //初始化構造 5. explicit ASIOTicket(const ASIOSessionHandle& session, Date_t expiration); 6. //獲取sessionId 7. SessionId sessionId() const final { 8. return _sessionId; 9. } 10. //asio模式沒用,針對legacy模型 11. Date_t expiration() const final { 12. return _expiration; 13. } 14. 15. //以下四個介面用於資料收發相關處理 16. void fill(bool sync, TicketCallback&& cb); 17. protected: 18. void finishFill(Status status); 19. bool isSync() const; 20. virtual void fillImpl() = 0; 21. private: 22. //會話資訊,一個連結一個session 23. std::weak_ptr<ASIOSession> _session; 24. //每個session有一個唯一id 25. const SessionId _sessionId; 26. //asio模型沒用,針對legacy生效 27. const Date_t _expiration; 28. //資料傳送或者接收成功後的回撥處理 29. TicketCallback _fillCallback; 30. //同步方式還是非同步方式進行資料處理,預設非同步 31. bool _fillSync; 32. };
該類保護多個成員變數,這些成員變數功能說明如下:
成員名 |
作用 |
_session |
Session 會話資訊,一個連結對應一個 session |
_sessionId |
每個 session 都有一個對應的唯一 ID |
_expiration |
Legacy 模式使用,當前都是用 asio ,該成員已淘汰 |
_fillCallback |
傳送或者接收一個完整 mongodb 報文後的回撥處理 |
_fillSync |
同步還是非同步方式收發資料。 adaptive 執行緒模型為非同步, synchronous 執行緒模型為同步讀寫方式 |
mongodb 在具體實現上,資料接收和資料傳送分開實現,分別是資料接收類 ASIOSourceTicket 和資料傳送類 ASIOSinkTicket ,這兩個類都繼承自 ASIOTicket 類,這兩個類的主要結構如下:
1. //資料接收的ticket 2. class TransportLayerASIO::ASIOSourceTicket : public TransportLayerASIO::ASIOTicket { 3. public: 4. //初始化構造 5. ASIOSourceTicket(const ASIOSessionHandle& session, Date_t expiration, Message* msg); 6. protected: 7. //資料接收Impl 8. void fillImpl() final; 9. private: 10. //接收到mongodb頭部資料後的回撥處理 11. void _headerCallback(const std::error_code& ec, size_t size); 12. //接收到mongodb包體資料後的回撥處理 13. void _bodyCallback(const std::error_code& ec, size_t size); 14. 15. //儲存資料的buffer,網路IO讀取到的原始資料內容 16. SharedBuffer _buffer; 17. //資料Message管理,資料來源為_buffer 18. Message* _target; 19. }; 1. 2. 20. //資料傳送的ticket 21. class TransportLayerASIO::ASIOSinkTicket : public TransportLayerASIO::ASIOTicket { 22. public: 23. //初始化構造 24. ASIOSinkTicket(const ASIOSessionHandle& session, Date_t expiration, const Message& msg); 25. protected: 26. //資料傳送Impl 27. void fillImpl() final; 28. private: 29. //傳送資料完成的回撥處理 30. void _sinkCallback(const std::error_code& ec, size_t size); 31. //需要傳送的資料message資訊 32. Message _msgToSend; 33. };
從上面的程式碼實現可以看出, ASIOSinkTicket 和 ASIOSourceTicket 類介面及成員實現幾乎意義,只是具體的實現方法不同,下面對ASIOSourceTicket 和 ASIOSinkTicket 相關核心程式碼實現進行分析。
3.1.2 ASIOSourceTicket 資料接收核心程式碼實現
資料接收過程核心程式碼如下:
1. //資料接收的fillImpl介面實現 2. void TransportLayerASIO::ASIOSourceTicket::fillImpl() { 3. //獲取對應session資訊 4. auto session = getSession(); 5. if (!session) 6. return; 7. //收到讀取mongodb頭部資料,頭部資料長度是固定的kHeaderSize位元組 8. const auto initBufSize = kHeaderSize; 9. _buffer = SharedBuffer::allocate(initBufSize); 10. 11. //呼叫TransportLayerASIO::ASIOSession::read讀取底層資料存入_buffer 12. //讀完頭部資料後執行對應的_headerCallback回撥函式 13. session->read(isSync(), 14. asio::buffer(_buffer.get(), initBufSize), //先讀取頭部欄位出來 15. [this](const std::error_code& ec, size_t size) { _headerCallback(ec, size); }); 16. } 17. 18. //讀取到mongodb header頭部資訊後的回撥處理 19. void TransportLayerASIO::ASIOSourceTicket::_headerCallback(const std::error_code& ec, size_t size) { 20. ...... 21. //獲取session資訊 22. auto session = getSession(); 23. if (!session) 24. return; 25. //從_buffer中獲取頭部資訊 26. MSGHEADER::View headerView(_buffer.get()); 27. //獲取message長度 28. auto msgLen = static_cast<size_t>(headerView.getMessageLength()); 29. //長度太小或者太大,直接報錯 30. if (msgLen < kHeaderSize || msgLen > MaxMessageSizeBytes) { 31. ....... 32. return; 33. } 34. .... 35. //內容還不夠一個mongo協議報文,繼續讀取body長度位元組的資料,讀取完畢後開始body處理 36. //注意這裡是realloc,保證頭部和body在同一個buffer中 37. _buffer.realloc(msgLen); 38. MsgData::View msgView(_buffer.get()); 39. 40. //呼叫底層TransportLayerASIO::ASIOSession::read讀取資料body 41. session->read(isSync(), 42. //資料讀取到該buffer 43. asio::buffer(msgView.data(), msgView.dataLen()), 44. //讀取成功後的回撥處理 45. [this](const std::error_code& ec, size_t size) { _bodyCallback(ec, size); }); 46. } 47. 48. //_headerCallback對header讀取後解析header頭部獲取到對應的msg長度,然後開始body部分處理 49. void TransportLayerASIO::ASIOSourceTicket::_bodyCallback(const std::error_code& ec, size_t size) { 50. ...... 51. //buffer轉存到_target中 52. _target->setData(std::move(_buffer)); 53. //流量統計 54. networkCounter.hitPhysicalIn(_target->size()); 55. //TransportLayerASIO::ASIOTicket::finishFill 56. finishFill(Status::OK()); //包體內容讀完後,開始下一階段的處理 57. //報文讀取完後的下一階段就是報文內容處理,開始走ServiceStateMachine::_processMessage 58. }
Mongodb 協議由 msg header + msg body 組成,一個完整的 mongodb 報文內容格式如下:
上圖所示各個欄位及body 內容部分功能說明如下表:
Header or body |
欄位名 |
功能說明 |
msg header |
messageLength |
整個 message 長度,包括 header 長度和 body 長度 |
requestID |
該請求 id 資訊 | |
responseTo |
應答 id | |
opCode |
操作型別: OP_UPDATE 、 OP_INSERT 、 OP_QUERY 、 OP_DELETE 等 | |
msg body |
Body |
不同 opCode 對應的包體內容 |
ASIOSourceTicket 類的幾個核心介面都是圍繞這一原則展開,整個mongodb 資料接收流程如下:
1. 讀取mongodb 頭部 header 資料,解析出 header 中的 messageLength 欄位。
2. 檢查messageLength 欄位是否在指定的合理範圍,該欄位不能小於 Header 整個頭部大小,也不能超過 MaxMessageSizeBytes 最大長度。
3. Header len 檢查透過,說明讀取 header 資料完成,於是執行 _headerCallback 回撥。
4. realloc 更多的空間來儲存 body 內容。
5. 繼續讀取body len 長度資料,讀取 body 完成後,執行 _bodyCallback 回撥處理。
3.1.3 ASIOSinkTicket 資料傳送類核心程式碼實現
ASIOSinkTicket 傳送類相比接收類,沒有資料解析相關的流程,因此實現過程會更加簡單,具體原始碼實現如下:
1. //傳送資料成功後的回撥處理 2. void TransportLayerASIO::ASIOSinkTicket::_sinkCallback(const std::error_code& ec, size_t size) { 3. //傳送的網路位元組數統計 4. networkCounter.hitPhysicalOut(_msgToSend.size()); 5. //執行SSM中對應的狀態流程 6. finishFill(ec ? errorCodeToStatus(ec) : Status::OK()); 7. } 8. 9. //傳送資料的fillImpl 10. void TransportLayerASIO::ASIOSinkTicket::fillImpl() { 11. //獲取對應session 12. auto session = getSession(); 13. if (!session) 14. return; 15. 16. //呼叫底層TransportLayerASIO::ASIOSession::write傳送資料,傳送成功後執行_sinkCallback回撥 17. session->write(isSync(), 18. asio::buffer(_msgToSend.buf(), _msgToSend.size()), 19. //傳送資料成功後的callback回撥 20. [this](const std::error_code& ec, size_t size) { _sinkCallback(ec, size); }); 21. }
3.2 總結
從上面的分析可以看出,Ticket 資料收發模組主要呼叫 session 會話模組來進行底層資料的讀寫、解析,當讀取或者傳送一個完整的 mongodb 報文後最終交由 SSM 服務狀態機模組排程處理。
ticket 模組主要介面功能總結如下表所示:
類命 |
介面名 |
功能說明 |
ASIOTicket |
ASIOTicket::getSession() |
獲取 session 資訊 |
ASIOTicket::isSync() |
判斷是同步收發還是非同步收發 | |
ASIOTicket::finishFill() |
執行 _fillCallback 回撥 | |
ASIOTicket::fill() |
給 _fillCallback 賦值 | |
ASIOTicket::ASIOTicket() |
ASIOTicket 構造初始化 | |
ASIOSourceTicket |
ASIOSourceTicket::ASIOSourceTicket() |
ASIOSourceTicket 初始化 |
ASIOSourceTicket::_bodyCallback() |
接收到 mesg header+body 後的回撥處理 | |
ASIOSourceTicket::_headerCallback |
接收到 msg header 後的回撥處理 | |
ASIOSinkTicket |
ASIOSinkTicket::ASIOSinkTicket() |
ASIOSinkTicket 初始化構造 |
ASIOSourceTicket::fillImpl() |
傳送指定 msg 資料,傳送完成後執行回撥 | |
ASIOSinkTicket::_sinkCallback |
傳送 msg 成功後的回撥處理 |
前面的分析也可以看出,Ticket 資料收發模組會呼叫 session 處理模組來進行真正的資料讀寫,同時接收或者傳送完一個完整 mongodb 報文後的後續回撥處理講交由 SSM 服務狀態機模組處理。
4. Session 會話子模組
Session 會話模組功能主要如下:負責記錄 HostAndPort 、和底層 asio 庫直接互動,實現資料的同步或者非同步收發。一個新連線 fd 對應一個唯一的 session ,對 fd 的操作直接對映為 session 操作。 Session 會話子模組主要程式碼實現相關檔案如下:
4.1 session 會話子模組核心程式碼實現
1. class TransportLayerASIO::ASIOSession : public Session { 2. //初始化構造 3. ASIOSession(TransportLayerASIO* tl, GenericSocket socket); 4. //獲取本session使用的tl 5. TransportLayer* getTransportLayer(); 6. //以下四個介面套接字相關,本端/對端地址獲取,獲取fd,關閉fd等 7. const HostAndPort& remote(); 8. const HostAndPort& local(); 9. GenericSocket& getSocket(); 10. void shutdown(); 11. 12. //以下四個介面呼叫asio網路庫實現資料的同步收發和非同步收發 13. void read(...) 14. void write(...) 15. void opportunisticRead(...) 16. void opportunisticWrite(...) 17. 18. //遠端地址資訊 19. HostAndPort _remote; 20. //本段地址資訊 21. HostAndPort _local; 22. //賦值見TransportLayerASIO::_acceptConnection 23. //也就是fd,一個新連線對應一個_socket 24. GenericSocket _socket; 25. //SSL相關不做分析, 26. #ifdef MONGO_CONFIG_SSL 27. boost::optional<asio::ssl::stream<decltype(_socket)>> _sslSocket; 28. bool _ranHandshake = false; 29. #endif 30. 31. //本套接字對應的tl,賦值建TransportLayerASIO::_acceptConnection(...) 32. TransportLayerASIO* const _tl; 33. }
該類最核心的三個介面ASIOSession(...) 、 opportunisticRead(...) 、 opportunisticWrite(..) 分別完成套接字處理、呼叫 asio 庫介面實現底層資料讀和底層資料寫。這三個核心介面原始碼實現如下:
1. //初始化構造 TransportLayerASIO::_acceptConnection呼叫 2. ASIOSession(TransportLayerASIO* tl, GenericSocket socket) 3. //fd描述符及TL初始化賦值 4. : _socket(std::move(socket)), _tl(tl) { 5. std::error_code ec; 6. 7. //非同步方式設定為非阻塞讀 8. _socket.non_blocking(_tl->_listenerOptions.transportMode == Mode::kAsynchronous, ec); 9. fassert(40490, ec.value() == 0); 10. 11. //獲取套接字的family 12. auto family = endpointToSockAddr(_socket.local_endpoint()).getType(); 13. //滿足AF_INET 14. if (family == AF_INET || family == AF_INET6) { 15. //no_delay keep_alive套接字系統引數設定 16. _socket.set_option(asio::ip::tcp::no_delay(true)); 17. _socket.set_option(asio::socket_base::keep_alive(true)); 18. //KeepAlive系統引數設定 19. setSocketKeepAliveParams(_socket.native_handle()); 20. } 21. 22. //獲取本端和對端地址 23. _local = endpointToHostAndPort(_socket.local_endpoint()); 24. _remote = endpointToHostAndPort(_socket.remote_endpoint(ec)); 25. if (ec) { 26. LOG(3) << "Unable to get remote endpoint address: " << ec.message(); 27. } 28. }
該類初始化的時候完成新連線_socket 相關的初始化設定,包括阻塞讀寫還是非阻塞讀寫。如果是同步執行緒模型 ( 一個連結一個執行緒 ) ,則讀寫方式位阻塞讀寫;如果是非同步執行緒模型 (adaptive 動態執行緒模型 ) ,則呼叫 asio 網路庫介面實現非同步讀寫。
此外,該連結_socket 對應的客戶端 ip:port 和服務端 ip:port 也在該初始化類中獲取,最終儲存到本 session 的 _remote 和 _local 成員中。
資料讀取核心程式碼實現如下:
1. //讀取指定長度資料,然後執行handler回撥 2. void opportunisticRead(...) { 3. std::error_code ec; 4. //如果是非同步執行緒模型,在ASIOSession構造初始化的時候會設定non_blocking非阻塞模式 5. //非同步執行緒模型這裡實際上是非阻塞讀取,如果是同步執行緒模型,則沒有non_blocking設定,也就是阻塞讀取 6. auto size = asio::read(stream, buffers, ec); 7. 8. //如果是非同步讀,並且read返回would_block或者try_again說明指定長度的資料還沒有讀取完畢 9. if ((ec == asio::error::would_block || ec == asio::error::try_again) && !sync) { 10. //buffers有大小size,實際讀最多讀size位元組 11. MutableBufferSequence asyncBuffers(buffers); 12. if (size > 0) { 13. asyncBuffers += size; //buffer offset向後移動 14. } 15. 16. //繼續非同步方式讀取資料,讀取到指定長度資料後執行handler回撥處理 17. asio::async_read(stream, asyncBuffers, std::forward<CompleteHandler>(handler)); 18. } else { 19. //阻塞方式讀取read返回後可以保證讀取到了size位元組長度的資料 20. //直接read獲取到size位元組資料,則直接執行handler 21. handler(ec, size); 22. } 23. }
opportunisticRead 首先呼叫asio::read(stream, buffers, ec) 讀取 buffers 對應 size 長度的資料, buffers 空間大小就是需要讀取的資料 size 大小。如果是同步執行緒模型,則這裡為阻塞式讀取,直到讀到 size 位元組才會返回;如果是非同步執行緒模型,這這裡是非阻塞讀取,非阻塞讀取當核心網路協議棧資料讀取完畢後,如果還沒有讀到 size 位元組,則繼續進行 async_read 非同步讀取。
當buffers 指定的 size 位元組全部讀取完整後,不管是同步模式還是非同步模式,最終都會執行 handler 回撥,開始後續的資料解析及處理流程。
傳送資料核心程式碼實現如下:
1. //傳送資料 2. void opportunisticWrite(...) { 3. std::error_code ec; 4. //如果是同步模式,則阻塞寫,直到全部寫成功。非同步模式則非阻塞寫 5. auto size = asio::write(stream, buffers, ec); 6. 7. //非同步寫如果返回try_again說明資料還沒有傳送完,則繼續非同步寫傳送 8. if ((ec == asio::error::would_block || ec == asio::error::try_again) && !sync) { 9. ConstBufferSequence asyncBuffers(buffers); 10. if (size > 0) { //buffer中資料指標偏移計數 11. asyncBuffers += size; 12. } 13. //非同步寫傳送完成,執行handler回撥 14. asio::async_write(stream, asyncBuffers, std::forward<CompleteHandler>(handler)); 15. } else { 16. //同步寫成功,則直接執行handler回撥處理 17. handler(ec, size); 18. } 19. }
資料傳送流程和資料接收流程類似,也分位同步模式傳送和非同步模式傳送,同步模式傳送為阻塞式寫,只有當所有資料透過 asio::write () 傳送成功後才返回;非同步模式傳送為非阻塞寫, asio::write () 不一定全部傳送出去,因此需要再次呼叫 asio 庫的 asio::async_write( ) 進行非同步傳送。
不管是同步模式還是非同步模式傳送資料,最終資料傳送成功後,都會呼叫 handler () 回撥來執行後續的流程。
4.2 總結
從上面的程式碼分析可以看出,session 會話模組最終直接和 asio 網路庫互動實現資料的讀寫操作。該模組核心介面功能總結如下表:
類名 |
介面名 |
功能說明 |
ASIOSession |
ASIOSession(...) |
新連線 fd 相關處理,如是否非阻塞、 delay 設定、 keep_alive 設定、兩端地址獲取等 |
getTransportLayer() |
獲取對應 TL | |
remote() |
獲取該連結對應的對端 Ip:port 資訊 | |
local() |
獲取該連結對應的對端 Ip:port 資訊 | |
getSocket() |
獲取該連結的 fd | |
shutdown() |
fd 回收處理 | |
opportunisticRead() |
同步或者非同步資料讀操作 | |
opportunisticWrite() |
同步或者非同步資料寫操作 |
5. 總結
《Mongodb 網路傳輸處理原始碼實現及效能調優 - 體驗核心效能極致設計》 一文對 mongodb 網路傳輸模組中的 ASIO 網路庫實現、 service_executor 服務執行子模組 ( 即執行緒模型子模組 ) 進行了詳細的分析,加上本文的 transport_layer 套接字處理及傳輸層管理子模組、 session 會話子模組、 Ticket 資料收發子模組、 service_entry_point 服務入口點子模組。
transport_layer 套接字處理及傳輸層管理子模組主要由 transport_layer_manager 和 transport_layer_asio 兩個核心類組成。分別完成 net 相關的配置檔案初始化操作,套接字初始化及處理,最終 transport_layer_asio 的相應介面實現了和 ticket 資料分發子模組、服務入口點子模組的關聯。
服務入口子模組主要由ServiceEntryPointImpl 類和 service_entry_point_utils 中的執行緒建立函式組成,實現新連線 accept 處理及控制。該模組透過 startSession() 讓服務入口子模組、 session 會話子模組、 ssm 狀態機子模組關聯起來。
ticket 資料收發子模組主要功能如下:呼叫 session 子模組進行底層 asio 庫處理、拆分資料接收和資料傳送到兩個類、完整 mongodb 報文讀取 、接收或者傳送 mongodb 報文後的回撥處理 , 回撥處理由 SSM 服務狀態機模組管理,當讀取或者傳送一個完整的 mongodb 報文後最終交由 SSM 服務狀態機模組排程處理。。
Session 會話模組功能主要如下:負責記錄 HostAndPort 、和底層 asio 庫直接互動,實現資料的同步或者非同步收發。一個新連線 fd 對應一個唯一的 session ,對 fd 的操作直接對映為 session 操作。
到這裡,整個mongodb 網路傳輸層模組分析只差 service_state_machine 狀態機排程子模組,狀態機排程子模組相比本文分析的幾個子模組更加複雜,因此將在下期《 mongodb 網路傳輸層模組原始碼分析三》中單獨分析。
本文所有原始碼註釋分析詳見如下連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69984922/viewspace-2729717/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mongodb核心原始碼實現、效能調優、最佳運維實踐系列-mongodb網路傳輸層模組原始碼實現三MongoDB原始碼運維
- mongodb核心原始碼實現、效能調優、最佳運維實踐系列-網路傳輸層模組原始碼實現三MongoDB原始碼運維
- mongodb核心原始碼實現、效能調優、最佳運維實踐系列-網路傳輸層模組原始碼實現四MongoDB原始碼運維
- mongodb核心原始碼實現、效能調優、最佳運維實踐系列-command命令處理模組原始碼實現二MongoDB原始碼運維
- mongodb核心原始碼實現、效能調優、最佳運維實踐系列-command命令處理模組原始碼實現三MongoDB原始碼運維
- mongodb核心原始碼實現、效能調優、最佳運維實踐系列-command命令處理模組原始碼實現一MongoDB原始碼運維
- mongodb核心原始碼實現及效能最佳化:transport_layer網路傳輸層模組原始碼實現二MongoDB原始碼
- mongodb核心transport_layer網路傳輸層模組原始碼實現三MongoDB原始碼
- mongodb核心transport_layer 網路傳輸層模組原始碼實現四MongoDB原始碼
- mongodb原始碼實現、調優、最佳實踐系列-數百萬行mongodb核心原始碼閱讀經驗分享MongoDB原始碼
- mongodb核心原始碼實現及效能優化系列:Mongodb write寫(增、刪、改)模組原始碼實現MongoDB原始碼優化
- mongodb網路傳輸處理原始碼實現及效能調優-體驗核心效能極致設計MongoDB原始碼
- 萬字長文 | MongoDB絡傳輸處理原始碼實現及效能調優MongoDB原始碼
- mongodb核心原始碼實現及效能最佳化系列:Mongodb特定場景效能數十倍提升最佳化實踐MongoDB原始碼
- mongodb核心原始碼實現、效能調優系列-為何要對開源mongodb資料庫核心做二次開發MongoDB原始碼資料庫
- Mongodb write寫(增、刪、改)模組原始碼實現MongoDB原始碼
- 網路傳輸層模組原始碼實現一(體驗效能極致設計)--2020年度中mongodb中文社群一等獎原始碼MongoDB
- mongodb核心原始碼實現及效能最佳化:常用高併發執行緒模型設計及mongodb執行緒模型最佳化實踐MongoDB原始碼執行緒模型
- 70行實現Promise核心原始碼Promise原始碼
- 多合一收款二維碼原理及實現(原始碼)原始碼
- Vue原始碼探究-核心類的實現Vue原始碼
- 實現彩色二維碼程式碼實
- spring原始碼解析 (七) 事務底層原始碼實現Spring原始碼
- 最佳實踐 | 原始碼升級gcc原始碼GC
- Promise原始碼實現Promise原始碼
- Seata原始碼分析(一). AT模式底層實現原始碼模式
- HashMap原始碼實現分析HashMap原始碼
- webpack Hmr 原始碼實現Web原始碼
- 仿Express原始碼實現(-)Express原始碼
- PostgreSQL MVCC 原始碼實現SQLMVC原始碼
- 婚戀app原始碼開發,如何實現介面效能優化?APP原始碼優化
- Redis核心原理與實踐--事務實踐與原始碼分析Redis原始碼
- java實現二維碼生成Java
- QT Widgets模組原始碼解析與實踐QT原始碼
- Axios 原始碼解讀 —— 原始碼實現篇iOS原始碼
- inet_pton在freeBSD中實現的原始碼+核心原始碼搜尋網站原始碼網站
- OkHttp 3.7原始碼分析(二)——攔截器&一個實際網路請求的實現HTTP原始碼
- SpringMVC實現多檔案上傳原始碼SpringMVC原始碼