<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    經驗不在于年限,在于積累---專注互聯網軟件開發(fā)

    把工作當事業(yè)做,把項目當作品做!

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      55 Posts :: 0 Stories :: 66 Comments :: 0 Trackbacks

    最近的一個線上項目(認證服務器)老是出現服務延遲的情況。具體的問題描述:

    (1)客戶端發(fā)送一個請求A(長連接),在服務器端的業(yè)務層需要20秒以上才能接收到。

    (2)客戶端發(fā)送一個請求B(端連接),在服務器端的業(yè)務層可以迅速接收到。

    從現象大致知道問題出在服務器端的網絡接收層,大量通過長連接發(fā)送過來的請求都堵塞在網絡層得不到處理(在網絡層排隊,還沒到應用層)。

    (友情提示:本博文章歡迎轉載,但請注明出處:hankchen,http://www.tkk7.com/hankchen

     

    后來經過排查,發(fā)現是Netty中的OrderedMemoryAwareThreadPoolExecutor原因。相關代碼如下:

    MemoryAwareThreadPoolExecutor executor = new OrderedMemoryAwareThreadPoolExecutor(threadNums, maxChannelMemorySize,
                                                                                                            maxTotalMemorySize, keepAliveTime,
                                                                                                            TimeUnit.SECONDS);
    ExecutionHandler executionHandler = new ExecutionHandler(executor);

    public ChannelPipeline getPipeline() throws Exception
    {
            ChannelPipeline pipeline = pipeline();
            pipeline.addLast("decoder", new AuthDecoder());
            pipeline.addLast("encoder", new AuthEncoder());
            pipeline.addLast("executor", executionHandler);
            pipeline.addLast("handler", new AuthServerHandler(commandFactory));
            return pipeline;
    }

     

    先介紹下背景知識,再來分析問題。

    大家都知道,Netty是一個基于事件的NIO框架。在Netty中,一切網絡動作都是通過事件來傳播并處理的,例如:Channel讀、Channel寫等等。回憶下Netty的流處理模型:

    Boss線程(一個服務器端口對于一個)---接收到客戶端連接---生成Channel---交給Work線程池(多個Work線程)來處理。

    具體的Work線程---讀完已接收的數據到ChannelBuffer---觸發(fā)ChannelPipeline中的ChannelHandler鏈來處理業(yè)務邏輯。

    注意:執(zhí)行ChannelHandler鏈的整個過程是同步的,如果業(yè)務邏輯的耗時較長,會將導致Work線程長時間被占用得不到釋放,從而影響了整個服務器的并發(fā)處理能力。

    所以,為了提高并發(fā)數,一般通過ExecutionHandler線程池來異步處理ChannelHandler鏈(worker線程在經過ExecutionHandler后就結束了,它會被ChannelFactory的worker線程池所回收)。在Netty中,只需要增加一行代碼:

    public ChannelPipeline getPipeline() {
             return Channels.pipeline(
                     new DatabaseGatewayProtocolEncoder(),
                     new DatabaseGatewayProtocolDecoder(),
                     executionHandler, // Must be shared
                     new DatabaseQueryingHandler());
    }
    例如:
    ExecutionHandler executionHandler = new ExecutionHandler(
                 new OrderedMemoryAwareThreadPoolExecutor(16, 1048576, 1048576))

     

    對于ExecutionHandler需要的線程池模型,Netty提供了兩種可選:

    1) MemoryAwareThreadPoolExecutor 通過對線程池內存的使用控制,可控制Executor中待處理任務的上限(超過上限時,后續(xù)進來的任務將被阻塞),并可控制單個Channel待處理任務的上限,防止內存溢出錯誤;

    2) OrderedMemoryAwareThreadPoolExecutor 是 MemoryAwareThreadPoolExecutor 的子類。除了MemoryAwareThreadPoolExecutor 的功能之外,它還可以保證同一Channel中處理的事件流的順序性,這主要是控制事件在異步處理模式下可能出現的錯誤的事件順序,但它并不保證同一Channel中的事件都在一個線程中執(zhí)行(通常也沒必要)。

    例如:

    Thread X: --- Channel A (Event A1) --.   .-- Channel B (Event B2) --- Channel B (Event B3) --->
                                          \ /
                                           X
                                          / \
    Thread Y: --- Channel B (Event B1) --'   '-- Channel A (Event A2) --- Channel A (Event A3) --->

    上圖表達的意思有幾個:

    (1)對整個線程池而言,處理同一個Channel的事件,必須是按照順序來處理的。例如,必須先處理完Channel A (Event A1) ,再處理Channel A (Event A2)、Channel A (Event A3)

    (2)同一個Channel的多個事件,會分布到線程池的多個線程中去處理。

    (3)不同Channel的事件可以同時處理(分擔到多個線程),互不影響。  

    OrderedMemoryAwareThreadPoolExecutor 的這種事件處理有序性是有意義的,因為通常情況下,請求發(fā)送端希望服務器能夠按照順序處理自己的請求,特別是需要多次握手的應用層協(xié)議。例如:XMPP協(xié)議。

     

    現在回到具體業(yè)務上來,我們這里的認證服務也使用了OrderedMemoryAwareThreadPoolExecutor。認證服務的其中一個環(huán)節(jié)是使用長連接,不斷處理來自另外一個服務器的認證請求。通信的數據包都很小,一般都是200個字節(jié)以內。一般情況下,處理這個過程很快,所以沒有什么問題。但是,由于認證服務需要調用第三方的接口,如果第三方接口出現延遲,將導致這個過程變慢。一旦一個事件處理不完,由于要保持事件處理的有序性,其他事件就全部堵塞了!而短連接之所以沒有問題,是因為短連接一個Channel就一個請求數據包,處理完Channel就關閉了,根本不存在順序的問題,所以在業(yè)務層可以迅速收到請求,只是由于同樣的原因(第三方接口),處理時間會比較長。

    其實,認證過程都是獨立的請求數據包(單個帳號),每個請求數據包之間是沒有任何關系的,保持這樣的順序沒有意義!

     

    最后的改進措施:

    1、去掉OrderedMemoryAwareThreadPoolExecutor,改用MemoryAwareThreadPoolExecutor。

    2、減少調用第三方接口的超時時間,讓處理線程盡早回歸線程池。

    (友情提示:本博文章歡迎轉載,但請注明出處:hankchen,http://www.tkk7.com/hankchen

    posted on 2012-04-08 12:32 hankchen 閱讀(14351) 評論(0)  編輯  收藏 所屬分類: 網絡開發(fā)+Mina+Netty
    主站蜘蛛池模板: 国产精品无码免费播放| 国产精品免费看久久久 | 亚洲av激情无码专区在线播放| 亚洲AV无码男人的天堂| 好男人看视频免费2019中文| 亚洲中文字幕一区精品自拍| 大地资源免费更新在线播放| 亚洲精品国产av成拍色拍| 国产成人aaa在线视频免费观看| 久久精品国产亚洲av瑜伽| 亚洲国产精品成人AV无码久久综合影院| 国产av无码专区亚洲av毛片搜| 免费日本黄色网址| 国产vA免费精品高清在线观看| 亚洲精品你懂的在线观看| 91精品免费高清在线| 亚洲一级特黄特黄的大片| 日本成人免费在线| 一区二区三区免费电影| 亚洲国产一区二区a毛片| 亚洲免费电影网站| 国产精品亚洲va在线观看| 久久精品国产亚洲Aⅴ香蕉| 三年片免费高清版| 亚洲最大黄色网址| 国产免费观看a大片的网站| 九九热久久免费视频| 亚洲激情校园春色| 亚洲区日韩区无码区| 日韩电影免费在线观看网站| 亚洲美女视频网址| 国产乱色精品成人免费视频| 亚洲天堂免费在线视频| 久久精品国产亚洲AV麻豆网站| 插B内射18免费视频| 一区二区三区免费在线观看| 在线电影你懂的亚洲| 国产成人高清精品免费软件 | 亚洲最大视频网站| 亚洲 国产 图片| 亚洲日本久久一区二区va|