成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Linux高性能服務(wù)器處理框架12步走

終于開(kāi)始學(xué)習(xí)epoll了,雖然不明白的地方還是很多,但從理論到實(shí)踐,相信自己動(dòng)手去寫(xiě)一個(gè)具體的框架后,一切會(huì)清晰很多。

Linux高性能服務(wù)器處理框架12步走

成都創(chuàng)新互聯(lián)公司"三網(wǎng)合一"的企業(yè)建站思路。企業(yè)可建設(shè)擁有電腦版、微信版、手機(jī)版的企業(yè)網(wǎng)站。實(shí)現(xiàn)跨屏營(yíng)銷(xiāo),產(chǎn)品發(fā)布一步更新,電腦網(wǎng)絡(luò)+移動(dòng)網(wǎng)絡(luò)一網(wǎng)打盡,滿足企業(yè)的營(yíng)銷(xiāo)需求!成都創(chuàng)新互聯(lián)公司具備承接各種類型的成都做網(wǎng)站、網(wǎng)站制作項(xiàng)目的能力。經(jīng)過(guò)十年的努力的開(kāi)拓,為不同行業(yè)的企事業(yè)單位提供了優(yōu)質(zhì)的服務(wù),并獲得了客戶的一致好評(píng)。

1、首先需要一個(gè)內(nèi)存池,目的在于:

·減少頻繁的分配和釋放,提高性能的同時(shí),還能避免內(nèi)存碎片的問(wèn)題;

·能夠存儲(chǔ)變長(zhǎng)的數(shù)據(jù),不要很傻瓜地只能預(yù)分配一個(gè)最大長(zhǎng)度;

·基于SLAB算法實(shí)現(xiàn)內(nèi)存池是一個(gè)好的思路:分配不同大小的多個(gè)塊,請(qǐng)求時(shí)返回大于請(qǐng)求長(zhǎng)度的最小塊即可,對(duì)于容器而言,處理固定塊的分配和回收,相當(dāng)容易實(shí)現(xiàn)。當(dāng)然,還要記得需要設(shè)計(jì)成線程安全的,自旋鎖比較好,使用讀寫(xiě)自旋鎖就更好了。

·分配內(nèi)容的增長(zhǎng)管理是一個(gè)問(wèn)題,比如第一次需要1KB空間,隨著數(shù)據(jù)源源不斷的寫(xiě)入,第二次就需要4KB空間了。擴(kuò)充空間容易實(shí)現(xiàn),可是擴(kuò)充的時(shí)候必然 涉及數(shù)據(jù)拷貝。甚至,擴(kuò)充的需求很大,上百兆的數(shù)據(jù),這樣就不好辦了。暫時(shí)沒(méi)更好的想法,可以像STL一樣,指數(shù)級(jí)增長(zhǎng)的分配策略,拷貝數(shù)據(jù)雖不可避免, 但是起碼重分配的幾率越來(lái)越小了。

·上面提到的,如果是上百兆的數(shù)據(jù)擴(kuò)展需要,采用內(nèi)存映射文件來(lái)管理是一個(gè)好的辦法:映射文件后,雖然占了很大的虛擬內(nèi)存,但是物理內(nèi)存僅在寫(xiě)入的時(shí)候才會(huì)被分配,加上madvice()來(lái)加上順序?qū)懙膬?yōu)化建議后,物理內(nèi)存的消耗也會(huì)變小。

·用string或者vector去管理內(nèi)存并不明智,雖然很簡(jiǎn)單,但服務(wù)器軟件開(kāi)發(fā)中不適合使用STL,特別是對(duì)穩(wěn)定性和性能要求很高的情況下。

2、第二個(gè)需要考慮的是對(duì)象池,與內(nèi)存池類似:

·減少對(duì)象的分配和釋放。其實(shí)C++對(duì)象也就是struct,把構(gòu)造和析構(gòu)脫離出來(lái)手動(dòng)初始化和清理,保持對(duì)同一個(gè)緩沖區(qū)的循環(huán)利用,也就不難了。

·可以設(shè)計(jì)為一個(gè)對(duì)象池只能存放一種對(duì)象,則對(duì)象池的實(shí)現(xiàn)實(shí)際就是固定內(nèi)存塊的池化管理,非常簡(jiǎn)單。畢竟,對(duì)象的數(shù)量非常有限。

3、第三個(gè)需要的是隊(duì)列:

·如果可以預(yù)料到極限的處理能力,采用固定大小的環(huán)形隊(duì)列來(lái)作為緩沖區(qū)是比較不錯(cuò)的。一個(gè)生產(chǎn)者一個(gè)消費(fèi)者是常見(jiàn)的應(yīng)用場(chǎng)景,環(huán)形隊(duì)列有其經(jīng)典的“鎖無(wú)關(guān)”算法,在一個(gè)線程讀一個(gè)線程寫(xiě)的場(chǎng)景下,實(shí)現(xiàn)簡(jiǎn)單,性能還高,還不涉及資源的分配和釋放。好啊,實(shí)在是好!

