Netty第二章 2020 3-9 Netty源码之flush优化
?1.Netty的flush優化handler——FlushConsolidationHandler
?
Netty的實現更復雜一些,對于用單獨線程池處理業務的場景,有一些特殊的處理和優化,比如如果異步處理的時候,即channelReadComplete比channelRead結束的要早,所以在flush調用的時候,readInProgress已經是false了,然后根據用戶決定是否開啟對于異步的強化來決定是直接flush還是走consolidateWhenNoReadInProgress,如果consolidateWhenNoReadInProgress為true(開啟增強),那么就用次數是否到達閾值來決定立即刷新還是延時刷新。
我們可以寫一個demo來嘗試一下,這里我們為業務單獨指定線程池,同時開啟異步增強
關于標志位,首先channelRead方法中會把readInProgress置為true,代表正在讀,還沒有執行channelReadComplete方法,此時flush是同步,因為還沒到channelReadComplete的時候。
然后channelReadComplete方法中把它又置為false,說明channelReadComplete方法執行完了,此后的flush都是異步了,因為業務執行慢,錯過了channelReadComplete。
再看這些count,這里第一次flushPendingCount++是1,不滿足閾值,所有走到scheduleFlush之中,雖然該方法中沒有延時,但是畢竟是單獨提交任務,所以給了其它請求write的機會,所以也就有可能節省flush的次數,這里為了讓scheduleFlush更慢,我們在這個斷點處停留一下,相當于卡住,不讓它schedule(調試技巧)。同時客戶端因為又發了請求,所以這第二個請求又會觸發到這里的flush
可以看到會走到代碼斷點處,這里就會觸發flushNow,這里會進行flush,并取消掉scheduleFlush這個任務,說明這兩個請求的flush合并為一個flush了,節省了一次flush。
2.Cassandra的flush優化——Dispatcher#Flusher
我們參考Cassandra的實現,https://github.com/PaytmLabs/cassandra/blob/master/src/java/org/apache/cassandra/transport/Message.java,去除Cassandra的編解碼和連接的部分,自己寫一個flush的優化器
然后和Netty的Consolidation對比一下,可以發現Cassandra的這個優化器的思路更為簡單清晰。它就是利用了隊列來保存待flush的內容,在達到flush條件的時候把隊列里存儲的需要flush的內容一次性flush出去。
flush的條件
flush的條件有兩個,一個是runsSinceFlush,還有一個是flushed的元素個數,兩者有其一滿足就可以flush,這樣可以防止兩種場景:
①請求量很大,在run方法執行3次以前,flushed中已經積攢了太多的需要flush的內容,所以要設置flushed的閾值
②請求量很小,flushed很久才會達到閾值,這樣要等很久才能把之前積攢的消息flush出去,會有很大延時,所以要設置runWithNoWork的閾值
結合這兩個設置就可以避免這兩種極端情況出現了。然后它還可以通過為eventLoop這個executor添加延時任務的方式循環調用該run方法,可以更精細的控制這個flush的流程。
自毀功能
然后這個flusher還有一個自毀功能,如果runsWithNoWork超過5次,說明連續5次都沒有發現要flush的內容,那么就判斷是否要結束該run方法,并不再schedule。
這里有兩個判決條件:待flush的隊列是否為空,running.compareAndSet(false,true)是否失敗,兩者滿足其一就可以結束run執行并不再schedule。
隊列為空比較容易理解,因為沒有待flush的任務了。那么running.compareAndSet(false,true)是否失敗是什么意思呢?我們看到Flusher的start方法中,會判斷running標志位,如果running是false,同時running.compareAndSet(false,true)成功,就可以將該run作為task用EventLoop來執行。那么假設這里有兩個線程,線程A執行到runsWithNoWork超過5次的邏輯了,那么它會先將running設置為false,然后執行running.compareAndSet(false,true),另一個線程B執行到start方法中的running,首先會判斷它是false,然后也執行running.compareAndSet(false,true),這兩個只會有一個成功。
如果線程A成功了,那么說明線程B的start沒有成功,但是確實又有任務需要添加到flush的隊列中,所以run方法不能就此終止,所以這里邏輯也是和這里的分析吻合的,這時不能return,要繼續schedule該run方法。
如果線程A沒成功,那么說明線程B的start成功了,既然已經成功又為EventLoop添加了該run方法這個任務,那么A線程正在執行的任務就沒必要保留了,那么這里的邏輯也和分析吻合,這時就會return,結束run方法,同時不再schedule。
3.總結
綜上,可以看出Cassandra的flush優化實現思路更加清晰簡單,但簡單的同時又不失全面,可以說考慮各種極端情況和場景,并且通過參數的可配置,讓用戶可以定制flush的控制邏輯,如果有flush優化場景的工程可以借鑒使用。
總結
以上是生活随笔為你收集整理的Netty第二章 2020 3-9 Netty源码之flush优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 动态规划C++实现--换钱的方法数(二)
- 下一篇: 内部类与异常类例题