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

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

定位到原因之后,修改線程池參數(shù)為常見(jiàn)策略,初始和最大線程數(shù)相同,隊(duì)列數(shù)9999,保證線程池的線程充足性。
修復(fù)
灰度
招呼測(cè)試妹紙測(cè)試
自信滿滿,悠閑喝水
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
三、梅開(kāi)二度
“在高并發(fā)場(chǎng)景下,復(fù)現(xiàn)了這個(gè)問(wèn)題,你快看一下”!測(cè)試妹紙對(duì)我投來(lái)鄙視的眼光犀利的說(shuō)道:“修復(fù)好了,再喊我回歸哈,拜拜~”。
奇怪,為什么這么平常的一個(gè)update語(yǔ)句,怎么會(huì)執(zhí)行這么長(zhǎng)時(shí)間呢?難道出發(fā)了框架的bug導(dǎo)致事務(wù)提交延遲?不對(duì)不對(duì),這個(gè)方向想偏了~也沒(méi)有其他地方在更新這個(gè)表了呀?不可能有表鎖,更不可能有行鎖呀……
masaga?!!
根據(jù)表鎖以及行鎖的思路,為了驗(yàn)證我的內(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í)行動(dòng)作 | 關(guān)鍵點(diǎn) |
---|---|---|---|
1 | 服務(wù)A | 執(zhí)行update語(yǔ)句 | 數(shù)據(jù)庫(kù) 行鎖 lock |
2 | 服務(wù)A | 調(diào)用服務(wù)B | RPC 調(diào)用 |
3 | 服務(wù)B | 執(zhí)行update語(yǔ)句 | 數(shù)據(jù)庫(kù) 行鎖 waiting |
4 | 服務(wù)A | 調(diào)用服務(wù)B超時(shí) | RPC timeout |
5 | 服務(wù)A | 再次調(diào)用服務(wù)B | RPC retry |
6 | 服務(wù)A | 調(diào)用調(diào)用服務(wù)B再次超時(shí) | RPC timeout |
7 | 服務(wù)A | PRC調(diào)用超時(shí)異常 | 數(shù)據(jù)庫(kù) 事務(wù)回滾 行鎖 unlock |
8 | 服務(wù)B | 執(zhí)行 | 數(shù)據(jù)庫(kù) 行鎖 競(jìng)爭(zhēng) |
不被人信任的滋味很難受!為了重新贏回測(cè)試妹紙對(duì)我的信任,這次的bug修復(fù)只需成功不許失敗!
四、解決方案
知道病根之后,問(wèn)題就很簡(jiǎn)單了。
最理想的方案
對(duì)微服務(wù)架構(gòu)進(jìn)行重構(gòu),但這樣做帶來(lái)的收益不高,現(xiàn)在手上還有優(yōu)先級(jí)更高的事情要做。

最實(shí)際的方案
是將服務(wù)A對(duì)服務(wù)B的調(diào)用和服務(wù)A的事務(wù)分離出來(lái)。這樣就不存在鎖競(jìng)爭(zhēng)的問(wèn)題了。

五、總結(jié)
看到了這里,你心里是不是已經(jīng)在想:我靠,大廠的系統(tǒng)架構(gòu)真的很垃圾,我都是關(guān)著燈的~(走錯(cuò)片場(chǎng)~)
其實(shí)這個(gè)系統(tǒng)變成這樣是有歷史原因的,如果當(dāng)初的開(kāi)發(fā)者能夠采用DDD的思想或者能夠明白微服務(wù)的對(duì)象高內(nèi)聚思想,或許今天就不會(huì)發(fā)生在我身上這場(chǎng)研發(fā)與測(cè)試之間的信任危機(jī)。
夕陽(yáng)落下,夜晚籠罩著大地。路旁的小貓咪悠然站了起來(lái),張大嘴巴打個(gè)哈欠的同時(shí)伸了個(gè)懶腰,然后走向3號(hào)門口,等待著心地善良的加班兒投食貓糧。“驗(yàn)證通過(guò),早點(diǎn)下班”。不遠(yuǎn)處傳來(lái)測(cè)試妹紙的聲音,夾雜著中央空調(diào)吹出的風(fēng)聲。
審核編輯 :李倩
-
macbook
+關(guān)注
關(guān)注
0文章
500瀏覽量
42233 -
線程
+關(guān)注
關(guān)注
0文章
508瀏覽量
20153 -
系統(tǒng)架構(gòu)
+關(guān)注
關(guān)注
1文章
72瀏覽量
23824
原文標(biāo)題:一個(gè)update語(yǔ)句執(zhí)行要10s,大廠的架構(gòu)真垃圾!
文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
基礎(chǔ)篇3:掌握Python中的條件語(yǔ)句與循環(huán)
淺談wsl --update` 命令行選項(xiàng)無(wú)效的解決方案
《ESP32S3 Arduino開(kāi)發(fā)指南》第三章 C/C++語(yǔ)言基礎(chǔ)
詳解TIA Portal SCL編程語(yǔ)言中的IF語(yǔ)句

hrtim里update reset和reset update同時(shí)打開(kāi)不會(huì)互相激勵(lì)嗎?
CPU的各種指令和執(zhí)行流程
ADC128S022的驅(qū)動(dòng)架構(gòu)參考 ti-adc128s052.c,要如何做移位生成12bit結(jié)果呢?
深入理解C語(yǔ)言:循環(huán)語(yǔ)句的應(yīng)用與優(yōu)化技巧

LM4890做了一個(gè)音頻功放電路,使用時(shí)發(fā)現(xiàn)4890不到10S鐘就非常燙接著就保護(hù)無(wú)聲了,是什么原因?
PCM2706C電腦端播放音樂(lè)后,點(diǎn)擊暫停出現(xiàn)10s左右的微弱噪聲如何解決?
TAS5805MPWPR輸出15W 10s后,芯片過(guò)熱保護(hù)了是什么原因?qū)е碌模?/a>
LTspice的編程語(yǔ)句應(yīng)該怎么寫?
想設(shè)計(jì)一個(gè)10Hz~10MHz的峰值檢波電路,請(qǐng)問(wèn)這個(gè)架構(gòu)可以達(dá)到我頻率范圍的要求嗎?
不到10塊錢,用Ai-M61-32S如何自制一個(gè)開(kāi)機(jī)棒?

使用ChatGPT解決開(kāi)發(fā)問(wèn)題

評(píng)論