·涉及多個(gè)生產(chǎn)者消費(fèi)者的時(shí)候,tbb::concurent_queue是不錯(cuò)的選擇,線程安全,并發(fā)性也好,就是不知道資源的分配釋放是否也管理得足夠好。

4、第四個(gè)需要的是映射表,或者說(shuō)hash表:

·因?yàn)閑poll是事件觸發(fā)的,而一系列的流程可能是分散在多個(gè)事件中的,因此,必須保留下中間狀態(tài),使得下一個(gè)事件觸發(fā)的時(shí)候,能夠接著上次處理的位置繼續(xù)處理。要簡(jiǎn)單的話,STL的hash_map還行,不過(guò)得自己處理鎖的問(wèn)題,多線程環(huán)境下使用起來(lái)很麻煩。

·多線程環(huán)境下的hash表,最好的還是tbb::concurent_hash_map。

5、核心的線程是事件線程:

·事件線程是調(diào)用epoll_wait()等待事件的線程。例子代碼里面,一個(gè)線程干了所有的事情,而需要開(kāi)發(fā)一個(gè)高性能的服務(wù)器的時(shí)候,事件線程應(yīng)該專注于事件本身的處理,將觸發(fā)事件的socket句柄放到對(duì)應(yīng)的處理隊(duì)列中去,由具體的處理線程負(fù)責(zé)具體的工作。

6、accept()單獨(dú)一個(gè)線程:

·服務(wù)端的socket句柄(就是調(diào)用bind()和listen()的這個(gè))最好在單獨(dú)的一個(gè)線程里面做accept(),阻塞還是非阻塞都無(wú)所謂,相比整個(gè)服務(wù)器的通訊,用戶接入的動(dòng)作只是很小一部分。而且,accept()不放在事件線程的循環(huán)里面,減少了判斷。

7、接收線程單獨(dú)一個(gè):

·接收線程從發(fā)生EPOLLIN事件的隊(duì)列中取出socket句柄,然后在這個(gè)句柄上調(diào)用recv接收數(shù)據(jù),直到緩沖區(qū)沒(méi)有數(shù)據(jù)為止。接收到的數(shù)據(jù)寫(xiě)入以socket為鍵的hash表中,hash表中有一個(gè)自增長(zhǎng)的緩沖區(qū),保存了客戶端發(fā)過(guò)來(lái)的數(shù)據(jù)。

·這樣的處理方式適合于客戶端發(fā)來(lái)的數(shù)據(jù)很小的應(yīng)用,比如HTTP服務(wù)器之類;假設(shè)是文件上傳的服務(wù)器,則接受線程會(huì)一直處理某個(gè)連接的海量數(shù)據(jù),其他客戶端的數(shù)據(jù)處理產(chǎn)生了饑餓。所以,如果是文件上傳服務(wù)器一類的場(chǎng)景,就不能這樣設(shè)計(jì)。

8、發(fā)送線程單獨(dú)一個(gè):

·發(fā)送線程從發(fā)送隊(duì)列獲取需要發(fā)送數(shù)據(jù)的SOCKET句柄,在這些句柄上調(diào)用send()將數(shù)據(jù)發(fā)到客戶端。隊(duì)列中指保存了SOCKET句柄,具體的信息 還需要通過(guò)socket句柄在hash表中查找,定位到具體的對(duì)象。如同上面所講,客戶端信息的對(duì)象不但有一個(gè)變長(zhǎng)的接收數(shù)據(jù)緩沖區(qū),還有一個(gè)變長(zhǎng)的發(fā)送 數(shù)據(jù)緩沖區(qū)。具體的工作線程發(fā)送數(shù)據(jù)的時(shí)候并不直接調(diào)用send()函數(shù),而是將數(shù)據(jù)寫(xiě)到發(fā)送數(shù)據(jù)緩沖區(qū),然后把SOCKET句柄放到發(fā)送線程隊(duì)列。

·SOCKET句柄放到發(fā)送線程隊(duì)列的另一種情況是:事件線程中發(fā)生了EPOLLOUT事件,說(shuō)明TCP的發(fā)送緩沖區(qū)又有了可用的空間,這個(gè)時(shí)候可以把SOCKET句柄放到發(fā)送線程隊(duì)列,一邊觸發(fā)send()的調(diào)用;

·需要注意的是:發(fā)送線程發(fā)送大量數(shù)據(jù)的時(shí)候,當(dāng)頻繁調(diào)用send()直到TCP的發(fā)送緩沖區(qū)滿后,便無(wú)法再發(fā)送了。這個(gè)時(shí)候如果循環(huán)等待,則其他用戶的 發(fā)送工作受到影響;如果不繼續(xù)發(fā)送,則EPOLL的ET模式可能不會(huì)再產(chǎn)生事件。解決這個(gè)問(wèn)題的辦法是在發(fā)送線程內(nèi)再建立隊(duì)列,或者在用戶信息對(duì)象上設(shè)置 標(biāo)志,等到線程空閑的時(shí)候,再去繼續(xù)發(fā)送這些未發(fā)送完成的數(shù)據(jù)。

