序
今天下午突然 出現(xiàn) 測(cè)試環(huán)境 cpu飆高,干到了 60%,其他項(xiàng)目 響應(yīng)時(shí)間明顯變長(zhǎng)。。。有點(diǎn)嚇人,不想背鍋
項(xiàng)目背景
出問(wèn)題的項(xiàng)目是 需要連接各個(gè)不同nacos 和不同的 namespace 進(jìn)行對(duì)應(yīng)操作的 一個(gè)項(xiàng)目,對(duì)nacos的操作都是httpClient 調(diào)用的api接口,「httpClient方法 沒(méi)有問(wèn)題,不用質(zhì)疑這個(gè)」
定位問(wèn)題
首先 這 cpu高了,直接top -Hp 看看
定位到 進(jìn)程id,然后 執(zhí)行 jstack 進(jìn)程id -> 1.txt
看到堆棧信息 ,下面提示信息有很多
"com.alibaba.nacos.client.config.security.updater"#2269daemonprio=5os_prio=0tid=0x00007fa3ec401800nid=0x8d85waitingoncondition[0x00007fa314396000] java.lang.Thread.State:TIMED_WAITING(parking) atsun.misc.Unsafe.park(NativeMethod) -parkingtowaitfor<0x00000000f7f3eae0>(ajava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) atjava.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215) atjava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078) atjava.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093) atjava.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809) atjava.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074) atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134) atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) atjava.lang.Thread.run(Thread.java:748)
但是上面這個(gè)提示信息 顯示 是 線程內(nèi)部的,而且是nacos client 內(nèi)部的
你這么搞,讓我很難受啊,我都是http 調(diào)用的,當(dāng)時(shí)就是為了 防止開(kāi)啟無(wú)用的線程,這。。。。。「怎么」
那我去 根據(jù)你的關(guān)鍵字找找 是哪里打印的,「關(guān)鍵字 com.alibaba.nacos.client.config.security.updater」
ServerHttpAgent 類的方法
//initexecutorService this.executorService=newScheduledThreadPoolExecutor(1,newThreadFactory(){ @Override publicThreadnewThread(Runnabler){ Threadt=newThread(r); t.setName("com.alibaba.nacos.client.config.security.updater"); t.setDaemon(true); returnt; } });
這是構(gòu)造方法啊,應(yīng)該只初始化一次的啊,往上debug,我靠,NacosConfigService 類中調(diào)用了,「debug 看什么時(shí)候調(diào)用了 不就行了嘛」
項(xiàng)目初始化的時(shí)候 調(diào)用了一次,業(yè)務(wù)系統(tǒng)依賴nacos嘛,ok 可以理解
再就是漫長(zhǎng)的等待,30s后 發(fā)現(xiàn)又是一次調(diào)用,我去,怎么可能。。。
往回debug,代碼如下
scheduler.schedule("定時(shí)校對(duì)灰度nacos配置",()->loadGrayConfig(grayFileName), 1800,1800,TimeUnit.SECONDS); /** *灰度配置更新解決網(wǎng)絡(luò)隔離的問(wèn)題 * *@paramgrayFileName灰度文件的名稱 */ privatevoidloadGrayConfig(StringgrayFileName){ synchronized(this){ System.err.println("loadGrayConfigdatetime:"+DateUtils.formatDate(newDate())); //刷一次緩存重新獲取nacos內(nèi)容賦值 grayConfigManager.loadNoCache(grayFileName); } }

等會(huì),難道 小丑是我。。。。
這當(dāng)時(shí)是為了灰度功能,定時(shí)數(shù)據(jù)校驗(yàn)用的 用了一個(gè)線程池,當(dāng)時(shí)以為用了線程池 妥妥的。。。還特意調(diào)用的 Nocache 方法,讓他創(chuàng)建新的nacos Config對(duì)象,做數(shù)據(jù)校對(duì)
「但是每調(diào)用一次 NacosFactory.createConfigService(properties) ,nacos config 構(gòu)造器就會(huì)開(kāi)一個(gè)線程,就導(dǎo)致了這個(gè)問(wèn)題」
這里可能你要問(wèn)了 你說(shuō) 為了防止網(wǎng)絡(luò)隔離 才加的這個(gè)調(diào)度任務(wù),什么是網(wǎng)絡(luò)隔離啊?
我剛開(kāi)始聽(tīng)說(shuō)這個(gè)概念是 當(dāng)時(shí)學(xué)習(xí) Raft
假設(shè)一個(gè)Raft集群擁有三個(gè)節(jié)點(diǎn),其中節(jié)點(diǎn)3的「網(wǎng)絡(luò)被隔離」 ,那么按照「BasicRaft」 的實(shí)現(xiàn),集群會(huì)有以下動(dòng)作:
節(jié)點(diǎn)3由于網(wǎng)絡(luò)被隔離,收不到來(lái)自Leader的Heartbeat和AppendEntries,所以節(jié)點(diǎn)3會(huì)進(jìn)入選舉過(guò)程,當(dāng)然選舉過(guò)程也是收不到投票的,所以節(jié)點(diǎn)3會(huì)反復(fù)超時(shí)選舉;節(jié)點(diǎn)3的Term就會(huì)一直增大
節(jié)點(diǎn)1與節(jié)點(diǎn)2會(huì)正常工作,并停留在當(dāng)時(shí)的Term
網(wǎng)絡(luò)恢復(fù)之后,Leader給節(jié)點(diǎn)3發(fā)送RPC的時(shí)候,節(jié)點(diǎn)3會(huì)拒絕這些RPC理由是發(fā)送方任期太小。
Leader收到節(jié)點(diǎn)3發(fā)送的拒絕后,會(huì)增大自己的Term,然后變成Follower。
隨后,集群開(kāi)始新的選舉,大概率原本的Leader會(huì)成為新一輪的Leader。
那么網(wǎng)絡(luò)隔離 Raft是怎么解決的呢?
多輪投票的安全問(wèn)題是棘手的,必須避免同一高度不同輪數(shù)分別提交兩個(gè)不同區(qū)塊的情形。在Tendermint中,這個(gè)問(wèn)題可以通過(guò)鎖機(jī)制(locking mechanism)得到解決。
鎖定規(guī)則:「預(yù)投票鎖(Prevote-the-Lock)」 :
驗(yàn)證者只能「預(yù)投票(pre-vote)」 他們被鎖定的區(qū)塊。這樣就阻止驗(yàn)證者在上一輪中預(yù)提交(pre-commit)一個(gè)區(qū)塊,之后又預(yù)投票了下一輪的另一個(gè)區(qū)塊。
· 波爾卡解鎖(Unlock-on-Polka ):驗(yàn)證者只有在看到更高一輪(相對(duì)于其當(dāng)前被鎖定區(qū)塊的輪數(shù))的波爾卡之后才能釋放該鎖。這樣就允許驗(yàn)證者解鎖,如果他們預(yù)提交了某個(gè)區(qū)塊,但是這個(gè)區(qū)塊網(wǎng)絡(luò)的剩余節(jié)點(diǎn)不想提交,這樣就保護(hù)了整個(gè)網(wǎng)絡(luò)的運(yùn)轉(zhuǎn),并且這樣做并沒(méi)有損害網(wǎng)絡(luò)安全性。
「解決方案是把term替換成(term, nodeid),并且按照字典序比較大小(a > b === a.term > b.term || a.term == b.term && a.nodeid > b. node_id). 這是paxos里的做法, 保證不會(huì)出現(xiàn)raft里的沖突.」
原理是, raft對(duì)voting的階段有2個(gè)值來(lái)描述: term和當(dāng)前投了哪個(gè)node_id, 即[term, nodeid], 由于raft不允許一個(gè)term vote2個(gè)不同的不同的node, 也就是說(shuō), vote_req.term > local.term && vote_req.nodeid == local.nodeid 才會(huì)grant這個(gè)vote請(qǐng)求.
把term替換成(term,nodeid)后, vote階段的大小比較變成了: vote_req.term > local.term || vote_req.term == local.term && vote_req.nodeid >= local.nodeid, 條件邊寬松了. 同一個(gè)term內(nèi), 較大nodeid的可以搶走較小nodeid 已經(jīng)建立的leader.
而日志中原本記錄的term也需要將其替換成(term, node_id), 因?yàn)檫@兩項(xiàng)加起來(lái)才能唯一確定一個(gè)leader. 之前raft里只需一個(gè)term就可以唯一確定一個(gè)leader.
vote中比較最大log id相應(yīng)的,從比較tuple (term, index) 改成比較tuple (term, node_id, index).
就這么點(diǎn)修改.
「總結(jié)下來(lái)就是 按照字典排序 和 預(yù)投票鎖 保證 當(dāng)多個(gè) term 相同的 candidate 相遇后,肯定會(huì)有一個(gè) 獲得多數(shù)派投票」
想法
我們?nèi)绻霈F(xiàn) 異常的網(wǎng)絡(luò)隔離情況再回來(lái),可能導(dǎo)致 數(shù)據(jù)的不一致,但是上面的 解決辦法 因?yàn)?比較重,不適合我們,我們就單純 引入 「定時(shí)校對(duì)的調(diào)度任務(wù) 進(jìn)行比較(和 對(duì)賬一樣)」
修復(fù)
我對(duì)nacos config 連接進(jìn)行 遍歷查找 是否存活,不存活 我就shutdown,然后生成一個(gè)新的,而不是這種全部生成一邊,畢竟人家 構(gòu)造器開(kāi)了線程。。。。
說(shuō)回來(lái)還是因?yàn)?我當(dāng)時(shí)自信了,沒(méi)往這個(gè)調(diào)用下面看,在子類中 寫的開(kāi)線程 哈哈,行吧,改改 ,跑到測(cè)試環(huán)境 看看效果(CPU)
審核編輯:劉清
-
cpu
+關(guān)注
關(guān)注
68文章
11042瀏覽量
216055 -
RPC
+關(guān)注
關(guān)注
0文章
111瀏覽量
11809 -
cache技術(shù)
+關(guān)注
關(guān)注
0文章
41瀏覽量
1197
原文標(biāo)題:記一次 Nacos 導(dǎo)致的 CPU 飆高問(wèn)題 !
文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄

第3集|醫(yī)院網(wǎng)絡(luò)(三)網(wǎng)絡(luò)隔離設(shè)計(jì)#網(wǎng)絡(luò)工程師#網(wǎng)絡(luò)隔離?#硬聲創(chuàng)作季
什么是網(wǎng)絡(luò)隔離技術(shù)
高性能CPU時(shí)鐘網(wǎng)絡(luò)設(shè)計(jì)

高性能CPU的時(shí)鐘網(wǎng)絡(luò)設(shè)計(jì)

物理隔離與邏輯隔離網(wǎng)絡(luò)光端機(jī)和光纖收發(fā)器到底有什么區(qū)別

CPU為什么不做成圓形呢?
JVM CPU使用率飆高問(wèn)題的排查分析過(guò)程
網(wǎng)絡(luò)隔離變壓器的選型
持續(xù)在榜的RAFT-Stereo,你確定不來(lái)了解嗎?

將Paxos和Raft統(tǒng)一為一個(gè)協(xié)議:Abstract-paxos

使用 RAPIDS RAFT 進(jìn)行機(jī)器學(xué)習(xí)和數(shù)據(jù)分析的可重用計(jì)算模式

評(píng)論