0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

jf_ro2CN3Fa 来源:芋道源码 2023-01-29 10:45 次阅读


一、问题描述

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

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

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

二、问题分析

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

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

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

updatetableseta=#{1},b=#{2},...whereid=#{0}(id主键)

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

masaga?!!

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

06f25d70-9f73-11ed-bfe3-dac502259ad0.jpg

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

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

06fe1174-9f73-11ed-bfe3-dac502259ad0.jpg

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

修复

灰度

招呼测试妹纸测试

自信满满,悠闲喝水

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

三、梅开二度

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

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

masaga?!!

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

070c7a52-9f73-11ed-bfe3-dac502259ad0.jpg

执行顺序如下:

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

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

四、解决方案

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

最理想的方案

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

07185eda-9f73-11ed-bfe3-dac502259ad0.jpg
最实际的方案

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

072741ca-9f73-11ed-bfe3-dac502259ad0.jpg

五、总结

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

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

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



审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • macbook
    +关注

    关注

    0

    文章

    496

    浏览量

    41634
  • 线程
    +关注

    关注

    0

    文章

    503

    浏览量

    19634
  • 系统架构
    +关注

    关注

    1

    文章

    68

    浏览量

    23513

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

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    PCM2706C电脑端播放音乐后,点击暂停出现10s左右的微弱噪声如何解决?

    请教TI工程师,我的系统架构为PCM2706C + I2S DAC解码,到耳机输出, 出现的问题是电脑端播放音乐后,点击暂停出现10s左右的微弱噪声, 用逻辑分析仪可捕捉到这10s
    发表于 10-17 07:50

    TAS5805MPWPR输出15W 10s后,芯片过热保护了是什么原因导致的?

    TAS5805MPWPR输出15W 10s后,芯片过热而保护了。输出的喇叭是4欧,底下散热焊盘接触良好。
    发表于 10-15 07:38

    鸿蒙TypeScript入门学习第6天:【条件语句

    条件语句用于基于不同的条件来执行不同的动作。 TypeScript 条件语句是通过条或多条语句
    的头像 发表于 04-01 13:51 697次阅读
    鸿蒙TypeScript入门学习第6天:【条件<b class='flag-5'>语句</b>】

    assign语句和always语句的用法

    的用法和功能。 、Assign语句 Assign语句的定义和语法 Assign语句用于在HDL中连续赋值,它允许在设计中为信号或变量分配
    的头像 发表于 02-22 16:24 2148次阅读

    伺服电机低速运转时间长,或低速停10s,开10秒 , 会使电机过热或烧毁电机吗?

    伺服电机低速运转时间长,或低速停10s,开10秒 , 会使电机过热或烧毁电机吗? 还是低速运转需配减速机? 负载很小, 应该不会有扭矩不够的情况,会不会有低频振荡
    发表于 01-10 07:58

    单片机if是什么语句

    具有如下的结构: if (条件) { // 如果条件为真,则执行这里的代码块 } else { // 如果条件为假,则执行这里的代码块 } 在这个结构中,条件是逻辑表达式,它可以是
    的头像 发表于 01-05 14:04 1540次阅读

    单片机中for语句的运用

    单片机中的for语句种常见的循环控制结构,用于重复执行段代码块,可以简化程序的编写和减少代码量。本文将详细介绍单片机中for语句的运用
    的头像 发表于 01-05 14:02 2044次阅读

    oracle执行sql查询语句的步骤是什么

    Oracle数据库是种常用的关系型数据库管理系统,具有强大的SQL查询功能。Oracle执行SQL查询语句的步骤包括编写SQL语句、解析SQL语句
    的头像 发表于 12-06 10:49 875次阅读

    oracle update用法

    Oracle Update是Oracle数据库中的关键字,用于更新数据库表中的数据。 在Oracle数据库中,Update命令用于修改表中已存在的数据。该命令可以根据特定的条件来更
    的头像 发表于 12-06 09:57 3909次阅读

    oracle的update语法

    Oracle是种强大的关系型数据库管理系统,具有广泛的应用,UPDATE语句是用于修改数据库中现有记录的重要操作之。在本文中,我们将详细介绍Oracle的
    的头像 发表于 12-05 16:22 2250次阅读

    sql where条件的执行顺序

    SQL语句中的WHERE条件是用来筛选数据的,它决定了哪些数据会被返回给用户。WHERE条件的执行顺序是影响SQL语句性能的重要因素,正
    的头像 发表于 11-23 11:31 2105次阅读

    python if语句多个条件怎么用

    所有条件都必须为True才会执行if语句中的代码块,or运算符表示只要有条件为True就会执行代码块,而not运算符则用于反转条件的结果
    的头像 发表于 11-21 16:45 2825次阅读

    oracle怎么修改表中的数据

    修改 Oracle 数据库表中的数据可以通过使用 UPDATE 语句来实现。UPDATE 语句
    的头像 发表于 11-21 11:39 1930次阅读

    oracle更新clob字段sql语句

    在Oracle中,更新CLOB字段可以使用UPDATE语句。CLOB字段是用于存储大量文本数据的数据类型,可以存储最多4GB的数据。下面是些详细的信息和示例。 UPDATE语法:
    的头像 发表于 11-21 11:29 3910次阅读

    SELECT语句的基本格式

    列名 1 , 列名 2 , ..., 列名n FROM 表名; 在这个格式中, SELECT 关键字用于指示我们正在执行查询操作。紧接着是我们检索的列名,用逗号分隔。如果我们想
    的头像 发表于 11-17 15:10 2517次阅读