一个update语句执行要10s,大厂的架构真垃圾!

文章来源:https://juejin.cn/post/7132454233638436901



目录

一、问题描述

二、问题分析

三、梅开二度

四、解决方案

五、总结



一、问题描述

    2022年7月2x日,窗外夕阳将落不落,余晖洒落在街道上,远处的热浪仿佛在说:嘿,欢迎来到烤箱中的瑞士卷—成都!

    “嘿!”,我回过神来看到一只洁白纤细的手落在我的肩膀上,眼光从窗外收回顺着手臂快速扭跟过去,然后看到脸色暗淡夹杂着些许痘痘的测试妹纸一脸的严肃!“昨天晚上上线后,这个后台执行更新信息非常缓慢,这里肯定有问题!”


二、问题分析

    “好的,我排查一下”。三步并作两步回到工位,掀开MacBook Pro的盖子、打开显示器的电源、输入链路日志跟踪系统地址、复制traceId、查看日志…… 这一套操作熟悉得令人心疼。

    排查日志初步发现实际调用了两次,第一次执行时间接近10s,调用超时,第二次执行时间接近5s。你肯定也想到了,RPC调用retry设置了值。对RPC配置检查之后确实设置的是retry=1,实际项目中,增、删、改等操作不应设置retry。

通过调用链排查发现update执行非常耗时。聪明的你一定也第一时间怀疑update语句有性能问题。把update语句拿出来:

update table set a=#{1},b=#{2},... where id =#{0} (id主键)

    这下傻眼了,根据主键id更新怎么可能要执行10s?

    masaga?!!

    为了验证我的猜想,command + 空格、键入idea并回车、打开对应的工程、定位到对应的方法处、迅速浏览一遍并思索片刻之后,真相大白!

8be63534b0588398ea42c871eb542829.jpeg

      服务B执行完update语句之后,事务commit之前,还有两个异步通知任务,使用的是spring的@Async注解,自定义的线程池,跟踪日志中的线程标志,排查过程中发现有的异步任务居然由原线程执行!进一步分析日志发现这种现象并不是一直发生,有时又是由异步线程执行。开始排查线程池,线程池果然设置了callRunner的失败策略。

    所以,由原线程执行时,事务的范围如下:

f894b8136debcb4e3a72332c12d1d603.jpeg

定位到原因之后,修改线程池参数为常见策略,初始和最大线程数相同,队列数9999,保证线程池的线程充足性。

    修复

    灰度

    招呼测试妹纸测试

    自信满满,悠闲喝水


三、梅开二度

    “在高并发场景下,复现了这个问题,你快看一下”!测试妹纸对我投来鄙视的眼光犀利的说道:“修复好了,再喊我回归哈,拜拜~”。

    奇怪,为什么这么平常的一个update语句,怎么会执行这么长时间呢?难道出发了框架的bug导致事务提交延迟?不对不对,这个方向想偏了~也没有其他地方在更新这个表了呀?不可能有表锁,更不可能有行锁呀……

masaga?!!

    根据表锁以及行锁的思路,为了验证我的内心OS猜想,立即使用 show processlist 进行了连接查询,果然有重大发现,除了服务B有连接之外,还有服务A的连接。而服务A又是服务B的上游系统!系统架构如下:

2fbcc4bcfdef37525425fa5d68a372b3.jpeg

执行顺序如下:

顺序服务执行动作关键点
1服务A执行update语句数据库 行锁 lock
2服务A调用服务BRPC 调用
3服务B执行update语句数据库 行锁 waiting
4服务A调用服务B超时RPC timeout
5服务A再次调用服务BRPC retry
6服务A调用调用服务B再次超时RPC timeout
7服务APRC调用超时异常数据库 事务回滚 行锁 unlock
8服务B执行数据库 行锁 竞争

不被人信任的滋味很难受!为了重新赢回测试妹纸对我的信任,这次的bug修复只需成功不许失败!


四、解决方案

    知道病根之后,问题就很简单了。

     最理想的方案

    对微服务架构进行重构,但这样做带来的收益不高,现在手上还有优先级更高的事情要做。

17df3abf1015125243beab0989f42726.jpeg

      最实际的方案

    是将服务A对服务B的调用和服务A的事务分离出来。这样就不存在锁竞争的问题了。

2533a8828bd6fe594ba186d80fa926be.jpeg


五、总结

    看到了这里,你心里是不是已经在想:我靠,大厂的系统架构真的很垃圾,我都是关着灯的~(走错片场~)

    其实这个系统变成这样是有历史原因的,如果当初的开发者能够采用DDD的思想或者能够明白微服务的对象高内聚思想,或许今天就不会发生在我身上这场研发与测试之间的信任危机。

    夕阳落下,夜晚笼罩着大地。路旁的小猫咪悠然站了起来,张大嘴巴打个哈欠的同时伸了个懒腰,然后走向3号门口,等待着心地善良的加班儿投食猫粮。“验证通过,早点下班”。不远处传来测试妹纸的声音,夹杂着中央空调吹出的风声。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值