IM二分法智能心跳策略

IM心跳策略

心跳的字段定義

  • minHeart 最小心跳,本地默認(rèn)120秒悯仙,服務(wù)器定120秒
  • maxHeart 最大心跳龄毡,本地默認(rèn)580秒,服務(wù)器定580秒
  • startHeart 起步心跳锡垄,本地默認(rèn)240秒沦零,服務(wù)器定240秒

心跳信息字段

  • networkTag 當(dāng)前網(wǎng)絡(luò)類型,如CMCC-4G
  • stabled 穩(wěn)定心跳的標(biāo)志位货岭,true表示穩(wěn)定心跳
  • stabledSuccessCount 穩(wěn)定心跳連續(xù)成功次數(shù)路操,這里是在心跳穩(wěn)定一段時(shí)間后,再嘗試上調(diào)的時(shí)候用千贯,例如stabledSuccessCount > 50的時(shí)候屯仗,穩(wěn)定心跳嘗試上調(diào)
  • failedCount 心跳連續(xù)失敗次數(shù),當(dāng)failedCount >= 3的時(shí)候搔谴,才會(huì)認(rèn)為當(dāng)前心跳是不可用的魁袜,會(huì)嘗試下調(diào),如果心跳一直失敗敦第,那么failedCount是不斷累計(jì)遞增
  • successCount 心跳連續(xù)成功次數(shù)慌核,心跳成功后就遞增1,同時(shí)successCount > 2的時(shí)候會(huì)把failedCount清零
  • curMinHeart 當(dāng)前心跳探測(cè)區(qū)間極小值
  • curMaxHeart 當(dāng)前心跳探測(cè)區(qū)間極大值
  • curHeart 當(dāng)前心跳
  • successHeartList 成功心跳列表申尼,每次心跳成功后垮卓,會(huì)把當(dāng)前的成功心跳記錄進(jìn)來(lái)

重置心跳

  • 當(dāng)TCP連接有除了心跳包以外的消息包在進(jìn)行傳輸(read)時(shí)候,就認(rèn)為該TCP連接在這個(gè)時(shí)刻仍然有效师幕,在程序中read到消息包數(shù)據(jù)后會(huì)對(duì)數(shù)據(jù)進(jìn)行短時(shí)間處理(ms級(jí)別)粟按,然后再write數(shù)據(jù)诬滩,只有收到同步通知,或者單推的時(shí)候本地發(fā)現(xiàn)消息已經(jīng)同步灭将,那此時(shí)就不會(huì)write疼鸟,不過(guò)這種情況發(fā)生的概率比較小,所以心跳是在write數(shù)據(jù)出去的時(shí)候進(jìn)行重置庙曙,這里不在read數(shù)據(jù)的時(shí)候重置心跳是為了避免在弱網(wǎng)環(huán)境下空镜,數(shù)據(jù)包要在網(wǎng)絡(luò)中傳輸幾分鐘,導(dǎo)致服務(wù)器連接超時(shí)捌朴,然后把TCP連接誤斷的這種情況
  • 如果心跳包在write的時(shí)候進(jìn)行重置吴攒,當(dāng)遇到此TCP已經(jīng)是無(wú)效連接,但是服務(wù)器和客戶端都沒(méi)有感知到這中情況砂蔽,那么客戶端對(duì)于write出去的消息會(huì)有一個(gè)超時(shí)檢測(cè)(20s洼怔,但是消息ack沒(méi)有超時(shí)檢測(cè)),write數(shù)據(jù)出去后收不到響應(yīng)的回饋左驾,20s超時(shí)到期镣隶,此時(shí)會(huì)通過(guò)心跳來(lái)驗(yàn)證TCP連接的有效性,心跳超時(shí)就進(jìn)行斷線重連诡右,所以這里會(huì)有60秒以上的消息延遲
  • TCP無(wú)效連接安岂,如果是客戶端的消息ack數(shù)據(jù)發(fā)送出去但是服務(wù)端沒(méi)有收到,那么將遇到兩種情況帆吻,第一是服務(wù)器連接超時(shí)端開(kāi)嗜闻,第二是客戶端下一個(gè)心跳檢測(cè)發(fā)現(xiàn)TCP連接是無(wú)效的,然后斷線重連桅锄,這里會(huì)有最多一個(gè)心跳周期的延遲

心跳策略圖

這里寫(xiě)圖片描述

觸發(fā)心跳上調(diào)

  • 探測(cè)期間的心跳發(fā)送成功并及時(shí)收到服務(wù)器的響應(yīng),這時(shí)候會(huì)執(zhí)行心跳上調(diào)
  • 穩(wěn)定一定的時(shí)間后嘗試上調(diào)(有待優(yōu)化)

