成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

心跳 —— 超時機(jī)制分析

godlong_X / 3029人閱讀

摘要:問題分析及解決方案服務(wù)端一般會保持很多個連接,所以,一般是創(chuàng)建一個定時器,定時檢查所有連接中哪些連接超時了。

問題描述

在C/S模式中,有時我們會長時間保持一個連接,以避免頻繁地建立連接,但同時,一般會有一個超時時間,在這個時間內(nèi)沒發(fā)起任何請求的連接會被斷開,以減少負(fù)載,節(jié)約資源。并且該機(jī)制一般都是在服務(wù)端實現(xiàn),因為client強(qiáng)制關(guān)閉或意外斷開連接,server端在此刻是感知不到的,如果放到client端實現(xiàn),在上述情況下,該超時機(jī)制就失效了。本來這問題很普通,不太值得一提,但最近在項目中看到了該機(jī)制的一種糟糕的實現(xiàn),故在此深入分析一下。

問題分析及解決方案

服務(wù)端一般會保持很多個連接,所以,一般是創(chuàng)建一個定時器,定時檢查所有連接中哪些連接超時了。此外我們要做的是,當(dāng)收到客戶端發(fā)來的數(shù)據(jù)時,怎么去刷新該連接的超時信息?

最近看到一種實現(xiàn)方式是這樣做的:

public class Connection {
    private long lastTime;
    public void refresh() {
        lastTime = System.currentTimeMillis();
    }

    public long getLastTime() {
        return lastTime;
    }
    //......
}

在每次收到客戶端發(fā)來的數(shù)據(jù)時,調(diào)用refresh方法。

然后在定時器里,用當(dāng)前時間跟每個連接的getLastTime()作比較,來判定超時:

public class TimeoutTask  extends TimerTask{
    public void run() {
        long now = System.currentTimeMillis();
        for(Connection c: connections){
            if(now - c.getLastTime()> TIMEOUT_THRESHOLD)
                ;//timeout, do something
        }
    }
}

看到這,可能不少讀者已經(jīng)看出問題來了,那就是內(nèi)存可見性問題,調(diào)用refresh方法的線程跟執(zhí)行定時器的線程肯定不是一個線程,那run方法中讀到的lastTime就可能是舊值,即可能將活躍的連接判定超時,然后被干掉。

有讀者此時可能想到了這樣一個方法,將lastTime加個volatile修飾,是的,這樣確實解決了問題,不過,作為服務(wù)端,很多時候?qū)π阅苁怯幸蟮?,下面來看下在我電腦上測出的一組數(shù)據(jù),測試代碼如下,供參考

public class PerformanceTest {
    private static long i;
    private volatile static long vt;
    private static final int TEST_SIZE = 10000000;

    public static void main(String[] args) {
        long time = System.nanoTime();
        for (int n = 0; n < TEST_SIZE; n++)
            vt = System.currentTimeMillis();
        System.out.println(-time + (time = System.nanoTime()));
        for (int n = 0; n < TEST_SIZE; n++)
            i = System.currentTimeMillis();
        System.out.println(-time + (time = System.nanoTime()));
        for (int n = 0; n < TEST_SIZE; n++)
            synchronized (PerformanceTest.class) {
            }
        System.out.println(-time + (time = System.nanoTime()));
        for (int n = 0; n < TEST_SIZE; n++)
            vt++;
        System.out.println(-time + (time = System.nanoTime()));
        for (int n = 0; n < TEST_SIZE; n++)
            vt = i;
        System.out.println(-time + (time = System.nanoTime()));
        for (int n = 0; n < TEST_SIZE; n++)
            i = vt;
        System.out.println(-time + (time = System.nanoTime()));
        for (int n = 0; n < TEST_SIZE; n++)
            i++;
        System.out.println(-time + (time = System.nanoTime()));
        for (int n = 0; n < TEST_SIZE; n++)
            i = n;
        System.out.println(-time + (time = System.nanoTime()));
    }
}

測試一千萬次,結(jié)果是(耗時單位:納秒,包含循環(huán)本身的時間):
238932949 volatile寫+取系統(tǒng)時間
144317590 普通寫+取系統(tǒng)時間
135596135 空的同步塊(synchronized)
80042382 volatile變量自增
15875140 volatile寫
6548994 volatile讀
2722555 普通自增
2949571 普通讀寫

從上面的數(shù)據(jù)看來,volatile寫+取系統(tǒng)時間的耗時是很高的,取系統(tǒng)時間的耗時也比較高,跟一次無競爭的同步差不多了,接下來分析下如何優(yōu)化該超時時機(jī)。

首先:同步問題是肯定得考慮的,因為有跨線程的數(shù)據(jù)操作;另外,取系統(tǒng)時間的操作比較耗時,能否不在每次刷新時都取時間?因為刷新調(diào)用在高負(fù)載的情況下很頻繁。如果不在刷新時取時間,那又該怎么去判定超時?

我想到的辦法是,在refresh方法里,僅設(shè)置一個volatile的boolean變量reset(這應(yīng)該是成本最小的了吧,因為要處理同步問題,要么同步塊,要么volatile,而volatile讀在此處是沒什么意義的),對時間的掌控交給定時器來做,并為每個連接維護(hù)一個計數(shù)器,每次加一,如果reset被設(shè)置為true了,則計數(shù)器歸零,并將reset設(shè)為false(因為計數(shù)器只由定時器維護(hù),所以不需要做同步處理,從上面的測試數(shù)據(jù)來看,普通變量的操作,時間成本是很低的),如果計數(shù)器超過某個值,則判定超時。 下面給出具體的代碼:

