大型分布式C++框架《四:netio之请求包中转站 上》
本來(lái)一篇文章就該搞定的。結(jié)果要分上下篇了。主要是最近頸椎很不舒服。同時(shí)還在做秒殺的需求也挺忙的。 現(xiàn)在不能久坐。看代碼的時(shí)間變少了。然后還買了兩本治療頸椎的書。在學(xué)著,不過感覺沒啥用。突然心里好害怕。如果頸椎病越來(lái)越重。以后的路怎么走。
? ? ? ? ? ?現(xiàn)在上下班有跑步,然后坐一個(gè)小時(shí)就起來(lái)活動(dòng)活動(dòng)。然后在跟著同時(shí)們一起去打羽毛球吧。也快30的人了。現(xiàn)在發(fā)覺身體才是真的。其他都沒什么意思。兄弟們也得注意~~
廢話不多說(shuō)。下面介紹下netio。
? ? ? ? ? netio在系統(tǒng)中主要是一個(gè)分包的作用。netio本事沒有任何的業(yè)務(wù)處理。拿到包以后進(jìn)行簡(jiǎn)單的處理。再根據(jù)請(qǐng)求的命令字發(fā)送到對(duì)應(yīng)的業(yè)務(wù)處理進(jìn)程去。
?
?
一、多進(jìn)程下的socket epoll以及“驚群現(xiàn)象”
2.1 多進(jìn)程下是監(jiān)聽socket的方式
1)比如我們想創(chuàng)建三個(gè)進(jìn)程同時(shí)處理一個(gè)端口下到來(lái)的請(qǐng)求。
2)父進(jìn)程先創(chuàng)建socket。然后再listen。注意這個(gè)時(shí)候父進(jìn)程frok。 2個(gè)進(jìn)程出來(lái)。加上父進(jìn)程就是3個(gè)進(jìn)程 3)每個(gè)進(jìn)程單獨(dú)創(chuàng)建字節(jié)epoll_create和epoll_wait. 并把socket放到epoll_wait里以上是平臺(tái)多進(jìn)程下監(jiān)聽同一個(gè)端口的方式。我們下面探究下為什么要這么做 2.1.1、為什么要fork出來(lái)的子進(jìn)程來(lái)繼承父進(jìn)程的socket。而不是多個(gè)進(jìn)程綁定同一個(gè)端口? 首先如果一個(gè)端口正在被使用,無(wú)論是TIME_WAIT、CLOSE_WAIT、還是ESTABLISHED狀態(tài)。 這個(gè)端口都不能被復(fù)用,這里面自然也是包括不能被用來(lái)LISTEN(監(jiān)聽)。所以在三個(gè)進(jìn)程里分別listen和bind端口肯定會(huì)失敗的 2.1.2 、為什么不能使用SO_REUSEADDR來(lái)是多個(gè)進(jìn)程監(jiān)聽同一個(gè)端口? 首先我們來(lái)看下SO_REUSEADDR的用途 服務(wù)端重啟的時(shí)候會(huì)進(jìn)入到TIME_WAIT的狀態(tài)。這個(gè)時(shí)候我們?cè)赽ind的端口會(huì)失敗的。但是我們不可能等TIME_WAIT狀態(tài)過去在重啟服務(wù) 因?yàn)?strong>TIME_WAIT可能會(huì)在一分鐘以上。這個(gè)時(shí)候我們?cè)O(shè)置為SO_REUSEADDR就是使得端口處在TIME_WAIT時(shí)候,可以復(fù)用監(jiān)聽。 注意SO_REUSEADDR只是在TIME_WAIT 重啟服務(wù)的時(shí)候有用。如果你是多個(gè)進(jìn)程要bind同一個(gè)端口。且IP相同。那么即使你設(shè)置了SO_REUSEADDR也會(huì)失敗 因?yàn)镾O_REUSEADDR允許在同一端口上啟動(dòng)同一服務(wù)器的多個(gè)實(shí)例,只要每個(gè)實(shí)例捆綁一個(gè)不同的本地IP地址即可。對(duì)于TCP,我們根本不可能啟動(dòng)捆綁相同IP地址和相同端口號(hào)的多個(gè)服務(wù)器。 2.1.3、TIME_WAIT的作用。為什么要TIME_WAIT的?
因?yàn)門CP實(shí)現(xiàn)必須可靠地終止連接的兩個(gè)方向(全雙工關(guān)閉), 一方必須進(jìn)入 TIME_WAIT 狀態(tài),因?yàn)榭赡苊媾R重發(fā)最終ACK的情形。 否則的會(huì)發(fā)送RST 2.1.4、多進(jìn)行下實(shí)現(xiàn)監(jiān)聽同一個(gè)端口的原因 因?yàn)閯?chuàng)建子進(jìn)程的時(shí)候,復(fù)制了一份socket資源給子進(jìn)程。其實(shí)可以這么理解。其實(shí)只有父進(jìn)程一個(gè)socket綁定了端口。其他子進(jìn)程只是使用的是復(fù)制的socket資源 2.1.5、epoll放到fork之后會(huì)怎么樣?
netio起5個(gè)進(jìn)程 james 2356 1 0 08:22 pts/0 00:00:00 ./netio netio_config.xml james 2357 2356 0 08:22 pts/0 00:00:00 ./netio netio_config.xml james 2358 2356 0 08:22 pts/0 00:00:00 ./netio netio_config.xml james 2359 2356 0 08:22 pts/0 00:00:00 ./netio netio_config.xml james 2360 2356 0 08:22 pts/0 00:00:00 ./netio netio_config.xml 我們先做幾個(gè)實(shí)驗(yàn)然后再具體分析 a)實(shí)驗(yàn)一 正常請(qǐng)求。我們慢慢的按順序發(fā)送十個(gè)請(qǐng)求。每個(gè)請(qǐng)求都是新的請(qǐng)求。 我們看下netio處理的進(jìn)程pid ?發(fā)現(xiàn)每次都是2358 開始我以為會(huì)這五個(gè)請(qǐng)求來(lái)競(jìng)爭(zhēng)來(lái)取socket接收到的請(qǐng)求化。那么每次處理的請(qǐng)求的子進(jìn)程應(yīng)該不一樣才對(duì)。但是每次都是同一個(gè)請(qǐng)求 after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2358 b)實(shí)驗(yàn)二 我們先并發(fā)2個(gè)請(qǐng)求。看服務(wù)處理進(jìn)程pid還是2358 after epoll_wait pid:2358 after epoll_wait pid:2358
這個(gè)時(shí)候我們客戶端fork8個(gè)進(jìn)程并發(fā)請(qǐng)求服務(wù)。發(fā)現(xiàn)2357和2358開始交替處理
after epoll_wait pid:2358 after epoll_wait pid:2358 after epoll_wait pid:2357 after epoll_wait pid:2358 after epoll_wait pid:2357 after epoll_wait pid:2358 after epoll_wait pid:2357 after epoll_wait pid:2358 c)實(shí)驗(yàn)三 我們?cè)趀poll_wait后面.recv之前 ? ?加上sleep(100000) 然后發(fā)送一個(gè)請(qǐng)求。發(fā)現(xiàn)每個(gè)進(jìn)程被喚醒以后 但是因?yàn)閟leep阻塞了。 然后會(huì)接著喚醒別的進(jìn)程來(lái)處理。每次喚醒都會(huì)被阻塞。一直到5個(gè)進(jìn)程全部被阻塞 after epoll_wait pid:2358 after epoll_wait pid:2357 after epoll_wait pid:2359 after epoll_wait pid:2356 after epoll_wait pid:2360 d)實(shí)驗(yàn)四 我們?cè)趀poll_wait后面recv 后面 加上是sleep(100000) 然后發(fā)送一個(gè)請(qǐng)求。發(fā)現(xiàn)有一個(gè)進(jìn)程recv處理完以后。sleep住。其他進(jìn)程并沒有被喚醒。| 1 | after epoll_wait pid:2358 |
當(dāng)我們并發(fā)兩個(gè)請(qǐng)求的時(shí)候。發(fā)現(xiàn)喚醒了兩個(gè)進(jìn)程
after epoll_wait pid:2357 after epoll_wait pid:2359 四個(gè)實(shí)驗(yàn)已經(jīng)做完現(xiàn)在我們來(lái)具體分析下原因 1)實(shí)驗(yàn)一中為什么 ?每次只有一個(gè)進(jìn)程來(lái)處理。 首先我們?nèi)齻€(gè)進(jìn)程都epoll_wait同一個(gè)fd。按理來(lái)說(shuō)這個(gè)時(shí)候其實(shí)應(yīng)該喚醒三個(gè)進(jìn)程都來(lái)處理的。但是每次都只有一個(gè)進(jìn)程來(lái)處理。如果是進(jìn)程競(jìng)爭(zhēng)處理的話。別的子進(jìn)程應(yīng)該也有機(jī)會(huì)來(lái)處理的。但是沒有。這就是我們所謂的“驚群”現(xiàn)象。但是并沒有發(fā)生。 查了下資料發(fā)現(xiàn)。內(nèi)核采用的不是競(jìng)爭(zhēng)。而是分配策略。在有多個(gè)子進(jìn)程epoll_wait 同一個(gè)fd的時(shí)候。會(huì)選擇一個(gè)子進(jìn)程來(lái)處理這個(gè)消息。 并不會(huì)喚醒其他子進(jìn)程。 2)實(shí)驗(yàn)二中 并發(fā)增大的時(shí)候 為什么會(huì)開始有多個(gè)子進(jìn)程來(lái)處理。 其實(shí)這里做的很有意思。內(nèi)核輪流喚醒監(jiān)聽fd的子進(jìn)程。如果子進(jìn)程很快處理完。那么就一直讓這個(gè)子進(jìn)程來(lái)處理fd.但是如果子進(jìn)程處理不完。速度沒那么快。會(huì)接著喚醒別的子進(jìn)程來(lái)處理這個(gè)fd. 即fd事件到達(dá)的時(shí)候。內(nèi)核會(huì)先去看下A進(jìn)程是否繁忙。如果不繁忙 。則讓這個(gè)A進(jìn)程一直處理。如果發(fā)現(xiàn)A進(jìn)程繁忙中。會(huì)去查看進(jìn)程B是否繁忙。如果不繁忙則B處理 ?后面的子進(jìn)程以此類推 所以我們看到 并發(fā)請(qǐng)求增大的時(shí)候 ?開始有多個(gè)子進(jìn)程來(lái)處理了 3)實(shí)驗(yàn)三、5個(gè)進(jìn)程為什么都被喚醒了? 其實(shí)就是上面說(shuō)的。被sleep住了。我們認(rèn)為進(jìn)程就是繁忙狀態(tài)中。會(huì)依次通知其他進(jìn)程來(lái)處理。 4)實(shí)驗(yàn)四 ?為什么只有一個(gè)進(jìn)程被喚醒處理 我們?cè)趕leep放在recv之后。發(fā)現(xiàn)只有一個(gè)進(jìn)程被喚醒。 我們可以任務(wù)進(jìn)程已經(jīng)接受并處理了任務(wù)。所有不需要再通知其他進(jìn)程了 這里我們小結(jié)下: epoll放在fork之后這種方式不會(huì)引起驚群現(xiàn)象。 會(huì)輪詢選擇其中一個(gè)子進(jìn)程來(lái)處理。如果子進(jìn)程來(lái)不及處理。則會(huì)通知另外一個(gè)子進(jìn)程來(lái)處理。 但是以上結(jié)論是做實(shí)驗(yàn)和查資料得來(lái)的。并沒有看內(nèi)核源碼。所有如果有看過內(nèi)核源碼的同學(xué)。希望能指點(diǎn)下。 2.1.6、epoll放到fork之前會(huì)怎么樣? 把epoll放到fork 之前。當(dāng)發(fā)送一個(gè)請(qǐng)求的時(shí)候 ?發(fā)現(xiàn)也是只喚醒了一個(gè)進(jìn)程來(lái)處理。 這里其實(shí)跟epoll放到fork之后是一樣的。 ? 但這里有個(gè)很蛋痛的地方 。 我們系統(tǒng)用到了unix域來(lái)做消息通知。當(dāng)container處理完消息。會(huì)發(fā)送uinx域來(lái)通知neito來(lái)處理回包。 但是回包的時(shí)候。不知道為什么 ?5個(gè)進(jìn)程都被喚醒了來(lái)被處理。最后有三個(gè)進(jìn)程被主動(dòng)結(jié)束了。 ? 下面是我自己的理解 a) 首先 是進(jìn)程id為 6000 的netio處理的數(shù)據(jù)。 當(dāng)container回包實(shí)際數(shù)據(jù)只會(huì)通知 f000_6000的uinx域中 如下圖。有5個(gè)進(jìn)程。就有5個(gè)uinx域 b) 但是由于多進(jìn)程公用一個(gè)epoll。其他進(jìn)程也被喚醒了。然后判斷發(fā)現(xiàn)這個(gè)fd是uxin域的類型。 然后就會(huì)去不停的讀取自己對(duì)應(yīng)的unix域文件。 但是其實(shí)沒有消息的。container只回到了 f000_6000 中所以其他進(jìn)程一直recvfrom =-1 而且由于正在處理 f000_6000 的進(jìn)程不夠及時(shí)。這個(gè)消息沒處理。epoll的特性是會(huì)一直通知進(jìn)程來(lái)處理。所以其他進(jìn)程會(huì)一直讀自己的unix域。然后就一直recvfrom =-1 如下圖。沒貼全。除了進(jìn)程6000其他進(jìn)程打印了一堆這樣的信息 c) 最后我們讀進(jìn)程6000從的uinx域中讀到數(shù)據(jù)后。 其他進(jìn)程剛好這個(gè)時(shí)候拿到fd是被處理過的。這個(gè)時(shí)候再來(lái)處理這個(gè)fd就是未定義的。 而我們對(duì)未定義的fd會(huì)直接stop進(jìn)程。所以最后三個(gè)進(jìn)程被主動(dòng)關(guān)閉了 這里我們小結(jié)一下 因?yàn)闆]有看內(nèi)核代碼 所有對(duì)這種情況只有靠實(shí)驗(yàn)和猜了。。。。。跪求大神指導(dǎo) 1、首先針對(duì)TCP端口內(nèi)核應(yīng)該是做了特殊處理。所以epoll在fork前還是后。如果處理及時(shí)。應(yīng)該都是只有一個(gè)進(jìn)程被喚醒。來(lái)處理。處理不及時(shí)會(huì)依次喚醒別的進(jìn)程。并不會(huì)造成驚群現(xiàn)象(就是那種臨界資源多個(gè)進(jìn)程來(lái)?yè)屵@個(gè)包。最后只有一個(gè)進(jìn)程能搶到包。但是做實(shí)驗(yàn)發(fā)現(xiàn)好像并不是競(jìng)爭(zhēng)的關(guān)系) 2、但是針對(duì)unix域的fd。公用一個(gè)epoll沒有特殊處理。就會(huì)造成驚群現(xiàn)象。并且多個(gè)進(jìn)程都能拿到這個(gè)fd來(lái)處理。二、netio之定時(shí)器
?
先看下圖。netio定時(shí)器所處在的位置。 由于epoll_wait了10毫秒。無(wú)論是否有請(qǐng)求觸發(fā)。 每隔10毫秒都會(huì)輪詢一次。這樣可以防止當(dāng)container通知netio的時(shí)候。消息丟失而導(dǎo)致netio不能處理的情況 定時(shí)器是一個(gè)比較重要的概念。每個(gè)服務(wù)進(jìn)程都會(huì)有個(gè)定時(shí)器來(lái)處理定時(shí)任務(wù)。這里介紹下netio的定時(shí)器. ?這里檢查定時(shí)時(shí)間事件做兩件事。一個(gè)是找出已經(jīng)到達(dá)的時(shí)間事件。并執(zhí)行子類的具體處理函數(shù)。第二個(gè)是給自動(dòng)時(shí)間事件續(xù)期。 netio初始化的時(shí)候。會(huì)注冊(cè)一個(gè)60秒的循環(huán)時(shí)間事件。即每60秒會(huì)執(zhí)行一次時(shí)間事件。這個(gè)時(shí)間事件有以下幾個(gè)動(dòng)作。1)清除超時(shí)的socket ? 2)查詢本地命令字列表 3)定時(shí)輸出netio的統(tǒng)計(jì)信息 3.1 ? 定時(shí)器的數(shù)據(jù)結(jié)構(gòu) netio的定時(shí)器數(shù)據(jù)結(jié)構(gòu)是最小堆。即最近的定時(shí)任務(wù)是在最小堆上 a)申請(qǐng)了65個(gè)大小的二維數(shù)組 const uint32_t DEFAULT_QUEUE_LEN = 1 + 64;m_pNodeHeap = new CNode*[DEFAULT_QUEUE_LEN]; 這里為什么申請(qǐng)1+64.其實(shí)只有64個(gè)可用。? 其中的一個(gè)指針是用來(lái)輔助最小堆算法的。 即m_pNodeHeap[0]?=?NULL; ? 是一直指向空的。 最小堆的最小值 ?是m_pNodeHeap【1】. b) CNode成員變量的意義 struct CNode {CNode(ITimerHandler *pTimerHandler = NULL, int iTimerID = 0) : m_pTimerHandler(pTimerHandler), m_iTimerID(iTimerID), m_dwCount(0) , bEnable(true){ }ITimerHandler *m_pTimerHandler;int m_iTimerID;CTimeValue m_tvExpired; // TimeValue for first checkCTimeValue m_tvInterval; // Time check intervalunsigned int m_dwCount; // Counter for auto re-schedulebool bEnable; }; m_pTimerHandler 主要是用來(lái)保存父類指針。當(dāng)時(shí)間事件觸發(fā)的時(shí)候。通過父類指針找到繼承類。來(lái)處理具體的 時(shí)間事件 m_tvExpired 記錄過期時(shí)間。比如一個(gè)事件過期時(shí)間是10秒。那么m_tvExpired就是存的當(dāng)前時(shí)間+10秒這個(gè)值。每次比較的時(shí)候。拿最小堆的的這個(gè)值跟當(dāng)前時(shí)間比對(duì)。如果當(dāng)前時(shí)間小于m_tvExpired說(shuō)明 沒有任何時(shí)間時(shí)間被觸發(fā)。如果當(dāng)前時(shí)間大于這個(gè)值。則認(rèn)為需要處理時(shí)間事件 m_dwCount 這個(gè)是用來(lái)設(shè)置自動(dòng)過期時(shí)間的次數(shù)。比如我們有一個(gè)時(shí)間事件。我們希望它執(zhí)行三次。每次的間隔以為1分鐘。那么這個(gè)值設(shè)置為3. 當(dāng)?shù)谝淮蔚竭_(dá)時(shí)間時(shí)間的時(shí)候。我們發(fā)現(xiàn)這個(gè)值大于0.則對(duì)m_tvExpired賦值當(dāng)前時(shí)間+1分鐘 重新進(jìn)入最小堆。然后m_dwCount減一。 下次依然是這樣處理。直到m_dwCount這個(gè)值到0.我們就認(rèn)為不需要再自動(dòng)給這個(gè)時(shí)間設(shè)置定時(shí)任務(wù)。 bEnable 這個(gè)值是用來(lái)判斷這個(gè)事件事件是否還有效。這里的做法很有意思。當(dāng)一個(gè)時(shí)間事件執(zhí)行完。或者不需要的時(shí)候。我們先是幫它設(shè)置為false.等下次check時(shí)間最堆的時(shí)候。如果發(fā)現(xiàn)這個(gè)時(shí)間事件是無(wú)效的。這個(gè)時(shí)候在delete m_tvInterval 這個(gè)是時(shí)間事件的間隔時(shí)間。比如我的時(shí)間事件是每10秒執(zhí)行一次。則這個(gè)值就設(shè)置為10秒 m_iTimerID 這個(gè)是時(shí)間事件的唯一ID這個(gè)值是自增的。每來(lái)一個(gè)新時(shí)間事件。m_iTimerID都會(huì)+1. 因?yàn)槌跏蓟臅r(shí)候。這個(gè)值為1了。所以最開始的時(shí)間事件m_iTimerID的值為2?
3.2 ? 定時(shí)清理無(wú)效連接 a)首先如果有客戶端connet進(jìn)來(lái)。 netio會(huì)把這個(gè)connet的fd保存下來(lái) 還有到來(lái)的時(shí)間。 m_mapTcpHandle[iTcpHandle]?=?(int)time(NULL); b ) 每次接受到數(shù)據(jù) 都會(huì)更新這個(gè)時(shí)間 c ) netio有個(gè)配置文件。 我們一般是設(shè)置為10秒。每次檢查定時(shí)事件的時(shí)候。都會(huì)去檢查m_mapTcpHandle。 用當(dāng)前時(shí)間 跟?m_mapTcpHandle里面保存的時(shí)間比較。當(dāng)發(fā)現(xiàn)超過10秒的時(shí)候 我們認(rèn)為這個(gè)連接時(shí)無(wú)效的。然后會(huì)把這個(gè)fd關(guān)閉。并刪除 d) 所以如果 ?要保持長(zhǎng)連接的話。 ?需要客戶端不停的發(fā)送心跳包。來(lái)更新這個(gè)時(shí)間 3.3 ?定時(shí)統(tǒng)計(jì)netio的統(tǒng)計(jì)信息 這有個(gè)很有意思的地方。 在初始化的時(shí)候。我們已經(jīng)注冊(cè)了一個(gè)每60秒執(zhí)行一次輸出的netio狀態(tài)的時(shí)間事件 ? 前面我們說(shuō)了m_dwCount這個(gè)值用來(lái)控制自動(dòng)時(shí)間事件的次數(shù)。我們每一分鐘會(huì)輸出netio的狀態(tài)信息。 這就是固定的時(shí)間事件。我們?nèi)雲(yún)wCount設(shè)置0.那么系統(tǒng)就認(rèn)為你這個(gè)時(shí)間事件是需要無(wú)限循環(huán)的。 就設(shè)置了一個(gè)最大值 (unsigned int )-1。 這個(gè)值算出來(lái)是4294967295。? 我們以每分鐘一次來(lái)計(jì)算。差不多要8000多年才能把這個(gè)m_dwCount減為0~~~~~ if (dwCount > 0)m_l_pNode->m_dwCount = dwCount;elsem_l_pNode->m_dwCount = (unsigned int)-1; 當(dāng)輸出完?duì)顟B(tài)信息后。會(huì)把netio的一些狀態(tài)初始化為0.因?yàn)槲覀兊臓顟B(tài)輸出是統(tǒng)計(jì)一分鐘的狀態(tài)。比如這一分鐘的請(qǐng)求包個(gè)數(shù)。比率。丟包個(gè)數(shù)等。 3.4 ?定時(shí)請(qǐng)求命令字 這里還是比較重要的是。比如我們新加了一個(gè)服務(wù)。如果不重啟netio是不知道的。但是我們會(huì)沒隔一分鐘去請(qǐng)求所有的命令字。 可以發(fā)現(xiàn)有心的服務(wù)加了進(jìn)來(lái)。三、netio 之日志分析
?
4.1、?netio_debug.log日志分析 下面分析下簡(jiǎn)單netio的日志。這里就大概介紹了 。不具體在介紹netio的值了 。 多看看就知道是什么意思的。? 還是請(qǐng)求道container. ?container發(fā)現(xiàn)參數(shù)校驗(yàn)不對(duì)直接把包丟回給netio的回包隊(duì)列 如下圖 a)192.168.254.128:58638 ? ?當(dāng)請(qǐng)求到來(lái)的時(shí)候會(huì)打印請(qǐng)求的IP和端口 b)Handle?=?00700008 ??但是這個(gè)socket不是原生的。是經(jīng)過處理的。 c)ConnNum?=?1 ?當(dāng)前有多個(gè)連接數(shù) d)?Timestamp?=?1460881087 ?請(qǐng)求到了的時(shí)間戳 如下圖 a) ?SendMsgq?REQUEST?START ? ? ? ? ? 這里是把內(nèi)容丟到消息隊(duì)列里 b)?_NotifyNext?REQUEST?START ? ? ? ? ?這里是通知container的uinx域。有消息丟到了你的消息隊(duì)列里 c)?OnRecvFrom?REQUEST?START ? ? ? ? 這里是接收到了container發(fā)來(lái)的uinx域 。告訴netio我已經(jīng)處理完。丟到你的回包消息隊(duì)列里去了。你趕緊去處理吧 d)?OnEventFire?request:0 ? ? ? ? ? ? ? ? ? ? 從消息隊(duì)列里拿到數(shù)據(jù)并開始處理。 ?回給客戶端包 e)OnClose?REQUEST?START ? ? ? ? ? ? ? ?客戶端發(fā)送close socket信號(hào)。 ?服務(wù)端接收后。關(guān)閉socket 4.2 ?netio_perform.log 日志分析 以下都是一份鐘的統(tǒng)計(jì)數(shù)據(jù) PkgRecv ? ? ? ? ? ? ? ? ? ? ?收到的包 PkgSent ? ? ? ? ? ? ? ? ? ? ?發(fā)送出去的包 ErrPkgSent ? ? ? ? ? ? ? ? 錯(cuò)誤的包。 PkgPushFail ? ? ? ? ? ? ? 這個(gè)暫時(shí)沒用到 PkgSendFail ? ? ? ? ? ? ? 這個(gè)是netio ?包發(fā)送的時(shí)候 。發(fā)不出去的個(gè)數(shù) BytesRecv ? ? ? ? ? ? ? ? ? 收到的字節(jié)數(shù) BytesSent ? ? ? ? ? ? ? ? ? 發(fā)送出去的字節(jié)數(shù) MaxConn ? ? ? ? ? ? ? ? ? 最大連接數(shù)。這個(gè)值不是一份內(nèi)的最大值。是從開始到輸出統(tǒng)計(jì)是。最高的同時(shí)連接數(shù)據(jù) TcpConnTimeout ? ? ? 因?yàn)槌瑫r(shí)。netio自動(dòng)關(guān)閉的TCP連接。 Cmd[0x20630001] ? ? ?是netio從回包隊(duì)列中拿到。命令字 Count[15] ? ? ? ? ? ? ? ? ? 該命令字一分鐘內(nèi)總共拿到的回包總數(shù) AverageTime[0]? ? ? ? ?每個(gè)包的平均處理時(shí)間。 這里是拿這15個(gè)包從netio-container-netio這期間的總時(shí)間 除以 15得到的平均時(shí)間 ?單位是毫秒 MaxTime[1] ? ? ? ? ? ? ? ?這15個(gè)包中耗時(shí)最長(zhǎng)的一個(gè)包。所耗時(shí)間 AverageRspLen[89] ? ?平均每個(gè)包回給客戶端的字節(jié)數(shù) MaxRspLen[89] ? ? ? ? ? 最大的一個(gè)回包字節(jié)數(shù) Ratio[100] ? ? ? ? ? ? ? ? ? ?這里先會(huì)拿到一個(gè)一分鐘內(nèi)netio接受包的總個(gè)數(shù)?(這里指客戶端來(lái)的請(qǐng)求包) ?。然后用用0x20630001命令字的個(gè)數(shù)來(lái)除以總包數(shù)再乘以100。得到0x20630001在這一分鐘內(nèi)。所占處理包的比重。 后面接著的一串是 命令字0x20630001的分布在不同相應(yīng)時(shí)間的個(gè)數(shù) 最后一天是正對(duì)一分鐘所有命令字包的統(tǒng)計(jì)?
?
最后:
1)對(duì)大型系統(tǒng)。統(tǒng)計(jì)日志很重要。可以時(shí)事了解系統(tǒng)的狀態(tài)
2)一定要處理好多進(jìn)程的關(guān)系
3)最后 一定要保護(hù)好身體。 ? 身體才是根本啊~~~
總結(jié)
以上是生活随笔為你收集整理的大型分布式C++框架《四:netio之请求包中转站 上》的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何不编程,采集网站评论信息?(视频教程
- 下一篇: MVC与MVVM框架