9、需要一個(gè)定時(shí)器線程:

·一位將epoll使用的高手說(shuō)道:“單純靠epoll來(lái)管理描述符不泄露幾乎是不可能的。完全解決方案很簡(jiǎn)單,就是對(duì)每個(gè)fd設(shè)置超時(shí)時(shí)間,如果超過(guò)timeout的時(shí)間,這個(gè)fd沒(méi)有活躍過(guò),就close掉”。

·所以,定時(shí)器線程定期輪訓(xùn)整個(gè)hash表,檢查socket是否在規(guī)定的時(shí)間內(nèi)未活動(dòng)。未活動(dòng)的SOCKET認(rèn)為是超時(shí),然后服務(wù)器主動(dòng)關(guān)閉句柄,回收資源。

10、多個(gè)工作線程:

·工作線程由接收線程去觸發(fā):每次接收線程收到數(shù)據(jù)后,將有數(shù)據(jù)的SOCKET句柄放入一個(gè)工作隊(duì)列中;工作線程再?gòu)墓ぷ麝?duì)列獲取SOCKET句柄,查詢hash表,定位到用戶信息對(duì)象,處理業(yè)務(wù)邏輯。

·工作線程如果需要發(fā)送數(shù)據(jù),先把數(shù)據(jù)寫(xiě)入用戶信息對(duì)象的發(fā)送緩沖區(qū),然后把SOCKET句柄放到發(fā)送線程隊(duì)列中去。

·對(duì)于任務(wù)隊(duì)列,接收線程是生產(chǎn)者,多個(gè)工作線程是消費(fèi)者;對(duì)于發(fā)送線程隊(duì)列,多個(gè)工作線程是生產(chǎn)者,發(fā)送線程是消費(fèi)者。在這里需要注意鎖的問(wèn)題,如果采用tbb::concurrent_queue,會(huì)輕松很多。

11、僅僅只用scoket句柄作為hash表的鍵,并不夠:

·假設(shè)這樣一種情況:事件線程剛把某SOCKET因發(fā)生EPOLLIN事件放入了接收隊(duì)列,可是隨即客戶端異常斷開(kāi)了,事件線程又因?yàn)镋POLLERR事 件刪除了hash表中的這一項(xiàng)。假設(shè)接收隊(duì)列很長(zhǎng),發(fā)生異常的SOCKET還在隊(duì)列中,等到接收線程處理到這個(gè)SOCKET的時(shí)候,并不能通過(guò) SOCKET句柄索引到hash表中的對(duì)象。

·索引不到的情況也好處理,難點(diǎn)就在于,這個(gè)SOCKET句柄立即被另一個(gè)客戶端使用了,接入線程為這個(gè)SCOKET建立了hash表中的某個(gè)對(duì)象。此時(shí),句柄相同的兩個(gè)SOCKET,其實(shí)已經(jīng)是不同的兩個(gè)客戶端了。極端情況下,這種情況是可能發(fā)生的。

·解決的辦法是,使用socket fd + sequence為hash表的鍵,sequence由接入線程在每次accept()后將一個(gè)整型值累加而得到。這樣,就算SOCKET句柄被重用,也不會(huì)發(fā)生問(wèn)題了。

12、監(jiān)控,需要考慮:

·框架中最容易出問(wèn)題的是工作線程:工作線程的處理速度太慢,就會(huì)使得各個(gè)隊(duì)列暴漲,最終導(dǎo)致服務(wù)器崩潰。因此必須要限制每個(gè)隊(duì)列允許的最大大小,且需要監(jiān)視每個(gè)工作線程的處理時(shí)間,超過(guò)這個(gè)時(shí)間就應(yīng)該采用某個(gè)辦法結(jié)束掉工作線程。

文章題目:Linux高性能服務(wù)器處理框架12步走
當(dāng)前地址:http://jinyejixie.com/article8/jjisip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、ChatGPT、網(wǎng)站設(shè)計(jì)、網(wǎng)站收錄、電子商務(wù)、軟件開(kāi)發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁(yè)設(shè)計(jì)公司
马边| 瑞安市| 徐水县| 贺兰县| 桂东县| 红安县| 阿尔山市| 锦州市| 通海县| 望城县| 时尚| 北京市| 翼城县| 宜兴市| 团风县| 清远市| 清远市| 深圳市| 阳谷县| 信阳市| 泰宁县| 高邮市| 长治县| 隆林| 丘北县| 江安县| 安乡县| 金湖县| 通州区| 兖州市| 固镇县| 甘肃省| 沛县| 梁平县| 石楼县| 汶上县| 波密县| 准格尔旗| 西林县| 乐亭县| 大同县|