记录一个诡异的线上宕机事故,大佬们帮忙排查一下问题呀

2021-09-09 11:48:14 +08:00
 teliang

环境

二三十个微服务 SpringBoot+Dubbo 部署在阿里的 K8S 上,数据库也是买的阿里的 RDS,听领导说配置还挺高的,支持主备自动切换什么的。

事故起因和经过

大版本上线,改了用户的缓存数据结构,凌晨上线时把 Redis 用户缓存全清了,上线当晚验证功能正常,白天运行也十分稳定。

下午 5 点多业务高峰的时候运营反馈系统蹦了,看后台是数据库负载正常、Dubbo 调用全部超时,领导首先怀疑是系统被攻击了,然后在阿里的后台打开了防火墙增强模式(具体叫什么不懂,效果是可以阻拦大部分到 Nginx 的请求),开完观察了好久后台调用还是超时,老板都开始炸锅了跑来了解情况,领导开始尝试万能的重启大法,ZK 的三个节点都重启了,微服务也挨个重启,绝望的是重启依然没有任何效果。

一顿瞎搞时间很快就到了晚上 8 点,这时候已经宕机 2 个多小时了还没找到原因,也不知道怎么恢复。然后我试着用 Arthas 监控了一下调用时间,发现主要业务流量入口 M 服务调用 Cache 服务一直超时,调用 C 主要是 M 从 Redis 获取不到用户缓存,需要 C 构建缓存放 Redis 。监控 C 服务的时候发现所有请求数据库的耗时都要 2000ms 以上,然后我们构建缓存需要读 8~9 次数据库但是 Dubbo 的超时时间设的是 10s 所以一直超时。

诡异事件

首先怀疑是 SQL 写的有问题,但是有一个根据主键 ID 查询单表的居然也要 2000+ms,这就非常离谱了,后面我把参数打出来自己拼接 SQL 用 Navicat 查询只要十几毫秒,领导说可能是工具监控有问题,然后当场给这个查询加调用时间的日志验证,从 master 拉的分支,只加了一行日志!!!

然后,重新发包观察,诡异的是,系统恢复正常了!!!没有调用超时的日志,新加的那行日志打印出来的也是十几毫秒,其他服务也能正常调用了!!!

事故报告

领导给的事故报告是晚上清除用户缓存,没有预先跑脚本构建缓存导致业务高峰期系统宕机。

疑惑

为什么那个时间点 Navicat 和微服务查询同一条 SQL 时间差这么多?然后加了行日志系统又自动恢复了?诡异,太诡异了,说没有鬼我是不信的

大佬们来帮忙排查一下这可能是什么原因呀

10416 次点击
所在节点    Java
81 条回复
huangmingyou
2021-09-09 11:51:15 +08:00
skywalking 这样的 apm 软件有吗,或者阿里云自己的 apm ; 微服务调用链很复杂的,需要这些工具。
villivateur
2021-09-09 11:54:45 +08:00
你这还不算奇怪的,我甚至遇到过加一行注释,问题就突然消失了的
teliang
2021-09-09 11:56:27 +08:00
@huangmingyou 没有这些工具。。。
chendy
2021-09-09 11:56:53 +08:00
看看 mysql 慢查,看看有没有相关的查询(可能没有)
可能是应用和数据库之间的网络出了什么问题
或者应用的连接池配置有问题
或者是有其他的慢查询拖住了连接池导致后续请求要排队
可能的点很多很多,慢慢查吧。。。
kaiger
2021-09-09 11:58:03 +08:00
@villivateur 这就离谱。。。
soupu626
2021-09-09 12:01:39 +08:00
服务 sql 慢,本地查着快
怀疑有其他的慢 sql 把服务的数据库链接池打满了?
导致你这个简单 sql 拿不到链接,大量耗时其实是在等待链接,执行时间其实很快和你的本地连上去查是一样的
akira
2021-09-09 12:02:13 +08:00
和这行代码有关的可能性几乎是 0
现在移除掉这行代码 估计也是正常的
zoharSoul
2021-09-09 12:46:00 +08:00
应该是连接池被某个 sql 占满了.
导致正常 sql 也要 2000+ms 才拿到连接并执行, 但是执行是很快的.
你本地 nativecat 快也是因为这个,
HiShan
2021-09-09 12:49:11 +08:00
蹲一个后续 )
defunct9
2021-09-09 12:56:12 +08:00
开 ssh,让我上去看看
huangmingyou
2021-09-09 13:11:30 +08:00
看 mysql slow log; 把怀疑的微服务停掉
gBurnX
2021-09-09 13:13:46 +08:00
当复杂系统,不容易及时排查出问题时,其实可以留一手:粗暴的监控大法:

1.能输出日志的 app,全部监控起来。

2.把你们自己写的程序里,每个函数、接口与数据库 rpc 、List/Queue/Cache 等 size,全部监控起来。

3.把 OS 、nginx 、iis 、db 等各种队列 /缓存 /容器 size,全部监控起来。

然后当 size 接近 total lenth 的 80%,以及 rpc 时间超过 3s 时,在监控面板报警。

性能问题,基本上就是这些,监控好了,就不会出现诡异问题了。
opengps
2021-09-09 13:21:10 +08:00
只看表象可以先推测一个可能的原因:直接清空缓存导致的缓存逻辑缺陷。
然后导致访问穿透缓存直达数据库,延伸到数据库压力过大,这个推测符合你说的单条查询也慢,至于重新发包回复,则往往是中断了慢查询占用的连接数等因素可能性比较大
opengps
2021-09-09 13:21:42 +08:00
简单来说,排查一下那些缓存时更新当晚没有及时回填的,可能会找到问题根源
teliang
2021-09-09 13:26:37 +08:00
@chendy
@soupu626
@zoharSoul
@opengps
@gBurnX
贴了个图,同一个 service 方法多次查询数据库不用每次都从连接池拿吧,应该是复用的才对呀
zoharSoul
2021-09-09 13:33:16 +08:00
@teliang #15 这要看是不是在一个事务里
Digitalzz
2021-09-09 13:42:48 +08:00
有没有用 Arthas 查看进入 Mapper 里的具体方法,这里面应该就可以看到是否是获取连接等到太长等问题。

或者说你们的 RDS 上是否可以看到当天连接数量的使用趋势图。
cxh116
2021-09-09 13:46:36 +08:00
看 web server 的线程数是不是大于数据库连接池的数量?
比如 web server 平常响应很快, 数据库连接很快释放回池.
但因某个查询慢,导致连接释放慢, 在数据连接不够时,其它 web 线程就要等池的连接释放才能够查询. 这就解释为什么 web server 查询慢,但 nativecat 查询快.
只是一种可能,对 java 相关的不太熟悉,供参考.
opengps
2021-09-09 13:46:59 +08:00
@teliang 是不是同一个查询链接跟是否同一个方法没有直接关系。这得看数据库访问层面是否同一个数据库查询实例之类的。虽然现在已经恢复了,不过你应该依然可以从 rds 后台查询到故障时段的 iops 指标,硬盘读写指标
liyunyang
2021-09-09 13:56:45 +08:00
"贴一个监控调用的数据,信息尽量都脱敏了,这是 C 服务 buildUserCacheData 的监控,时间都超过 20 秒了"

问一下楼主这个监控使用什么做的,准备给公司设计一个微服务的监控方案

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/800791

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX