一、問題描述
2022年7月2x日,窗外夕陽將落不落,余暉灑落在街道上,遠(yuǎn)處的熱浪仿佛在說:嘿,歡迎來到烤箱中的瑞士卷—成都!
“嘿!”,我回過神來看到一只潔白纖細(xì)的手落在我的肩膀上,眼光從窗外收回順著手臂快速扭跟過去,然后看到臉色暗淡夾雜著些許痘痘的測試妹紙一臉的嚴(yán)肅!“昨天晚上上線后,這個后臺執(zhí)行更新信息非常緩慢,這里肯定有問題!”
基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
- 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
- 視頻教程:https://doc.iocoder.cn/video/
二、問題分析
“好的,我排查一下”。三步并作兩步回到工位,掀開MacBook Pro的蓋子、打開顯示器的電源、輸入鏈路日志跟蹤系統(tǒng)地址、復(fù)制traceId、查看日志…… 這一套操作熟悉得令人心疼。
排查日志初步發(fā)現(xiàn)實際調(diào)用了兩次,第一次執(zhí)行時間接近10s,調(diào)用超時,第二次執(zhí)行時間接近5s。你肯定也想到了,RPC調(diào)用retry設(shè)置了值。對RPC配置檢查之后確實設(shè)置的是retry=1,實際項目中,增、刪、改等操作不應(yīng)設(shè)置retry。
通過調(diào)用鏈排查發(fā)現(xiàn)update執(zhí)行非常耗時。聰明的你一定也第一時間懷疑update語句有性能問題。把update語句拿出來:
updatetableseta=#{1},b=#{2},...whereid=#{0}(id主鍵)
這下傻眼了,根據(jù)主鍵id更新怎么可能要執(zhí)行10s?
masaga?!!
為了驗證我的猜想,command + 空格、鍵入idea并回車、打開對應(yīng)的工程、定位到對應(yīng)的方法處、迅速瀏覽一遍并思索片刻之后,真相大白!

服務(wù)B執(zhí)行完update語句之后,事務(wù)commit之前,還有兩個異步通知任務(wù),使用的是spring的@Async注解,自定義的線程池,跟蹤日志中的線程標(biāo)志,排查過程中發(fā)現(xiàn)有的異步任務(wù)居然由原線程執(zhí)行!進(jìn)一步分析日志發(fā)現(xiàn)這種現(xiàn)象并不是一直發(fā)生,有時又是由異步線程執(zhí)行。開始排查線程池,線程池果然設(shè)置了callRunner的失敗策略。
所以,由原線程執(zhí)行時,事務(wù)的范圍如下:

定位到原因之后,修改線程池參數(shù)為常見策略,初始和最大線程數(shù)相同,隊列數(shù)9999,保證線程池的線程充足性。
修復(fù)
灰度
招呼測試妹紙測試
自信滿滿,悠閑喝水
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
三、梅開二度
“在高并發(fā)場景下,復(fù)現(xiàn)了這個問題,你快看一下”!測試妹紙對我投來鄙視的眼光犀利的說道:“修復(fù)好了,再喊我回歸哈,拜拜~”。
奇怪,為什么這么平常的一個update語句,怎么會執(zhí)行這么長時間呢?難道出發(fā)了框架的bug導(dǎo)致事務(wù)提交延遲?不對不對,這個方向想偏了~也沒有其他地方在更新這個表了呀?不可能有表鎖,更不可能有行鎖呀……
masaga?!!
根據(jù)表鎖以及行鎖的思路,為了驗證我的內(nèi)心OS猜想,立即使用 show processlist 進(jìn)行了連接查詢,果然有重大發(fā)現(xiàn),除了服務(wù)B有連接之外,還有服務(wù)A的連接。而服務(wù)A又是服務(wù)B的上游系統(tǒng)!系統(tǒng)架構(gòu)如下:

