likes
comments
collection
share

数据库挂了导致的生产事故

作者站长头像
站长
· 阅读数 11

那是一个休闲的周六上午,我吃着面,突然看到工作群信息两条告警信息:1.生产数据库异常。2.下单业务连接数据库失败......不是吧阿sir,这种事都能让我碰到,手中的面突然不香了。接着领导信息接踵而来,我说赶紧先让运维重启数据库服务器吧,我也没权限操作数据库服务器呀。说完大量吸入手中的拌面,赶紧回家看看问题。

业务背景

数据库挂了导致的生产事故

数据库主从类似keepalived的机制,主从都安装keepalived,keepalived会定期检测心跳,主机器挂了会进行vip飘移。简单来说就是访问43VIP,就是访问41,检测到41挂了,就会进行VIP漂移和数据库主从切换。一开始是说vip没飘过去,我就说赶紧重启41。。不然没法玩,后面说已经飘过去了,43是能访问的,但是程序还是有问题。我还以为是43访问不了,那就和程序没有关系,原来还是有关系的....。然后运维重启了在线系统,问题解决。

数据库挂了导致的生产事故

问题定位

因为运维重启前没有打印线程快照,所以只能通过业务日志的时间去定位问题.....

首先记录几个时间:

故障发生时间 11:36:28 - 11:54:30

最后一次HTTP请求返回:11:37:13

路径:tomcat的logs目录下localhost_access_log.2023-03-11.txt

数据库挂了导致的生产事故

第一次系统报错时间:11:37:21

路径:catalina.out

数据库挂了导致的生产事故

确定在36分半的时候,数据库已经挂了,在线系统的请求全卡在请求数据库那里,然后坚持了差不多一分钟就无法处理请求了。系统卡了20分钟,重启后恢复。

故障分析

为什么获取数据库连接失败没有抛异常呢?

数据库挂了导致的生产事故

因为c3p0连接池的5秒超时被注释掉了。。为什么注释掉了呢,这要追溯到上一次的生产事故了...大概就是某一天的并发很高,然后系统网络又有点卡顿,导致数据库连接数满了,有一些连接请求数据库5秒后就抛异常了,最关键的是..系统try catch把异常吞了,导致没有触发重试机制。然后领导就觉得让他慢慢消费也可以,就注释掉了。这其实算是一个策略,数据库连接池满了到底怎么处理,如果是短时间内的堵塞,可以让他慢慢消费,如果是长时间的堵塞,就只能抛异常了。就要从结果来说还是要设置超时时间比较好,就不会导致请求堵塞。。

为什么会报C3P0的死锁?

网上搜c3p0 APPARENT DEADLOCK发现一大堆案例。我以为是因为这个死锁导致的系统崩溃,结果在本地环境能复现这个问题。我是本地搭了一个数据库,然后没有启动服务,连接池连不上就会报这个错误。

数据库挂了导致的生产事故

接着我尝试访问下单接口,看看多久返回

数据库挂了导致的生产事故

数据库挂了导致的生产事故

2分钟。。直接卡死

如果设置了超时时间

数据库挂了导致的生产事故

接着我再把本地数据库打开,系统正常访问,所以问题是和c3p0死锁没有关系,就是请求全堵塞了。

优化方案

  1. 设置超时时间5秒,虽然可能会抛弃一部分请求,但是不至于堵塞整个系统
  2. 业务拆分,把关键业务和非关键业务分开部署,现在是由于一个上报接口并发太高导致tomcat连接数和数据库连接数都用完了,后期还能根据业务拆分数据库。
  3. 加大tomcat连接和c3p0数据库连接数,现在tomcat默认200的连接数,c3p0最大设置200,要把这两个参数翻倍,让系统再坚挺一会儿。
  4. 数据库主从切换时间要更迅速一点,一分多钟才切换成功有点久了
  5. 告警出现值班运维要马上查看系统cpu和内存使用情况,如果出现异常需要记录下来,并打印线程快照,最后重启服务。

总结

由于主库挂了导致4台集群无法工作,就是因为一个超时时间的问题,也确实不应该。只能用要多想想一些特殊的情况,比如数据库挂了怎么办,线程池满了怎么办,http请求超时怎么办。一个大事故的发生都是多个小问题引起的。另外微服务思想也是重要的,不能因为某个小业务并发高导致系统堵塞。