1. 程式人生 > >epoll程式設計,如何實現高併發伺服器開發?

epoll程式設計,如何實現高併發伺服器開發?

閒答。

按重要性和基礎程度,打亂下順序吧~~
先回問題,然後說怎麼實現。

注:以下資料,均基於亞馬遜AWS c3.xlarge 機型。
虛擬CPU:4
記憶體:7.5 GB
c3.xlarge 配置和價格: AWS | Amazon EC2

~~~~~~~~~~ 分割線 ~~~~~~~~~~
2、查了很多資料,單單多程序是不現實的,但是多執行緒開發linux系統線上程的數量上是有上限的,如何解決?
多執行緒數量限制?有!但這重要嗎?想著開著無限的執行緒,每個執行緒都在跑?

執行緒排程是有系統資源開銷的!!!!
執行緒排程是有系統資源開銷的!!!!
執行緒排程是有系統資源開銷的!!!!

重要的事情說三遍~~!!!
理論上,如果沒有I/O等待等讓CPU idle的事情,執行緒數最好等於CPU核心數目。
執行緒數最好等於CPU核心數目!!!
執行緒數最好等於CPU核心數目!!!
執行緒數最好等於CPU核心數目!!!

重要的事情再說三遍。

舉個實際的栗子:
本人負責公司網路框架的架構設計和開發。在4核的 c3.xlarge 虛擬機器上,壓測框架時,2000 worker 執行緒的QPS(這裡理解為TPS問題也不大)遠遠低於4個worker執行緒的QPS!
4個worker執行緒,再加其他輔助執行緒,QPS最大每秒35萬。2000 worker執行緒,加同樣的輔助執行緒,QPS最大每秒15萬~~!

大部分的時間和其他系統資源都消耗在了執行緒的切換上~~!這就是為什麼單執行緒的程式在某些情況下比多執行緒的程式要快~~!(單執行緒模擬多執行緒的執行緒庫,不妨參考 state thread:
state-threads.sourceforge.net
。足夠簡單。) 

1、本系統處理的業務為多客戶端接入,一旦接入基本超過8個小時的長連線,但是登陸以後客戶端基本不怎麼活動,只有客戶端觸發相關設定事件才會產生活躍通訊。
6、系統開發使用TCP協議。
目前開的框架,TCP長連結,最大壓測連結108萬,總 QPS 6萬。
伺服器也是c3.xlarge。開了18臺機器做客戶端壓,每臺機器6萬連結(記得要修改 /proc/sys/net/ipv4/ip_local_port_range,不然一臺機器出不了這麼多連結)。

4、客戶端接入時間隨機,系統執行初期不會存在同一時間成千上萬使用者登陸的情況,但是使用者一旦接入伺服器就會長時間不會斷開。
壓測,每批次新加6萬連結。

5、能否使用epoll技術跟多執行緒技術配合開發?HOW?
Linux上,必須的!!!

3、QQ、SKYPE等的多客戶端登陸軟體,伺服器一般是如何設計開發的?
沒有一般,都是根據具體需求實際定製!!!
沒有一般,都是根據具體需求實際定製!!!
沒有一般,都是根據具體需求實際定製!!!

但分散式、去中心化、無狀態化、一致性雜湊、……,都是必須的~~~!
但分散式、去中心化、無狀態化、一致性雜湊、……,都是必須的~~~!
但分散式、去中心化、無狀態化、一致性雜湊、……,都是必須的~~~!

(說了好幾個三遍,累死了~~~喝點水~~)
不妨上網搜搜,將網路架構,伺服器架構的演化。中小型公司按那些套路來,基本都能搞定。圖太多,說起來太羅嗦。都是重複勞動,我就不寫了,請自己搜。

你問大公司?請參考第一句話:沒有一般,都是根據具體需求實際定製!!!
補充一點:網上搜的,都會對memcached、redis 等有很大的依賴。但我上家公司,也用,很重要,但只是給PHP端用。後端服務叢集全用專用快取~!!
專用快取~~!含邏輯~~!自己開發~~!
專用快取~~!含邏輯~~!自己開發~~!
專用快取~~!含邏輯~~!自己開發~~!
又說三遍。
撐住1.6億註冊使用者。

7、希望大家能給個詳細開發框架。
框架?是參考架構設計吧?

框架有很多,比如ICE,Facebook Thrift、Apache Thrift 等~~
注意,後兩個thrift不完全相同~~!!!