執(zhí)行順序如下:
順序 | 服務(wù) | 執(zhí)行動作 | 關(guān)鍵點 |
---|---|---|---|
1 | 服務(wù)A | 執(zhí)行update語句 | 數(shù)據(jù)庫 行鎖 lock |
2 | 服務(wù)A | 調(diào)用服務(wù)B | RPC 調(diào)用 |
3 | 服務(wù)B | 執(zhí)行update語句 | 數(shù)據(jù)庫 行鎖 waiting |
4 | 服務(wù)A | 調(diào)用服務(wù)B超時 | RPC timeout |
5 | 服務(wù)A | 再次調(diào)用服務(wù)B | RPC retry |
6 | 服務(wù)A | 調(diào)用調(diào)用服務(wù)B再次超時 | RPC timeout |
7 | 服務(wù)A | PRC調(diào)用超時異常 | 數(shù)據(jù)庫 事務(wù)回滾 行鎖 unlock |
8 | 服務(wù)B | 執(zhí)行 | 數(shù)據(jù)庫 行鎖 競爭 |
不被人信任的滋味很難受!為了重新贏回測試妹紙對我的信任,這次的bug修復(fù)只需成功不許失敗!
四、解決方案
知道病根之后,問題就很簡單了。
最理想的方案
對微服務(wù)架構(gòu)進(jìn)行重構(gòu),但這樣做帶來的收益不高,現(xiàn)在手上還有優(yōu)先級更高的事情要做。

最實際的方案
是將服務(wù)A對服務(wù)B的調(diào)用和服務(wù)A的事務(wù)分離出來。這樣就不存在鎖競爭的問題了。

五、總結(jié)
看到了這里,你心里是不是已經(jīng)在想:我靠,大廠的系統(tǒng)架構(gòu)真的很垃圾,我都是關(guān)著燈的~(走錯片場~)
其實這個系統(tǒng)變成這樣是有歷史原因的,如果當(dāng)初的開發(fā)者能夠采用DDD的思想或者能夠明白微服務(wù)的對象高內(nèi)聚思想,或許今天就不會發(fā)生在我身上這場研發(fā)與測試之間的信任危機。
夕陽落下,夜晚籠罩著大地。路旁的小貓咪悠然站了起來,張大嘴巴打個哈欠的同時伸了個懶腰,然后走向3號門口,等待著心地善良的加班兒投食貓糧。“驗證通過,早點下班”。不遠(yuǎn)處傳來測試妹紙的聲音,夾雜著中央空調(diào)吹出的風(fēng)聲。
審核編輯 :李倩
-
macbook
+關(guān)注
關(guān)注
0文章
500瀏覽量
42086 -
線程
+關(guān)注
關(guān)注
0文章
507瀏覽量
20029 -
系統(tǒng)架構(gòu)
+關(guān)注
關(guān)注
1文章
71瀏覽量
23741
原文標(biāo)題:一個update語句執(zhí)行要10s,大廠的架構(gòu)真垃圾!
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
CPU的各種指令和執(zhí)行流程
ADC128S022的驅(qū)動架構(gòu)參考 ti-adc128s052.c,要如何做移位生成12bit結(jié)果呢?
深入理解C語言:循環(huán)語句的應(yīng)用與優(yōu)化技巧

LM4890做了一個音頻功放電路,使用時發(fā)現(xiàn)4890不到10S鐘就非常燙接著就保護無聲了,是什么原因?
PCM2706C電腦端播放音樂后,點擊暫停出現(xiàn)10s左右的微弱噪聲如何解決?
TAS5805MPWPR輸出15W 10s后,芯片過熱保護了是什么原因?qū)е碌模?/a>
LTspice的編程語句應(yīng)該怎么寫?
想設(shè)計一個10Hz~10MHz的峰值檢波電路,請問這個架構(gòu)可以達(dá)到我頻率范圍的要求嗎?
請問ESP32-ADF如何編譯指定ESP32S2?
i2s使用并口,i2s_parallel PLL_D2_CLK APLL_CLK頻率怎么設(shè)置?
愛旗V200系列模組連接AEP平臺update的工作機制
STM8S103F3P6怎么復(fù)用重映射ADC AIN3?
三個3輸入正與非門SN5410 SN54LS10 SN54S10 SN7410 SN74LS10 SN74S10數(shù)據(jù)表

評論