Chaos網(wǎng)絡(luò)事件庫菜鳥修煉寶典
Chaos是一個(gè)基于Linux平臺(tái), c++開發(fā)的reactor模式的網(wǎng)絡(luò)事件庫, 目前僅支持TCP傳輸協(xié)議, 僅在x86_64下編譯, 并遵循3-clause BSD開源協(xié)議. 在使用上, 可以說它很像boost asio, 可能是由于我對(duì)boost asio的接口設(shè)計(jì)很有愛吧, 而且對(duì)于boost asio在異步編程方面的思想, 我個(gè)人也比較認(rèn)同, 但至今我也沒有仔細(xì)閱讀過boost asio的源碼, 一是boost的模板化編程在可讀性上讓我比較折磨, 其二則是不想在對(duì)設(shè)計(jì)先入為主的情況下去開發(fā)chaos, 很多事情只有我們自己親自去思考, 才能有所收獲.
進(jìn)入主題, 關(guān)于chaos庫源碼和所有測(cè)試用例和應(yīng)用服務(wù), 都可在https://github.com/lyjdamzwf/chaos 下載
源碼目錄結(jié)構(gòu)
chaos – chaos庫源碼
async_method – 用于異步消息隊(duì)列的實(shí)現(xiàn), 是最小的task單位, 類似于boost::bind & boost:function
utility – 常用工具類
thread – 對(duì)pthread的封裝
task_service – 核心模塊, 包含了異步消息隊(duì)列, 網(wǎng)絡(luò)I/O管理, 以及超時(shí)事件, task_service可以作為多線程異步編程強(qiáng)大的工具而不單單作為一個(gè)網(wǎng)絡(luò)層的reactor模塊(相當(dāng)于boost asio的io_service)
log – 日志組件
heart_beat – 基于task_service的通用型元素心跳管理.
network - 基于task_service, 底層I/O multiplexing使用epoll LT模式, 提供了常用的socket行為, 統(tǒng)一對(duì)連接進(jìn)行管理, 并提供了用戶空間的讀寫緩沖區(qū), 可以使開發(fā)者快速地搭建一個(gè)tcp服務(wù)器
test – 一些測(cè)試用例, 小到一個(gè)工具類的測(cè)試, 大到不同類型的服務(wù)器程序
簡(jiǎn)單的TCP Server
要建立一個(gè)tcp server, 使用chaos只要簡(jiǎn)單的三步:
1. 首先我們要先定義一個(gè)連接事件回調(diào), 當(dāng)chaos發(fā)現(xiàn)任何連接狀態(tài)的改變都會(huì)回調(diào)該函數(shù)
2. 連接策略類的定義, 該類告訴chaos對(duì)于tcp數(shù)據(jù)包如何處理
這里需要特別說明一點(diǎn)的是, 對(duì)于tcp字節(jié)流的處理, chaos底層有默認(rèn)的機(jī)制, 當(dāng)一個(gè)完整的數(shù)據(jù)包被讀取之后, handle_packet就會(huì)被調(diào)用, 可以看到, 服務(wù)在收到完整的數(shù)據(jù)包之后, 發(fā)送了同樣的內(nèi)容給對(duì)端.
默認(rèn)策略的實(shí)現(xiàn)就在test_server_echo_conn_t所繼承的default_conn_strategy_t中, 該類對(duì)所有tcp字節(jié)流的處理流程是:
默認(rèn)策略的包頭成員:
如果你希望使用自己的tcp字節(jié)流解析策略, 那么可以自己繼承chaos::network::connection_t進(jìn)行實(shí)現(xiàn), 在初始化服務(wù)的時(shí)候注入自己的策略即可, 具體方式是提供一個(gè)你繼承自connection_t的類, 然后作為tcp_service_t的模板參數(shù)
3. 初始化并啟動(dòng)服務(wù)
chaos::network::tcp_service_t類的運(yùn)行機(jī)制是固定一個(gè)線程做accept的工作, 而accept成功的連接會(huì)分派到各個(gè)work線程上進(jìn)行I/O, work線程的數(shù)量可在start時(shí)指定.
這樣就完成了一個(gè)簡(jiǎn)單的tcp echo server的建立, 以上只是我截取的關(guān)鍵代碼片段, 在chaos/test/echo_server目錄中有完整的代碼可供參考.
如何生成并應(yīng)用chaos到自己的項(xiàng)目
chaos目前提供的鏈接方式是以靜態(tài)庫(.a)存在的, 你可以運(yùn)行根目錄下的build_all.sh腳本進(jìn)行生成(需要安裝automake軟件), 你不需要再安裝任何第三方庫即可編譯整個(gè)chaos, 當(dāng)編譯完成后會(huì)在根目錄生成lib臨時(shí)目錄, 里面即包含相應(yīng)的chaos靜態(tài)庫, 之后可參照test目錄下的用例的方式鏈接到自己的項(xiàng)目中.
網(wǎng)絡(luò)庫之外看chaos
之前我曾提到task_service不僅僅是作為一個(gè)網(wǎng)絡(luò)庫的Reactor核心, 它亦可作為日常開發(fā)當(dāng)中多線程及異步編程的利器, 讓你不用關(guān)心線程切換, 多線程消息投遞等細(xì)節(jié)問題, 通過簡(jiǎn)單地將請(qǐng)求包裝成一個(gè)異步方法, 投遞到指定的task_service(線程池)中, 就能執(zhí)行該任務(wù), 在之后的系列文章中我會(huì)做詳細(xì)分析.
Chaos與libevent, boost asio, ACE, ICE等知名庫的不同之處
從開始寫chaos時(shí), 我的初衷可能就不是libevent, boost asio那樣的通用庫, 而是幫助使用者快速搭建一個(gè)簡(jiǎn)單易用的tcp服務(wù), 基于reactor核心寫的network模塊也是出于這個(gè)目的而做的封裝. 如果使用libevent或boost asio, 你依然要關(guān)心如何去接受一個(gè)連接, 去創(chuàng)建啟動(dòng)線程, 去驅(qū)動(dòng)EventLoop, 考慮如何分配線程, 如何管理連接, 而如果使用ACE, ICE, 又會(huì)顯得比較臃腫龐大, 另一個(gè)角度看, ICE是個(gè)網(wǎng)絡(luò)服務(wù)解決方案, 而不是單純的網(wǎng)絡(luò)庫, 而chaos就介于他們之間, 即保持著一定的輕量化, 也希望使用者能夠足夠易用快速開發(fā), 當(dāng)然, 這樣也必然會(huì)失去一些靈活性, 但我個(gè)人覺得這對(duì)于絕大部分應(yīng)用都無傷大雅.
性能
對(duì)于部分應(yīng)用來講, 雖然網(wǎng)絡(luò)層不會(huì)成為整個(gè)服務(wù)的瓶頸所在, 但網(wǎng)絡(luò)庫的性能依然至關(guān)重要, 我個(gè)人認(rèn)為在本機(jī)做吞吐量的測(cè)試是一個(gè)不錯(cuò)的途徑, 而且不用考慮硬件網(wǎng)卡的限制, 我的方法是在同樣的機(jī)器環(huán)境上, 根據(jù)不同的應(yīng)用層緩沖區(qū)大小, 連接數(shù), 單線程/多線程 這幾個(gè)方面來評(píng)測(cè).
具體流程是, 客戶端啟動(dòng)N個(gè)線程并啟動(dòng)N個(gè)TCP連接向服務(wù)器發(fā)送數(shù)據(jù), 服務(wù)器接收到完整的數(shù)據(jù)包之后馬上回傳相同內(nèi)容給對(duì)端(如同上面的echo server), 一段時(shí)間后統(tǒng)計(jì)整個(gè)過程的吞吐量, 以下是我統(tǒng)計(jì)的相關(guān)數(shù)據(jù):
測(cè)試環(huán)境信息
服務(wù)器型號(hào): HP DL160
CPU: E5504
MEM:
OS: centOS 5.8
當(dāng)然, 需要一提的是這份吞吐量測(cè)試報(bào)告和其他一些網(wǎng)絡(luò)庫的吞吐量測(cè)試沒有太大的可對(duì)比性, 畢竟不同的硬件環(huán)境, 不同的測(cè)試代碼給結(jié)果帶來的差距比我們想象當(dāng)中的要大.
吞吐量的測(cè)試客戶端可在test/throughput_client目錄中找到完整的代碼
服務(wù)器代碼見echo_server