心跳上調(diào)策略

  • 記錄成功心跳的信息
  1. successHeartList.add(curHeart);successCount++;
  2. if (successCount >= 2) failedCount = 0;心跳連續(xù)成功兩次样眠,才認(rèn)為當(dāng)前心跳在該網(wǎng)絡(luò)環(huán)境下運(yùn)行穩(wěn)定
  3. 把當(dāng)前的心跳信息更新到文件中友瘤。
  4. if (stabled == true) stabledSuccessCount++;
  • 如果當(dāng)前心跳不是穩(wěn)定心跳,那么執(zhí)行以下操作:
  1. 從成功心跳列表中篩選比當(dāng)前心跳大一級(jí)的心跳周期作為當(dāng)前心跳:curHeart = successHeart;
  2. 如果1沒(méi)有篩選出結(jié)果檐束,則用二分法進(jìn)行上調(diào):
    (1)curMinHeart = curHeart;
    (2)if (curMaxHeart < curMinHeart) curMaxHeart = curMinHeart;
    (3)curHeart = (curMinHeart + curMaxHeart) / 2;
  • 判斷curHeart > maxHeart辫秧,如果是則curHeart = maxHeart;stabled = true被丧;這是用來(lái)異常過(guò)濾
  • 檢測(cè)心跳探測(cè)區(qū)間是否達(dá)到機(jī)值條件:
  1. if (curMaxHeart - curMinHeart <= 10 && stabled == false) curHeart = curMinHeart;
  2. 如果已經(jīng)達(dá)到極值條件(curMaxHeart - curMinHeart <= 10)盟戏,那么stabled = true;
  • 使用curHeart進(jìn)行下一個(gè)心跳的發(fā)送

觸發(fā)心跳下調(diào)

  • 心跳下調(diào)無(wú)非是TCP連接斷線導(dǎo)致心跳下調(diào),但并不是所有的TCP斷線都要下調(diào)心跳甥桂,當(dāng)前遇到會(huì)導(dǎo)致TCP斷線的情況有以下幾種:
  1. 心跳超時(shí)主動(dòng)斷開(kāi)TCP連接(socket closed)柿究,此時(shí)應(yīng)該下調(diào)心跳
  2. IM SDK初始化會(huì)主動(dòng)斷開(kāi)TCP并重新連接(socket closed),不應(yīng)該下調(diào)心跳
  3. 本地網(wǎng)絡(luò)斷開(kāi)造成 TCP連接被動(dòng)斷開(kāi)(Software caused connection abort黄选,socket closed)蝇摸,這里分為兩種情況婶肩,第一個(gè)是網(wǎng)絡(luò)切換,那么這時(shí)候是網(wǎng)絡(luò)斷開(kāi)貌夕,然后再重新連上的一個(gè)過(guò)程律歼,應(yīng)用能明顯的感知到這個(gè)過(guò)程(網(wǎng)絡(luò)切換廣播),TCP連接在網(wǎng)絡(luò)切換的時(shí)候會(huì)被動(dòng)斷開(kāi)啡专,這時(shí)候在下調(diào)心跳之前要先檢測(cè)下本地網(wǎng)絡(luò)是否可用险毁,如果不可用則不進(jìn)行心跳下調(diào),其實(shí)因?yàn)楸镜鼐W(wǎng)絡(luò)斷開(kāi)導(dǎo)致的TCP斷線是不應(yīng)該下調(diào)心跳的们童,這里多了個(gè)檢測(cè)就是為了在一定程度上過(guò)濾掉一部分因?yàn)楸镜鼐W(wǎng)絡(luò)斷開(kāi)導(dǎo)致的心跳誤下調(diào)畔况;還有一種是modem其實(shí)已經(jīng)斷網(wǎng)了,此時(shí)modem可能在進(jìn)行重連病附,但是并沒(méi)有網(wǎng)絡(luò)切換廣播问窃,此時(shí)應(yīng)用層是無(wú)感知的,但是TCP連接可以立馬感知到完沪,并被動(dòng)斷開(kāi)域庇,這時(shí)候檢測(cè)本地網(wǎng)絡(luò)也是可用的(不準(zhǔn)),所以這時(shí)候會(huì)導(dǎo)致心跳誤下調(diào)覆积,Android sdk接口判斷本地網(wǎng)絡(luò)是否可用其實(shí)是不準(zhǔn)確的听皿,如果接口返回不可用,那么本地網(wǎng)絡(luò)一定是不可用的宽档,如果接口返回可用尉姨,那網(wǎng)絡(luò)還不一定真的可用,因?yàn)榻涌跈z測(cè)的只是設(shè)備本地網(wǎng)絡(luò)而已吗冤,如果連接上一個(gè)假wifi(需要驗(yàn)證密碼)又厉,那么設(shè)備到wifi路由器這段網(wǎng)絡(luò)是通的,但是wifi路由器到外網(wǎng)是不通的椎瘟,這時(shí)候設(shè)備是感知不到的覆致,通過(guò)ping才能準(zhǔn)確的知道網(wǎng)絡(luò)是否真的可用,當(dāng)手機(jī)卡欠費(fèi)的時(shí)候肺蔚,本地接口也是返回網(wǎng)絡(luò)可用煌妈,道理類似
  4. 服務(wù)器close造成TCP連接被動(dòng)斷開(kāi)(read返回-1),此時(shí)會(huì)下調(diào)心跳
  5. 其他網(wǎng)絡(luò)原因造成的TCP連接被動(dòng)斷開(kāi)(connection reset等)宣羊,此時(shí)會(huì)下調(diào)心跳
  6. TLV數(shù)據(jù)解析錯(cuò)誤主動(dòng)斷開(kāi)TCP連接璧诵,不應(yīng)該下調(diào)心跳
  7. 除了以上6中原因會(huì)造成TCP斷開(kāi),如果還有其他原因在成TCP斷開(kāi)仇冯,需要檢測(cè)三個(gè)條件才滿足心跳下調(diào)的條件:第一是當(dāng)前心跳是否已經(jīng)啟動(dòng)之宿,第二是當(dāng)前設(shè)備本地網(wǎng)絡(luò)是否可用,第三是TCP斷開(kāi)前苛坚,已經(jīng)持續(xù)連接超過(guò)一個(gè)最小心跳周期的時(shí)間澈缺,滿足以上三個(gè)條件才進(jìn)行下調(diào)心跳坪创,否則不下調(diào)

