微服務(wù)系統(tǒng)RPC超時(shí)重試,你確定自己懂嗎?

今天給大家分享一知識(shí)點(diǎn),是關(guān)于我們平時(shí)開發(fā)系統(tǒng)做 RPC 通信的時(shí)候,經(jīng)常會(huì)設(shè)置超時(shí)和重試兩個(gè)參數(shù)。
關(guān)于這兩個(gè)參數(shù)要是沒(méi)有設(shè)置好的話,很可能會(huì)導(dǎo)致我們的系統(tǒng)被搞垮,但是可能很多人都不知道這里面的問(wèn)題,所以今天給大家好好講講。
業(yè)務(wù)系統(tǒng)架構(gòu)圖
首先,我們還是先引出一個(gè)話題,那就是平時(shí)我們開發(fā)的系統(tǒng)是什么樣的?其實(shí)往簡(jiǎn)單了說(shuō),就是用 SpringBoot+SSM 開發(fā)一套業(yè)務(wù)代碼,然后用 Nacos+Dubbo 去 RPC 調(diào)用別的系統(tǒng)。
這個(gè)架構(gòu)圖非常簡(jiǎn)單,如下所示:

微服務(wù)項(xiàng)目技術(shù)難點(diǎn) 1:RPC 的超時(shí)機(jī)制
那么在兩個(gè)系統(tǒng)進(jìn)行 RPC 調(diào)用的時(shí)候,有兩個(gè)參數(shù)其實(shí)是至關(guān)重要的,一個(gè)是 timeout 超時(shí)時(shí)間,一個(gè)是 retry 重試次數(shù),這個(gè) timeout 超時(shí)通常用于什么場(chǎng)景呢?
大家可以想象一個(gè)場(chǎng)景,如果說(shuō)我們不設(shè)置 timeout 超時(shí)時(shí)間,是否可能出現(xiàn)這樣一種情況,就是你調(diào)用的那個(gè)系統(tǒng)可能故障了,或者是掛了,或者是他的性能突然很慢很慢,導(dǎo)致你調(diào)用他好幾秒都沒(méi)法返回。
如下圖:

如果要是你調(diào)用一個(gè)系統(tǒng)時(shí)間很久都沒(méi)法返回,此時(shí)會(huì)導(dǎo)致什么問(wèn)題?
我們要知道,你自己這個(gè)系統(tǒng)對(duì)外接收請(qǐng)求靠的是線程,假設(shè)我們是 通過(guò) SpringBoot 內(nèi)嵌 Tomcat 對(duì)外接收請(qǐng)求的,那么其實(shí) Tomcat 就會(huì)開很多線程,每個(gè) Http 請(qǐng)求過(guò)來(lái)了,每個(gè)請(qǐng)求都是要交給一個(gè)線程來(lái)處理的。
如下圖所示:

那么一個(gè)線程拿到了一個(gè)請(qǐng)求開始處理之后,他就會(huì)去調(diào)用別的系統(tǒng),如果要是調(diào)用別的系統(tǒng)這個(gè)過(guò)程中因?yàn)樗收狭耍瑢?dǎo)致調(diào)用時(shí)間超長(zhǎng),好幾秒都沒(méi)個(gè)響應(yīng),這個(gè)時(shí)候會(huì)怎么樣呢?
那還不簡(jiǎn)單,這會(huì)導(dǎo)致 Tomcat 一個(gè)線程一直阻塞好幾秒都沒(méi)法去處理別的請(qǐng)求。那么這個(gè)時(shí)候,如果所有線程都因?yàn)檎{(diào)用一個(gè)服務(wù)被阻塞住了,是不是就導(dǎo)致新的請(qǐng)求過(guò)來(lái)沒(méi)有一個(gè)線程可以處理了?
如下圖:

所以說(shuō),往往來(lái)說(shuō),我們對(duì)于別的服務(wù) RPC 調(diào)用一般都得設(shè)置一個(gè)超時(shí)時(shí)間,比如說(shuō),設(shè)置 timeout=1s,那么意思就是說(shuō),我們調(diào)用別的系統(tǒng)如果超過(guò) 1s 沒(méi)有響應(yīng),就直接拋個(gè)異常就返回了,這樣就可以避免我們的 Tomcat 線程 長(zhǎng)時(shí)間阻塞了。
如下圖:

微服務(wù)項(xiàng)目技術(shù)難點(diǎn) 2:RPC 的重試機(jī)制
那么除了這個(gè) timeout 超時(shí)時(shí)間以外,還有另外一個(gè)參數(shù)是 retry,這個(gè) retry 的意思,就是說(shuō)如果你 RPC 調(diào)用一個(gè)服務(wù)要是失敗了,此時(shí)就可以通過(guò) retry 設(shè)置自動(dòng)做一個(gè)重試。
比如說(shuō)自動(dòng)可以重試 2 次,那么這個(gè)時(shí)候如果是因?yàn)榫W(wǎng)絡(luò)偶然抖動(dòng)導(dǎo)致的調(diào)用失敗,就可以通過(guò)重試 2 次讓他能夠成功完成調(diào)用了。
如下圖:

生產(chǎn)項(xiàng)目中 timeout 和 retry 一般設(shè)置成多少呢?
好了,現(xiàn)在 timeout 和 retry 兩個(gè)參數(shù)講完了,下面就可以講這兩個(gè)參數(shù)設(shè)置不當(dāng)是如何導(dǎo)致系統(tǒng)出現(xiàn)故障的了。
先來(lái)說(shuō)這個(gè) timeout,這個(gè) timeout 設(shè)置可一定要慎重啊,因?yàn)槿绻窃O(shè)置的不謹(jǐn)慎,可能導(dǎo)致你的系統(tǒng)莫名其妙就直接跨掉了。
比如說(shuō),這個(gè) timeout 你要是設(shè)置的時(shí)間太長(zhǎng)了,好比說(shuō) 5s,10s,那么可能在極端情況下,比如對(duì)方系統(tǒng)故障了,你每個(gè)請(qǐng)求都要 5s、10s 才能返回,那不就會(huì)導(dǎo)致剛才上面說(shuō)的問(wèn)題了?
就是 Tomcat 每個(gè)線程都得阻塞 5s、10s 才能返回,這就導(dǎo)致你的系統(tǒng)沒(méi)法處理新的請(qǐng)求了。
如下圖:

那么如果要是 timeout 設(shè)置的太短了呢?比如說(shuō)設(shè)置 timeout=500ms,那好,這可能也有很大問(wèn)題了。
因?yàn)橛锌赡苣骋惶煲驗(yàn)楦慊顒?dòng)流量比較大,你調(diào)用的系統(tǒng)因?yàn)閴毫Ρ容^大,導(dǎo)致他的 CPU 負(fù)載很高,然后平時(shí)一般請(qǐng)求都是 300~400ms 可以返回,結(jié)果今天搞成 500~600ms 了,剛好超過(guò)了 timeout 時(shí)間。
此時(shí)就會(huì)導(dǎo)致,你大量的請(qǐng)求即將處理完畢要返回的時(shí)候,結(jié)果一到 500ms 就超時(shí)異常拋出,一到 500ms 就超時(shí)異常拋出。
如下圖:

所以說(shuō),timeout 超時(shí)參數(shù)設(shè)置,通常是這么設(shè)置的,對(duì)于你要調(diào)用的系統(tǒng)你要看看他平時(shí)調(diào)用要多久能返回,然后比正常的耗時(shí)設(shè)置的多個(gè) 50% 就可以了。
比如平時(shí)一般正常在 100~200ms,偶爾高峰會(huì)在 500ms,那你設(shè)置個(gè) timeout=800ms 或者 1s 其實(shí)都可以。
然后就是 retry 這個(gè)參數(shù),這個(gè)參數(shù)也是不能胡亂設(shè)置的,尤其是對(duì)于一些調(diào)用別的系統(tǒng)寫入數(shù)據(jù)的接口。
如果你要是對(duì)別的服務(wù)的寫接口設(shè)置了 retry,就可能有這樣一種場(chǎng)景,某一次寫入接口可能耗時(shí)稍微長(zhǎng)了一些,導(dǎo)致了超時(shí)出錯(cuò),結(jié)果你又 retry 再次重試寫入,就可能導(dǎo)致數(shù)據(jù)會(huì)有重復(fù)的問(wèn)題。
所以說(shuō)通常都建議 retry 參數(shù)對(duì)讀接口可以設(shè)置一下,但是對(duì)寫接口最好是不要設(shè)置。
好了,今天關(guān)于 RPC 超時(shí)和重試參數(shù)的分享就到這里了。
