然後怎麼做:
沒有固定的套路!!!只有要注意的要點!!!
沒有固定的套路!!!只有要注意的要點!!!
沒有固定的套路!!!只有要注意的要點!!!

又是三遍。

要點:
儘量少的執行緒切換
儘量少的共享衝突
儘量無鎖
工作中的執行緒數儘量等於CPU核心數
儘量沒有等待時間片的執行緒
邏輯儘量簡化,避免不必要的封裝和轉發
工程不是學術,OOP要給簡單易用高效能好維護讓道~~!
(就是ICE概念多,太複雜,上家公司才開發了自己的框架。就是因為Facebook Thrift 太羅嗦,一個非同步都要繞好幾道彎,連結還和CPU核心繫結(如果就一個連結,10萬QPS,你會發現就一個核忙得要死,其他核心都在吃乾飯~),現在公司才決定自己開發網路框架。)
EPOLL:Edge Trigger、OneShot!!!
不要在epoll_wait()執行緒中用太長時間處理非epoll_wait()的事情。
能用atomic的就不要用mutex(這是C++11的事了)

上面就不三遍了,太多太囉嗦~~~

~~~~~~~~~~~~~ 7月3日追加 ~~~~~~~~~~~~~~

感謝 Irons Du曾凌恆每天不吃冰淇淋 的評論,涉及到一些昨天忘了的事情。
PS:今次不三遍了~~:)

追加要點:

A. 資料庫
資料庫一定要分佈。
如果有好的資料路由中間層服務,或者好的叢集管理器,或者好的Sharding服務,是MongoDB還是MySQL完全不重要~~~!
如果使用MongoDB,需要注意查詢 API 的where處理(自定義Javascript查詢條件)。C API的 where 處理非常非常低效(至少去年還是這樣。今年因專案的關係,沒有跟進)
資料庫一定要分庫分表。
分表強烈建議使用Hash分表,儘量避免按區段分表。
Hash分表設計好了,要擴容也非常容易。區段分表貌似擴容很容易,但時間長了,你的熱點資料分佈就極其不均勻了。
分庫分表,儘量非同步併發查詢(靠你的資料路由中介軟體了。當前兩家公司都是自己開發的,外面的吹得太凶,不實用。)
除支付業務外,嚴格禁止聯合查詢、複合查詢、事務操作!!!!
(支付一會單說)
分庫分表,表都不在一臺機器上了,聯合查詢、複合查詢、事務操作必然失敗~~~!
聯合查詢、複合查詢、事務相關的操作請由中間層服務配合完成!!!
PS:MySQL等,聯合查詢、複合查詢、事務操作,效率極低~~極低~~~!!!還會因為鎖表時間過長而阻塞其他查詢~~!!
支付的邏輯設計並分解好了,可以不用事務完成。要用事務,請確定相關的表均部署在同一臺數據庫例項上!!!

B. 去中心化、無狀態:
高彈性架構這是必須的。
儘量將狀態剝離成一個單獨的狀態服務(也是分散式叢集),其他業務邏輯全部變成無狀態的。狀態資訊請通過狀態服務處理。
無狀態的一般去中心化都很簡單。無外乎一致性雜湊、隨機、輪轉等等。
去中心化也是確保無單點故障!!!
如果非要有中心,請儘量選折以下兩個方案:
1. 中心如果很簡單,請確保在崩潰/殺死後,1秒鐘內能立刻復活啟動~~~
2. 中心改為管理叢集,自動選舉主核心。當原主核心失效後,新的核心自動接管當前叢集網路。

C. 協議:
不要使用XML!!!這都不想說了,讓我看到就是千萬只神獸在胸中蹦騰~~!!!
如果文字,請使用JSON。如果二進位制,請使用JSON對應的二進位制化協議。BSON嘛~~持保留態度。
如果需要協議的灰度升級,如果在協議灰度升級時不想實現兩套不同版本的介面,請遠離使用IDL的協議/框架!!!
這也是這兩家公司棄用 ICE和Facebook Thrift 的原因之一。

最後,如果你是初入行者,不妨多看看前面其他大拿推薦的資料,看看Reactor模式,看看Proactor。多看看其他框架,服務叢集的設計。
但是!!
當你成長後,一切模式、設計,都是扯淡~~!
模式是死的,需求是變動的,人和思維是活的!
只有根據實際需求,具體設計!具體定製!!!
(還記得無字真經嗎~~)

(貌似扯遠了,已經不是伺服器高併發了,而是高併發後端系統叢集了。。。-_-! )