evpp是一個基於libevent開發的現代化C++11高性能網絡服務器,自帶TCP/UDP/HTTP等協議的異步非阻塞式的服務器和客戶端庫。
特性:
-
現代版的C++11接口
-
非阻塞異步接口都是C++11的functional/bind形式的回調仿函數(不是libevent中的C風格的函數指針)
-
非阻塞純異步多線程TCP服務器/客戶端
-
非阻塞純異步多線程HTTP服務器/客戶端
-
非阻塞純異步多線程UDP服務器
-
支持多進程模式
-
優秀的跨平台特性和高性能(繼承自libevent的優點)
除此之外,基於該庫之上,還提供兩個附帶的應用層協議庫:
-
evmc :一個純異步非阻塞式的memcached的C++客戶端庫,支持membase集群模式。詳情請見:evmc readme
-
evnsq : 一個純異步非阻塞式的NSQ的C++客戶端庫,支持消費者、生產者、服務發現等特性。詳情請見:evnsq readme
將來還會推出redis的客戶端庫。
由來:
我們開發小組負責的業務需要用到TCP協議來建設長連接網關服務和一些其他的一些基於TCP的短連接服務,在調研開源項目的過程中,沒有發現一個合適的庫來滿足我們要求。結合我們自身的業務情況,理想中的C++網絡庫應具備一下幾個特性:
-
接口簡單易用,最好是C++接口
-
多線程,也能支持多進程
-
最好是基於libevent實現(因為現有的歷史遺留框架、基礎庫等是依賴libevent),這樣能很方便嵌入libevent的事件循環,否則改動較大或者集成起來的程序可能會有很多跨線程的調用
基於這些需要,可供選擇的不多,所以我們只能自己開發一個。開發過程中,接口設計方面基本上大部分是參考muduo項目來設計和實現的,當然也做了一些取舍和增改;同時也大量借鑒了Golang的一些設計哲學和思想,舉幾個小例子來說明一下:
-
Duration : 這是一個時間區間相關的類,自帶時間單位信息,參考了Golang項目中的Duration實現。我們在其他項目中見到太多的時間是不帶單位的,例如timeout,到底是秒、毫秒還是微秒?需要看文檔說明或具體實現,好一點的設計會將單位帶在變量名中,例如timeout_ms,但還是沒有Duration這種獨立的類好。目前C++11中也有類似的實現std::chrono::duration,但稍顯復雜,沒有咱們這個借鑒Golang實現的版本來的簡單明了。
-
Buffer : 這是一個緩沖區類,融合了muduo和Golang兩個項目中相關類的設計和實現
-
http::Server : 這是一個http服務器類,自帶線程池,它的事件循環和工作線程調度,完全是線程安全的,業務層不用太多關心跨線程調用問題。同時,還將http服務器的核心功能單獨抽取出來形成
-
http::Service類,是一個可嵌入型的服務器類,可以嵌入到已有的libevent事件循環中。
網絡地址的表達就僅僅使用"ip:port"這種形式字符串表示,就是參考Golang的設計 -
httpc::ConnPool是一個http的客戶端連接池庫,設計上盡量考慮高性能和復用。以后基於此還可以增加負載均衡和故障轉移等特性。
另外,我們實現過程中極其重視線程安全問題,一個事件相關的資源必須在其所屬的EventLoop中初始化和析構釋放,這樣我們能最大限度的減少出錯的可能。為了達到這個目標我們重載event_add和event_del等函數,每一次調用event_add,就在對應的線程私有數據中記錄該對象,在調用event_del時,檢查之前該線程私有數據中是否擁有該對象,然后在整個程序退出前,再完整的檢查所有線程的私有數據,看看是否仍然有對象沒有析構釋放,詳細代碼實現可以參考 https://github.com/Qihoo360/evpp/blob/master/evpp/inner_pre.cc#L46~L87。我們如此苛刻的追求線程安全,只是為了讓一個程序能安靜的平穩的退出或Reload,因為我們深刻的理解“編寫永遠運行的系統,和編寫運行一段時間后平靜關閉的系統是兩碼事”,后者要困難的多。
http://www.oschina.net/p/evpp
