• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-4  評論-40  文章-117  trackbacks-0



            摘要:在對I/O 完成端口進行底層封裝的基礎上,提出一種具有高性能的、可擴展性的通用網絡通信模塊設計方案。該方案采用多種系
            統性能優化技術,如線程池、對象池和環形緩存區等。該模塊在Win32 平臺上用C++開發完成,經過嚴格的壓力和性能測試后,實驗結果
            表明該模塊能夠支持海量并發連接,具有較高的數據吞吐量,在實際項目應用中也取得了良好的表現。
            關鍵詞:完成端口;服務器;多線程;線程池;對象池;緩存區
            Design Method of Underlying Module of Network Communication
            for High Performance Server
            WANGWen-wu1,2, ZHAOWei-dong1,2,WANG Zhi-cheng1,2, CHEN Yue1,2, HAN Xia-lin1,2
            (1. State Education Commission Engineering Center for Enterprise Digital Technology, Shanghai 200092;
            2. Research Center of CAD, Tongji University, Shanghai 201804)
            【Abstract】On the base of underlying encapsulation for I/O Completion Port(IOCP), this paper presents a design solution with high performance
            and scalable module of generic network communication, which emploies a variety of optimization techniques of system performance, such as thread
            pool, object pool and ring buffer. The module is developed in C++ programming language on Win32 platform. Experimental results show that the
            module can support massive concurrent connections, and has higher data throughput based on severe pressure and performance tests. The proposed
            solution has also got a good performance in the actual project application.
            【Key words】completion port; server; multi-threading; thread pool; object pool; ring buffer

            計算機工程

            Computer Engineering

            第35 卷第3 期
            Vol.35 No.3
            2009 年2 月
            February 2009

            1 概述
            要設計與開發出一款高性能的服務器(如網游服務器、
            Web 服務器和代理服務器等),一般都采用高效率的網絡I/O
            模型[1]。Linux 平臺上經常會采用epoll 模型,而在Win32 平
            臺上完成端口(以下簡稱IOCP)模型[2]是設計與開發高性能
            的、具有可伸縮性的服務器的最佳選擇,它可以支持海量并
            發客戶端請求。多線程編程是服務器端開發常用技術,多線
            程必然涉及線程間的通信與同步。如果使用不當,也會影響
            到系統的性能,必須謹慎設計才能保證系統良好運行。減少
            數據拷貝以及小對象頻繁創建與銷毀是一種很重要的提高系
            統性能手段,可通過設計內存池或對象池加以解決。這幾個
            問題的提出,說明實際的高性能服務器研發比較復雜,尤其
            是采用高效I/O 模型來架構服務器時,更是增加了開發的難
            度,原因是這些模型的機制比較復雜。
            底層網絡通信模塊是服務器應用程序的核心模塊,也是
            高性能服務器的最基礎模塊之一。它主要的功能是接收海量
            并發連接、接收網絡數據包、暫存和發送應用邏輯層的邏輯
            數據包,所以,它也是上次應用邏輯和底層網絡之間通信的
            媒介。
            2 IOCP 機制
            要實現一個并發的網絡服務器,比較簡單的模型是:每
            當一個請求到達就創建一個新線程,然后在新線程中為請求
            服務。這種模型減輕了實際開發的復雜度,在并發連接較少
            的情況下可以考慮使用,然而在高并發需求下并不適用。高
            并發環境中,創建和銷毀大量線程所花費的時間和消耗的系
            統資源是巨大的,而且會加重線程調度的負擔,同時線程上
            下文切換(context switch)也會浪費許多寶貴的CPU 時間。
            為了提高系統性能,首先必須有足夠的可運行線程來充
            分利用CPU 資源,但線程的數量不能太多。事實上,具體工
            作線程的數量和并發連接數量不是直接相關聯的。在Win32
            平臺下開發高效的服務器端應用程序,最理想的模型是IOCP
            模型,該模型解決了一系列系統性能瓶頸問題。
            IOCP 提供了最好的可伸縮性,而且其執行效率比較高,
            采用這種網絡模型可能會加大開發的復雜度, 但卻是
            Windows 平臺上唯一適用于開發高負載服務器的技術。
            IOCPWindows 系統的一種內核對象[3],也是Win32 下最復雜
            的一種I/O 模型,它通過一定數量的工作線程對重疊I/O 請
            求進行處理,以便為已經完成的I/O 請求提供服務,相對其
            他I/O 模型,它可以管理任意數量套接字句柄。它主要由等
            待線程隊列和I/O 完成隊列2 個部分組成。一個完成端口對
            象可以和多個套接字句柄相關聯,當針對某個套接字句柄發
            起的異步I/O 操作完成時,系統向該完成端口的I/O 完成隊
            列加入一個I/O 完成包。于此同時, 工作線程調用
            GetQueuedCompletionStatus(以下簡稱GQCS)時,如果I/O 完
            基金項目:廣東省教育部產學研結合基金資助項目“基于RFID 技
            術石化產品計量監控管理系統應用研究與開發”(2007A090302094)
            作者簡介:王文武(1983-),男,碩士研究生,主研方向:CAD,
            企業信息化;趙衛東,研究員、博士生導師;王志成,博士;陳悅、
            韓下林,碩士研究生
            收稿日期:2008-11-30 E-mail:jerry.wenwu@gmail.com
            —104—
            成隊列中有完成包,當前調用就會返回,取得數據進行后續
            的處理。
            成功創建一個完成端口后,便可開始將套接字句柄與對
            象關聯到一起。但在關聯套接字之前,首先必須創建一個或
            多個工作者線程為完成端口提供服務。
            3 模塊設計方案
            3.1 架構設計
            在充分考慮服務器性能和擴展性的基礎上,本文提出了
            基于三層結構的系統設計方案,該模塊的架構如圖1 所示。
            #OnConnectionEstablished() : void
            #OnReadCompleted() : void
            #OnWriteCompleted() : void
            CIocpServer
            #HandleRecvMessage() : void
            CTestServer
            #OnConnectionEstablished() : void
            #OnReadCompleted() : void
            #OnWriteCompleted() : void
            #HandleRecvMessage() : void
            CUserServer
            圖1 模塊設計架構
            圖1 看上去并不復雜,但卻是一個兼顧可擴展性和高性
            能的架構,在實際項目應用中也取得了很好的表現,下面是
            對圖1 主要類的功能分析。
            CIocpServer 類是完成端口服務器基本通信類,它使用
            Windows 平臺特有的IOCP 機制,對網絡通信模型進行底層
            封裝。提供了基本的服務器端網絡通信功能,這些功能主要
            有開啟服務器、關閉服務器、管理客戶端連接列表、管理未
            決的接受請求列表、發出異步操作等。同時通過多態機制向
            它的派生類提供以下基本擴展接口:
            (1)新連接確立的處理接口。
            (2)客戶端斷開連接時的處理接口。
            (3)連接出現錯誤時的處理接口。
            (4)從客戶端接收完數據后的處理接口。
            (5)向客戶端發送完數據后的處理接口。
            (6)拼包處理接口。
            CUserServer 類繼承CIocpServer,在CIocpServer 的基礎
            上,CUserServer 加入了一些服務器邏輯處理功能,并且封裝
            了3 類數據隊列和3 類處理線程,分別如下:
            (1)接收數據包隊列及接收線程:接收隊列用于存放接收
            到的數據包,此數據包還沒有進行邏輯意義上的拼包,接收
            線程從此隊列中取出數據包,并將其拼裝成邏輯意義上完整
            的數據包加入到邏輯數據包隊列中。
            (2)邏輯數據包隊列及邏輯處理線程:邏輯隊列用于存放
            已經拼包成了邏輯意義上的數據包,邏輯處理線程對此類數
            據包進行邏輯解析,這里就是服務器的主要邏輯部分,有的
            數據包在處理完成后,可能是需要向客戶端返回處理結果,
            此時就需要邏輯線程將處理完成的數據包放入發送數據包隊
            列中。
            (3)發送數據包隊列及發送線程:發送隊列存放待發送的
            數據包,發送線程根據數據包里的客戶端套接字發送給特定
            客戶端。
            CTestServer 類是一個測試類, 主要用于演示如何在
            CUserServer 的基礎上派生一個真正的應用服務器,并用于說
            明它需要重載實現CUserServer 的哪些重要虛函數。
            3.2 資源管理
            用IOCP 開發服務器時,當I/O 發生錯誤時需要有效地
            釋放與套接字相關的緩存區,如果對同一緩存區釋放多次,
            就會導致內存釋放的錯誤。當投遞的異步I/O 請求返回了非
            WSA_IO_PENDING 錯誤時,要對此錯誤進行處理,通常執
            行2 步操作:釋放此次操作使用的緩沖區數據;關閉當前操
            作所使用的套接字句柄。同時GQCS 調用會返回FALSE,也
            要做上面2 步相同的操作,這樣就可能產生對同一緩存區進
            行重復釋放的錯誤。解決的辦法可以有2 種:
            (1)通過引用計數機制控制緩存區釋放;
            (2)使緩存區釋放操作線性化。
            該系統的設計采用了第(2)種解決方案,所謂的釋放操作
            線性化是指把可能引起2 次釋放同一緩存區的操作合并為一
            次釋放。如果在執行異步I/O 操作過程中發生了非WSA_ IO_
            PENDING 錯誤,可以讓GQCS 返回時得知這個錯誤和發生
            錯誤時的緩存區指針,而不對該錯誤進行處理。通知的方式
            是,使用PostQueuedCompletionStatus(以下簡稱Post)函數拋
            出一個特殊標志的消息,這個特殊標志可以通過GQCS 函數
            的第2 個參數,即傳送字節數來表示,可以選擇任何一個不
            可能出現的值,比如一個負數。當然,如果通過單句柄數據
            或單I/O 數據來傳遞也是可以的。而發生錯誤時的緩沖區指
            針,必須要通過單句柄數據或單I/O 數據來傳遞。
            把釋放操作全放在GQCS 函數里以后,對釋放操作的處
            理就比較統一了。當然,為了實現真正的線性化和原子化,
            在釋放操作的執行邏輯上需要對釋放代碼加鎖以實現線程互
            斥(多線程情況下)。
            3.3 包的亂序解決方案
            如果在同一個套接字上一次提交多個異步I/O 請求,肯
            定會按照它們提交的次序完成,但在多線程環境下,完成包
            處理次序可能和提交次序不一致。該問題的一個簡單的解決
            方法是一次只投遞一個異步I/O 請求,當工作線程處理完該
            請求的完成數據包后,再投遞下一個異步I/O 請求。但這樣
            做會降低服務器的處理性能。為了保證完成包處理次序和提
            交次序相一致,可以為每個連接上投遞的請求都分配一個序
            號,單句柄數據中記錄當前需要讀取的單I/O 數據的序號,
            如果工作線程獲得的單I/O 數據的序號與單句柄數據中記錄
            的序號一致的話,就處理該數據。如果不相等,則把這個單
            I/O 數據保存到該連接的pOutOfOrderReads 列表中。
            4 性能優化
            在網絡服務器的開發過程中,池(Pool)技術已經被廣泛應
            用。使用池技術在一定層度上可以明顯優化服務器應用程序
            的性能,提高程序執行效率和降低系統資源開銷。這里所說
            的池是一種廣義上的池,比如數據庫連接池、線程池、內存
            池、對象池等。其中,對象池可以看成保存對象的容器,在
            進程初始化時創建一定數量的對象,需要時直接從池中取出
            一個空閑對象,用完后并不直接釋放掉對象,而是再放到對
            象池中以方便下一次對象請求可以直接復用。其他幾種池的
            設計思想也是如此,池技術的優勢是,可以消除對象創建所
            —105—
            帶來的延遲,從而提高系統的性能。
            4.1 線程池
            線程池[4]是提高服務器程序性能的一種很好技術,在
            Win32 平臺下開發的網絡服務器程序使用的線程池可分為兩
            類:一類是由完成端口對象負責維護的工作線程池,主要負
            責網絡層相關處理(比如投遞異步讀或寫操作等);另一類是
            負責邏輯處理的線程池,它是專門提供給應用層來使用的。
            本文提出了一種邏輯線程池的設計方案,線程池框架結構主
            要分為以下幾個部分:
            (1)線程池管理器:用于創建并管理線程,往任務隊列添
            加數據包等,并可以動態增加工作線程。
            (2)工作線程:線程池中的線程,執行實際的邏輯處理。
            (3)任務接口:每個任務必須實現的接口,以供工作線程
            調度任務使用。
            (4)任務隊列:提供一種緩存機制,用于存放從網絡層接
            收的數據包。
            該通信模塊使用了上述線程池的設計方案,從測試結果
            來看,當并發連接數很大時,線程池對服務器的性能改善是
            顯著的。
            該設計方案有個很好的特性,就是可以創建工作線程數
            量固定的線程池,也可以創建動態線程池。如果有大量的客
            戶要求服務器為其服務,但由于線程池的工作線程是有限的
            話,服務器只能為部分客戶端服務,客戶端提交的任務只能
            在任務隊列中等待處理。動態改變的工作線程數目的線程池,
            可以以適應突發性的請求。一旦請求變少了將逐步減少線程
            池中工作線程的數目。當然線程增加可以采用一種超前方式,
            即批量增加一批工作線程,而不是來一個請求才建立創建一
            個線程。批量創建是更加有效的方式,而且該方案還限制了
            線程池中工作線程數目的上限和下限,確保線程池技術能提
            高系統整體性能。
            4.2 對象池
            對象池[5-6]是針對特定應用程序而設計的內存管理方式,
            在某種場合下內存的分配和釋放性能會大大提升。默認的內
            存管理函數(new/delete 或malloc/free)有其不足之處,如果應
            用程序頻繁地在堆上分配和釋放內存,那么就會導致性能損
            失,并且會使系統中出現大量的內存碎片,降低內存的利
            用率。
            所謂對象池就是應用程序可以通過系統的內存分配調用
            預先一次性申請適當大小的內存塊,然后可以根據特定對象
            的大小,把該塊內存分割成一個個大小相同的對象。如果對
            象池中沒有空閑對象使用時,可以再向系統申請同樣大小的
            內存塊。如果對象使用完畢后直接放到對象池中,這種內存
            管理策略能有效地提升程序性能。
            4.2.1 對象池的應用
            當服務器接受一個客戶端請求后,會創建成功返回一個
            客戶端套接字句柄。如果出現大量并發客戶端連接請求時,
            就會出現頻繁地分配和釋放對象的情況,這個過程可能會消
            耗大量的系統資源,有損系統性能。WinSock2 還提供一個接
            受擴展函數AcceptEx,它允許在接受連接之前就事先創建一
            個套接字句柄,使之與接受連接相關聯。在調用AcceptEx 時,
            可以直接把該句柄作為參數傳遞給AcceptEx。有了這個保證,
            可以通過采用對象池技術來提升系統性能,可以在接受連接
            之前就創建一定數量的套接字句柄,隨著新連接請求的到來
            將句柄分配出去,當客戶端斷開連接后,把相應句柄重新放
            入套接字對象池中。
            另外需要用到對象池的地方是,在每一次投遞WSASend
            或WSARecv 操作時,都要傳進一個重疊結構體參數。可以
            提前創建一個重疊結構體對象池,當發起異步I/O 操作時,
            先從池中取一個結構體對象,用完之后并不直接銷毀,而是
            再放回對象池以便以后重復利用。創建的結構體數量取決于
            完成端口的處理效率,如果處理效率比較高,則數量可能就
            少些,反之,就需要多創建些對象。
            該系統所設計的對象池是線程安全的,可以被多個線程
            共享,在獲得和釋放對象時都需要加鎖,從而保證線程間互
            斥訪問對象池。
            4.2.2 對象池的優點
            與系統直接管理內存相比,對象池在系統性能優化方面
            主要有如下優點:
            (1)針對特殊情況,例如需要頻繁分配和釋放固定大小的
            對象時,不需要復雜的分配算法和線程同步。也不需要維護
            內存空閑表的額外開銷,從而獲得較好的性能。
            (2)由于直接分配一定數量的連續內存空間作為內存塊,
            因此一定程度上提高了程序局部性能,提升了應用程序整體
            性能。
            (3)比較容易控制頁邊界對齊和內存字節對齊,基本沒有
            內存碎片問題。
            4.3 環形緩存區
            基于TCP 協議的服務器應用程序,拼包處理過程必不可
            少。由于要從接收緩存中分解出一個個邏輯數據包,因此一
            般都要涉及內存拷貝操作,過多的內存拷貝必然降低系統
            性能。
            當然,就邏輯數據包的拼裝問題而言,也完全可以避免
            數據拷貝操作,方法是使用環形緩沖區。本文所說的環形緩
            沖區是具體這種特征的接收緩沖區,在服務器的接收事件里,
            當處理完了一次從緩沖區里取走所有完整邏輯包的操作后,
            可能會在緩沖區里遺留下來新的不完整數據包。使用了環形
            緩沖區后,就可以不將數據重新復制到緩沖區首部以等待后
            續數據的拼裝,可以根據記錄下的隊列首部和隊列尾部指針
            進行下一次的拼包操作。
            環形緩沖區在IOCP 的處理中,甚至在其他需要高效率
            處理數據收發的網絡模型的接收事件處理中,是一種被廣泛
            采用的優化方案。
            5 實驗結果
            為了證明論文中系統優化的方法能獲得預期的性能優
            勢,對內存池和系統整體性能進行了實驗測試。測試硬件是:
            CPU:AMD Turion 64,內存:1 024 MB,網絡:100 MB 局
            域網,操作系統:Windows XP Professional SP2。
            測試1:對象池性能測試
            由表1 可以看出,由于使用對象池來分配小對象的內存,
            速度提高了52.48%,使得內存分配獲得了顯著的效率提升。
            速度提高的原因可以歸結為以下幾點:
            (1)除了偶爾的內存申請和銷毀會導致從進程堆中分配
            和銷毀內存塊外,絕大多數的內存申請和銷毀都由對象池在
            已經申請到的內存塊中進行,而沒有直接與進程打交道,而
            直接與進程打交道是很耗時的操作。
            (2)這是在單線程環境的對象池,在多線程環境下,由于
            加鎖,因此速度提高的會少些。
            (下轉第114 頁)
            posted on 2009-03-10 19:51 李陽 閱讀(2577) 評論(1)  編輯 收藏 引用 所屬分類: 游戲開發

            評論:
            # re: 高性能服務器底層網絡通信模塊的設計方法 2012-04-04 15:32 | xmx1108
            很有幫助的  回復  更多評論
              
            亚洲国产精品无码成人片久久| 精品国产婷婷久久久| 人妻无码αv中文字幕久久| 久久久免费精品re6| 88久久精品无码一区二区毛片| 国产一区二区精品久久凹凸| 久久久久亚洲AV成人网人人网站 | 久久99国产精品成人欧美| 亚洲精品综合久久| 国产精品久久久久国产A级| 久久亚洲欧洲国产综合| 久久精品国产只有精品2020| 久久久无码精品亚洲日韩京东传媒 | 亚洲av日韩精品久久久久久a| 免费观看成人久久网免费观看| 麻豆久久久9性大片| 国产69精品久久久久99| 国产精品一久久香蕉国产线看观看| 亚洲精品tv久久久久| 亚洲国产成人久久综合碰碰动漫3d | 久久精品国产99国产精品导航| 88久久精品无码一区二区毛片| 青青草原精品99久久精品66| 国产精品久久新婚兰兰| 欧美亚洲日本久久精品| 久久久久国产精品嫩草影院| 色综合久久久久| 亚洲欧美精品伊人久久| 久久国产亚洲精品麻豆| 91精品国产高清91久久久久久| 亚洲乱码中文字幕久久孕妇黑人| 日批日出水久久亚洲精品tv| 久久天天躁狠狠躁夜夜av浪潮| 精品水蜜桃久久久久久久| 99久久国产主播综合精品| 麻豆精品久久久一区二区| 久久综合欧美成人| 国产综合精品久久亚洲| 日韩精品无码久久一区二区三| 国产精品综合久久第一页| 久久久久亚洲AV成人网|