心跳下調(diào)策略

  • 記錄心跳失敗信息:
  1. 從successHeartList移除當(dāng)前心跳鎖對(duì)應(yīng)的心跳周期;stabledSuccessCount;successCount;failedCount++;
  2. 把當(dāng)前的心跳信息更新到文件中。
  • if (stabled == true && failedCount >= 3)那么執(zhí)行以下操作:
  1. stabled = false;
  2. 從successHeartList篩選比當(dāng)前心跳小一級(jí)的心跳heart
  3. if ((minHeart + curHeart) / 2 < heart) selectedHeart = heart;curHeart = selectedHeart;
  4. 如果沒(méi)有篩選到適合條件的selectedHeart,那么就進(jìn)行二分法下調(diào):
    (1)currentMaxHeart = currentHeart;
    (2)currentMinHeart = minHeart;
    (3)currentHeart = (currentMinHeart + currentMaxHeart) / 2;
  • if (stabled == false && failedCount >= 3)那么執(zhí)行以下操作:
  1. 從successHeartList篩選比當(dāng)前心跳小一級(jí)的心跳heart;
  2. if ((minHeart + curHeart) / 2 < heart) selectedHeart = heart;curHeart = selectedHeart;
  3. 如果沒(méi)有篩選到適合條件的selectedHeart,那么就進(jìn)行二分法下調(diào):
    (1)currentMaxHeart = currentHeart;
    (2)if (currentMaxHeart < curentMinHeart) currentMaxHeart = currentMinHeart;
    (3)currentHeart = (currentMinHeart + currentMaxHeart) / 2;
  • 檢測(cè)心跳探測(cè)區(qū)間是否達(dá)到極值條件:
  1. if (curMaxHeart - curMinHeart <= 10 && stabled == false) currentMinHeart = minHeart;
  2. 之所以加入這個(gè)判斷是為了當(dāng)心跳一直失敗下調(diào)姐赡,但是curMinHeart和curMaxHeart又很接近導(dǎo)致二分法無(wú)法下調(diào)的時(shí)候莱预,就直接把curHeart設(shè)置成minHeart

穩(wěn)定心跳

  • 有效的穩(wěn)定心跳是NAT臨界值
  • 探測(cè)心跳達(dá)到最大心跳值的時(shí)候認(rèn)為是穩(wěn)定心跳
  • 探測(cè)心跳滿足二分法的極值條件(curMaxHeart - curMinHeart < 10)的時(shí)候認(rèn)為是穩(wěn)定心跳
  • 探測(cè)心跳達(dá)到最小心跳值的時(shí)候認(rèn)為是穩(wěn)定心跳
  • 當(dāng)探測(cè)到穩(wěn)定心跳之后,正式使用的心跳值會(huì)在探測(cè)到的穩(wěn)定心跳的基礎(chǔ)上扣除20秒项滑,但是扣除后的心跳值一定要在最大值和最小值之間依沮,避開(kāi)臨界值

