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