public class Connection {
    int count = 0;
    volatile boolean reset = false;
    public void refresh() {
        if (reset == false)
            reset = true;
    }
}

public class TimeoutTask extends TimerTask {
    public void run() {
        for (Connection c : connections) {
            if (c.reset) {
                c.reset = false;
                c.count = 0;
            } else if (++c.count >= TIMEOUT_COUNT)
                ;// timeout, do something
        }
    }
}

代碼中的TIMEOUT_COUNT 等于超時時間除以定時器的周期,周期大小既影響定時器的執(zhí)行頻率,也會影響實際超時時間的波動范圍(這個波動,第一個方案也存在,也不太可能避免,并且也不需要多么精確)。

代碼很簡潔,下面來分析一下。

reset加上了volatile,所以保證了多線程操作的可見性,雖然有兩個線程都對變量有寫操作,但無論這兩個線程怎么穿插執(zhí)行,都不會影響其邏輯含義。

再說下refresh方法,為什么我在賦值語句上多加了個條件?這不是多了一次volatile讀操作嗎?我是這么考慮的,高負(fù)載下,refresh會被頻繁調(diào)用,意味著reset長時間為true,那么加上條件后,就不會執(zhí)行寫操作了,只有一次讀操作,從上面的測試數(shù)據(jù)來看,volatile變量的讀操作的性能是顯著優(yōu)于寫操作的。只不過在reset為false的時候,多了一次讀操作,但此情況在定時器的一個周期內(nèi)最多只會發(fā)一次,而且對高負(fù)載情況下的優(yōu)化顯然更有意義,所以我認(rèn)為加上條件還是值得的。

最后提及一下,我有點完美主義,自認(rèn)為上面的方案在我當(dāng)前掌握的知識下,已經(jīng)很漂亮了,如果你發(fā)現(xiàn)還有可優(yōu)化的地方,或更好的方案,希望能分享。

via ifeve

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/69761.html

相關(guān)文章

  • 斷開TCP連接

    摘要:我們知道通過三次握手建立可靠連接,通過四次揮手?jǐn)嚅_連接,連接是比較昂貴的資源。從上分析,安全可靠的斷開連接至少需要四次,再多一次的意義不大。連接的異常斷開以上都是在理想的情況下發(fā)生的,理想狀態(tài)下,一個連接可以被長期保持。 我們知道TCP通過三次握手建立可靠連接,通過四次揮手?jǐn)嚅_連接,TCP連接是比較昂貴的資源。為什么TCP需要通過三次握手才能建立可靠的連接?兩次不行么?斷開連接為什么需...

    fyber 評論0 收藏0
  • 淺析 Netty 實現(xiàn)心跳機(jī)制與斷線重連

    摘要:基礎(chǔ)何為心跳顧名思義所謂心跳即在長連接中客戶端和服務(wù)器之間定期發(fā)送的一種特殊的數(shù)據(jù)包通知對方自己還在線以確保連接的有效性為什么需要心跳因為網(wǎng)絡(luò)的不可靠性有可能在保持長連接的過程中由于某些突發(fā)情況例如網(wǎng)線被拔出突然掉電等會造成服務(wù)器和客戶端的 基礎(chǔ) 何為心跳 顧名思義, 所謂 心跳, 即在 TCP 長連接中, 客戶端和服務(wù)器之間定期發(fā)送的一種特殊的數(shù)據(jù)包, 通知對方自己還在線, 以確保 ...

    waterc 評論0 收藏0
  • dubbo源碼解析(十)遠(yuǎn)程通信——Exchange層

    摘要:和斷開,處理措施不一樣,會分別做出重連和關(guān)閉通道的操作。取消定時器取消大量已排隊任務(wù),用于回收空間該方法是停止現(xiàn)有心跳,也就是停止定時器,釋放空間。做到異步處理返回結(jié)果時能給準(zhǔn)確的返回給對應(yīng)的請求。 遠(yuǎn)程通訊——Exchange層 目標(biāo):介紹Exchange層的相關(guān)設(shè)計和邏輯、介紹dubbo-remoting-api中的exchange包內(nèi)的源碼解析。 前言 上一篇文章我講的是dubb...

    cppprimer 評論0 收藏0
  • 使用Netty,我們到底在開發(fā)些什么?

    摘要:比如面向連接的功能包發(fā)送接收數(shù)量包發(fā)送接收速率錯誤計數(shù)連接重連次數(shù)調(diào)用延遲連接狀態(tài)等。你要處理的,就是心跳超時的邏輯,比如延遲重連。發(fā)生異常后,可以根據(jù)不同的類型選擇斷線重連比如一些二進(jìn)制協(xié)議的編解碼紊亂問題,或者調(diào)度到其他節(jié)點。 在java界,netty無疑是開發(fā)網(wǎng)絡(luò)應(yīng)用的拿手菜。你不需要太多關(guān)注復(fù)雜的nio模型和底層網(wǎng)絡(luò)的細(xì)節(jié),使用其豐富的接口,可以很容易的實現(xiàn)復(fù)雜的通訊功能。 和...

    DesGemini 評論0 收藏0

發(fā)表評論

0條評論

godlong_X

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<