Android機(jī)子上存在的問(wèn)題

  • 對(duì)于系統(tǒng)APP發(fā)起的alarm,在android原生系統(tǒng)不會(huì)存在alarm被對(duì)齊的問(wèn)題枪狂,因?yàn)閍ndroid系統(tǒng)對(duì)于系統(tǒng)app發(fā)起的alarm會(huì)設(shè)置alarm的flag為FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED危喉,在Android6.0以上系統(tǒng)AlarmManagerService會(huì)在doze模式下忽略有該flag的alrm,因此不會(huì)被延遲喚醒州疾,至于AlarmClokc辜限,flag是FLAG_WAKE_FROM_IDLE,doze模式下也不會(huì)對(duì)該flag的alarm做延遲喚醒
  • 在Android6.0系統(tǒng)以上严蓖,休眠的時(shí)候alarm是會(huì)被延遲執(zhí)行的薄嫡,可通過(guò)加入系統(tǒng)白名單的方式來(lái)避免,Google的GCM就是默認(rèn)系統(tǒng)白名單颗胡,但是在手機(jī)上毫深,系統(tǒng)白名單嘗試過(guò),并沒(méi)有用毒姨;手表是原生的Android系統(tǒng)哑蔫,可以嘗試加入白名單更加可靠
  • alarm的對(duì)齊喚醒:國(guó)內(nèi)的手機(jī)廠商例如華為,魅族弧呐,小米都是自定制的android系統(tǒng)闸迷,對(duì)于AlarmManager都有對(duì)齊喚醒策略,因此會(huì)導(dǎo)致心跳alarm的時(shí)間不準(zhǔn)確俘枫,例如設(shè)置了270秒alarm一次腥沽,但是在這些手機(jī)上可能要推遲到300秒才能喚醒,那么問(wèn)題來(lái)了崩哩,如果NAT超時(shí)時(shí)間是2分鐘,而這些手機(jī)的alarm最小間隔是5分鐘言沐,那就坑了邓嘹,永遠(yuǎn)無(wú)法探測(cè)到最佳心跳,你設(shè)置120秒的alarm险胰,手機(jī)系統(tǒng)也給你延遲到5分鐘才執(zhí)行alarm汹押,不過(guò)這種情況只有在手機(jī)休眠的時(shí)候才會(huì)對(duì)齊喚醒,在手機(jī)不休眠的時(shí)候起便,我側(cè)過(guò)棚贾,alarm計(jì)時(shí)還是準(zhǔn)確的
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末窖维,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妙痹,更是在濱河造成了極大的恐慌铸史,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,207評(píng)論 6 521
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怯伊,死亡現(xiàn)場(chǎng)離奇詭異琳轿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)耿芹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,455評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門(mén)崭篡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人吧秕,你說(shuō)我怎么就攤上這事琉闪。” “怎么了砸彬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 170,031評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵颠毙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拿霉,道長(zhǎng)吟秩,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,334評(píng)論 1 300
  • 正文 為了忘掉前任绽淘,我火速辦了婚禮涵防,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沪铭。我一直安慰自己壮池,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,322評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布杀怠。 她就那樣靜靜地躺著椰憋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赔退。 梳的紋絲不亂的頭發(fā)上橙依,一...
    開(kāi)封第一講書(shū)人閱讀 52,895評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音硕旗,去河邊找鬼窗骑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛漆枚,可吹牛的內(nèi)容都是我干的创译。 我是一名探鬼主播,決...
    沈念sama閱讀 41,300評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼墙基,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼软族!你這毒婦竟也來(lái)了刷喜?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,264評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤立砸,失蹤者是張志新(化名)和其女友劉穎掖疮,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體仰禽,經(jīng)...
    沈念sama閱讀 46,784評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氮墨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,870評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吐葵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片规揪。...
    茶點(diǎn)故事閱讀 40,989評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖温峭,靈堂內(nèi)的尸體忽然破棺而出猛铅,到底是詐尸還是另有隱情,我是刑警寧澤凤藏,帶...
    沈念sama閱讀 36,649評(píng)論 5 351
  • 正文 年R本政府宣布奸忽,位于F島的核電站,受9級(jí)特大地震影響揖庄,放射性物質(zhì)發(fā)生泄漏栗菜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,331評(píng)論 3 336
  • 文/蒙蒙 一蹄梢、第九天 我趴在偏房一處隱蔽的房頂上張望疙筹。 院中可真熱鬧,春花似錦禁炒、人聲如沸而咆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,814評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)暴备。三九已至,卻和暖如春们豌,著一層夾襖步出監(jiān)牢的瞬間涯捻,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,940評(píng)論 1 275
  • 我被黑心中介騙來(lái)泰國(guó)打工望迎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留障癌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,452評(píng)論 3 379
  • 正文 我出身青樓擂煞,卻偏偏與公主長(zhǎng)得像混弥,于是被迫代替她去往敵國(guó)和親趴乡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子对省,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,995評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容