新聞中心
一、寫在前面
相信不少朋友都在自己公司使用Spring Cloud框架來構(gòu)建微服務(wù)架構(gòu),畢竟現(xiàn)在這是非?;鸬囊婚T技術(shù)。

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)建站!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、成都小程序開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了大悟免費建站歡迎大家使用!
如果只是用戶量很少的傳統(tǒng)IT系統(tǒng),使用Spring Cloud可能還暴露不出什么問題。
如果是較多用戶量,高峰每秒高達(dá)上萬并發(fā)請求的互聯(lián)網(wǎng)公司的系統(tǒng),使用Spring Cloud技術(shù)就有一些問題需要注意了。
二、場景引入,問題初現(xiàn)
先不空聊原理、理論,來講一個真實的例子,這是我的一個朋友在創(chuàng)業(yè)互聯(lián)網(wǎng)公司發(fā)生過的真實案例。
朋友A的公司做互聯(lián)網(wǎng)類的創(chuàng)業(yè),組建了一個小型研發(fā)團隊,上來就用了Spring Cloud技術(shù)棧來構(gòu)建微服務(wù)架構(gòu)的系統(tǒng)。
一段時間沒日沒夜的加班,好不容易核心業(yè)務(wù)系統(tǒng)給做出來了,平時正常QA測試沒發(fā)現(xiàn)什么大毛病,感覺性能還不錯,一切都很完美。
然后系統(tǒng)就這么上線了,一開始用戶規(guī)模很小,注冊用戶量小幾十萬,日活幾千用戶。
每天都有新的數(shù)據(jù)進入數(shù)據(jù)庫的表中,就這么日積月累的,沒想到數(shù)據(jù)規(guī)模居然慢慢吞吞增長到了單表幾百萬。
這個時候呢,看起來也沒太大的毛病,就是有用戶反映,系統(tǒng)有些操作,會感覺卡頓幾秒鐘,會刷不出來頁面。
這是為啥呢?
- 核心原因是單表數(shù)據(jù)量大了一些,達(dá)到了幾百萬。
- 有個別服務(wù),跑的SQL比較復(fù)雜,一大堆的多表關(guān)聯(lián)
- 并且還沒有設(shè)計好索引,或者是設(shè)計了索引,但無奈一些小弟寫了上百行的大SQL,SQL實在太復(fù)雜了,那么一個SQL跑出來好幾秒肯定是正常的。
如果大家對微服務(wù)框架有點了解的話,應(yīng)該知道,比如Feign + Ribbon組成的服務(wù)調(diào)用框架,是有接口調(diào)用超時這一說的,有一些參數(shù)可以設(shè)置接口調(diào)用的超時時間。
如果你調(diào)用一個接口,好幾秒刷不出來,人家就超時異常返回,用戶就刷不出來頁面了。
三、揚湯止沸,飲鴆止渴
一般碰到這種事情,一大坨屎一樣的SQL擺在那兒,寫SQL的人過一個月自己都看不懂了,80%的工程師看著都不愿意去花時間重寫和優(yōu)化。
一是修改的人力成本太高,二是誰敢負(fù)擔(dān)這責(zé)任呢?
系統(tǒng)跑的好好的,就是慢了點而已,結(jié)果你硬是亂改一通,重構(gòu),把系統(tǒng)核心業(yè)務(wù)流程搞掛了怎么辦?
所以,那些兄弟第一反應(yīng)是:增加超時時間?。〗涌诼c可以,但是別超時不響應(yīng)??!
咱們讓接口執(zhí)行個幾秒把結(jié)果返回,用戶不就可以刷出來頁面了!不用重構(gòu)系統(tǒng)了??!輕松+愉快!
如何增加呢?很簡單,看下面的參數(shù)就知道了:
大家如果看過之前的文章,應(yīng)該知道,Spring Cloud里一般會用hystrix的線程池來執(zhí)行接口調(diào)用的請求。
所以設(shè)置超時一般設(shè)置兩個地方,feign和ribbon那塊的超時,還有hystrix那塊的超時。其中后者那塊的超時一般必須大于前者。
Spring Cloud玩兒的好的兄弟,可千萬別看著這些配置發(fā)笑,因為我確實見過不少Spring Cloud玩兒的沒那么溜的哥們,真的就這么干了。
好了,日子在繼續(xù)。。。
優(yōu)化了參數(shù)后,看上去效果不錯,用戶雖然覺得有的頁面慢是慢點,但是起碼過幾秒能刷出來。
這個時候,日活幾千的用戶量,壓根兒沒什么并發(fā)可言,高峰期每秒最多一二十并發(fā)請求罷了。
大家看看下面這張圖,感受一下現(xiàn)場氛圍:
四、問題爆發(fā),洪水猛獸
隨著時間的推移,公司業(yè)務(wù)高速發(fā)展……
那位兄弟的公司,在系統(tǒng)打磨成熟,幾萬用戶試點都o(jì)k之后,老板立馬拿到一輪幾千萬的融資。
公司上上下下意氣風(fēng)發(fā)啊!緊接著就是組建運營團隊,地推團隊,全國大范圍的推廣。
總之就是三個字:推!推!推!
這一推不打緊!研發(fā)人員在后臺系統(tǒng)發(fā)現(xiàn),自己的用戶量蹭蹭蹭的直線增長。
注冊用戶增長了幾十倍,突破了千萬級別,日活用戶也翻了幾十倍,在活動之類的高峰期,居然達(dá)到了上百萬的日活用戶量!
幸福的煩惱。。。
為什么這么說?因為用戶量上來后,悲劇的事情就發(fā)生了。
高峰期每秒的并發(fā)請求居然達(dá)到了近萬的程度,研發(fā)團隊的兄弟們哪里敢怠慢!在這個過程中,先是緊張的各種擴容服務(wù),一臺變兩臺,兩臺變四臺。
然后數(shù)據(jù)庫主從架構(gòu)掛上去,讀寫分離是必須的,否則單個數(shù)據(jù)庫服務(wù)器哪能承載那么大的請求!多搞幾個從庫,扛一下大量的讀請求,這樣基本就扛住了。
正準(zhǔn)備坐下來喝口茶、松口氣,更加悲劇的事情就發(fā)生了。
在這個過程中,那些兄弟經(jīng)常會發(fā)現(xiàn)高峰期,系統(tǒng)的某個功能頁面,突然就整個hang死了,就是沒法再響應(yīng)任何請求!所有用戶刷新這個頁面全部都是無法響應(yīng)!
這是為什么呢?原因很簡單?。∫粋€服務(wù)A的實例里,專門調(diào)用服務(wù)B的那個線程池里的線程,總共可能就幾十個。每個線程調(diào)用服務(wù)B都會卡住5秒鐘。
那如果每秒鐘過來幾百個請求這個服務(wù)實例呢?一下子那個線程池里的線程就全部hang死了,沒法再響應(yīng)任何請求了。
大家來看看下面這張圖,再直觀的感受一下這個無助的過程!
這個時候咋辦?兄弟們只能祭出程序員最古老的法寶,重啟機器!
遇到頁面刷不出來,只能重啟機器,相當(dāng)于短暫的初始化了一下機器內(nèi)的資源。
然后接著運行一段時間,又卡死,再次重啟!真是令人崩潰?。∮脩魝兊捏w驗是極差的,老板的心情是憤怒的!
畫外音:
其實這個問題本身不大,但如果對Spring Cloud沒有高并發(fā)場景的真實經(jīng)驗,確實可能會跟這幫兄弟一樣,搞出些莫名其妙的問題。
比如這個公司,明明應(yīng)該去優(yōu)化服務(wù)接口性能,結(jié)果硬是調(diào)大了超時時間。結(jié)果導(dǎo)致并發(fā)量高了,對那個服務(wù)的調(diào)用直接hang死,系統(tǒng)的核心頁面刷不出來,影響用戶體驗了,這怪誰呢?
五、追本溯源,治標(biāo)治本
沒法子了,那幫兄弟們只能找人求助。下面就是作者全程指導(dǎo)他們完成系統(tǒng)優(yōu)化的過程。
第一步
關(guān)鍵點,優(yōu)化圖中核心服務(wù)B的性能?;ヂ?lián)網(wǎng)公司,核心業(yè)務(wù)邏輯,面向C端用戶高并發(fā)的請求,不要用上百行的大SQL,多表關(guān)聯(lián),那樣單表幾百萬行數(shù)據(jù)量的話,會導(dǎo)致一下執(zhí)行好幾秒。
其實最佳的方式,就是對數(shù)據(jù)庫就執(zhí)行簡單的單表查詢和更新,然后復(fù)雜的業(yè)務(wù)邏輯全部放在java系統(tǒng)中來執(zhí)行,比如一些關(guān)聯(lián),或者是計算之類的工作。
這一步干完了之后,那個核心服務(wù)B的響應(yīng)速度就已經(jīng)優(yōu)化成幾十毫秒了,是不是很開心?從幾秒變成了幾十毫秒!
第二步
那個超時的時間,也就是上面那段ribbon和hystrix的超時時間設(shè)置。
奉勸各位同學(xué),不要因為系統(tǒng)接口的性能過差而懶惰,搞成幾秒甚至幾十秒的超時,一般超時定義在1秒以內(nèi),是比較通用以及合理的。
為什么這么說?
因為一個接口,理論的最佳響應(yīng)速度應(yīng)該在200ms以內(nèi),或者慢點的接口就幾百毫秒。
如果一個接口響應(yīng)時間達(dá)到1秒+,建議考慮用緩存、索引、NoSQL等各種你能想到的技術(shù)手段,優(yōu)化一下性能。
否則你要是胡亂設(shè)置超時時間是幾秒,甚至幾十秒,萬一下游服務(wù)偶然出了點問題響應(yīng)時間長了點呢?那你這個線程池里的線程立馬全部卡死!
這兩步解決之后,其實系統(tǒng)表現(xiàn)就正常了,核心服務(wù)B響應(yīng)速度很快,而且超時時間也在1秒以內(nèi),不會出現(xiàn)hystrix線程池頻繁卡死的情況了。
第三步
事兒還沒完,你要真覺得兩步就搞定了,那還是經(jīng)驗不足。
如果你要是超時時間設(shè)置成了1秒,如果就是因為偶然發(fā)生的網(wǎng)絡(luò)抖動,導(dǎo)致接口某次調(diào)用就是在1.5秒呢?這個是經(jīng)常發(fā)生的,因為網(wǎng)絡(luò)的問題,接口調(diào)用偶然超時。
所以此時配合著超時時間,一般都會設(shè)置一個合理的重試,如下所示:
設(shè)置這段重試之后,Spring Cloud中的Feign + Ribbon的組合,在進行服務(wù)調(diào)用的時候,如果發(fā)現(xiàn)某臺機器超時請求失敗,會自動重試這臺機器,如果還是不行會換另外一臺機器重試。
這樣由于偶爾的網(wǎng)絡(luò)請求造成的超時,不也可以通過自動重試避免了?
第四步
其實事兒還沒完,如果把重試參數(shù)配置了,結(jié)果你居然就放手了,那還是沒對人家負(fù)責(zé)任啊!
你的系統(tǒng)架構(gòu)中,只要涉及到了重試,那么必須上接口的冪等性保障機制。
否則的話,試想一下,你要是對一個接口重試了好幾次,結(jié)果人家重復(fù)插入了多條數(shù)據(jù),該怎么辦呢?
其實冪等性保證本身并不復(fù)雜,根據(jù)業(yè)務(wù)來,常見的方案:
- 可以在數(shù)據(jù)庫里建一個唯一索引,插入數(shù)據(jù)的時候如果唯一索引沖突了就不會插入重復(fù)數(shù)據(jù)
- 或者是通過redis里放一個唯一id值,然后每次要插入數(shù)據(jù),都通過redis判斷一下,那個值如果已經(jīng)存在了,那么就不要插入重復(fù)數(shù)據(jù)了。
類似這樣的方案還有一些??傊?,要保證一個接口被多次調(diào)用的時候,不能插入重復(fù)的數(shù)據(jù)。
六、總結(jié)全文,回眸再看
有圖有真相!老規(guī)矩,最后給大家上一張圖,最終優(yōu)化后的系統(tǒng)表現(xiàn)大概是長下面這樣子的。
當(dāng)前文章:面試官:你知道怎么把SpringCloud性能優(yōu)化提升10倍以上嗎?
文章來源:http://www.5511xx.com/article/dpsceig.html


咨詢
建站咨詢
