前段时间,我们线上的MyCat数据库中间件出了一次故障,整个过程惊心动魄,从数据库连接打满、业务系统超时报警,到定位原因、紧急处理、恢复服务,花了好几个小时,也暴露了我们在数据库中间件运维上的很多问题。
MyCat是我们一直在用的数据库中间件,用来做分库分表和读写分离,线上的几个核心业务系统,都通过MyCat访问数据库。平时用得好好的,性能也不错,没想到那天突然出了故障,而且影响还不小,几个核心业务都受了影响。
今天来做一次完整的故障复盘,从故障发生、发现、定位、解决,到事后的反思和改进,详细记录整个过程,希望能给用MyCat或者其他数据库中间件的朋友一些参考,避免踩类似的坑。
一、故障发生
那天是周四,下午两点多,正是业务高峰时段,大家都在正常工作。突然,运维群里的告警响了,业务系统的接口响应时间超过了阈值,很多接口都超时了,错误率也在飙升。
一开始,我们以为是应用服务器的问题,或者是网络的问题,赶紧登录服务器看了一下,发现应用服务器的CPU、内存、负载都正常,网络也正常,但数据库的连接数很高,几乎打满了,而且很多连接处于等待状态,应用那边一直在报获取数据库连接超时。
我们赶紧去看MyCat的状态,发现MyCat的连接数也很高,后端的数据库连接池也满了,MyCat的日志里,大量的报错,都是"后端连接获取失败""连接超时""SQL执行超时"这些。这时候,我们意识到,可能是MyCat或者数据库出问题了。
更糟糕的是,随着时间的推移,影响的业务越来越多,几个核心业务系统都出现了超时和报错,用户开始反馈页面打不开、下单失败、查询不到数据,客服那边也开始接到用户的投诉。情况很紧急,我们赶紧拉了个紧急故障处理群,把DBA、运维、开发都拉进来,一起排查问题。
二、初步排查
首先,我们排查了后端的MySQL数据库,看看是不是数据库本身出了问题。登录到MySQL服务器上,看了一下数据库的状态,发现数据库的CPU和IO都不高,负载也正常,没有慢查询,也没有锁等待,数据库本身看起来是正常的,没有明显的性能问题。
那问题就出在MyCat这一层了。我们看了一下MyCat的运行状态,发现MyCat的进程还在,CPU和内存也不高,但连接数很高,前端的应用连接和后端的数据库连接,都几乎打满了,而且很多连接处于空闲状态,没有释放。
我们又看了一下MyCat的日志,发现了一个奇怪的现象:有大量的SQL,是同一个业务的查询,而且这些SQL的执行时间都很长,有的甚至超过了几十秒,还没有返回结果。这些SQL,把MyCat的后端连接都占住了,导致其他业务的SQL,获取不到后端连接,只能等待,进而超时,整个系统就卡住了。
那为什么这些SQL会执行这么长时间呢?我们把这些SQL拿出来看了一下,发现是一个分页查询的SQL,查询条件比较复杂,而且没有走索引,是全表扫描。但这个SQL,以前也经常执行,虽然慢一点,但也不至于几十秒不返回,为什么今天突然这么慢,还把连接都占住了呢?
我们又看了一下这个业务的访问量,发现今天这个业务的访问量,比平时高了很多,是平时的好几倍。原来是运营那边搞了一个活动,这个业务的查询量暴增,大量的慢SQL同时涌进来,每个SQL都要执行很长时间,占住一个后端连接,很快就把MyCat的后端连接池打满了,其他业务的SQL就获取不到连接了,只能等待,进而超时,整个系统就卡住了。
到这里,初步的判断是:某个业务因为活动,查询量暴增,大量的慢SQL同时执行,占满了MyCat的后端连接池,导致其他业务获取不到数据库连接,系统整体超时。
但问题还没完全搞清楚,为什么这些SQL会这么慢?以前也执行过,没这么慢啊?还有,为什么MyCat的连接池被占满之后,没有超时释放,一直占着?这些问题,需要进一步排查。
三、深入定位
我们继续深入排查,首先看了一下那个慢SQL的执行计划,发现确实是全表扫描,没有走索引,而且查询的表数据量很大,有几千万条数据,全表扫描的话,确实需要很长时间。但以前这个SQL也执行,为什么以前没这么慢呢?
我们问了一下这个业务的开发,才知道,这个业务的查询条件,最近加了一个新的筛选条件,这个条件没有对应的索引,而且这个条件的选择性很差,导致查询变成了全表扫描,性能急剧下降。但因为平时这个业务的查询量不大,虽然慢一点,但也能接受,就没太在意,也没加索引。今天活动一来,查询量暴增,大量的全表扫描SQL同时执行,就把数据库和MyCat都拖垮了。
然后,我们又看了一下MyCat的配置,发现了一个更严重的问题:MyCat的后端连接池,没有设置连接的最大空闲时间和执行超时时间。也就是说,一个连接被一个SQL占住之后,只要这个SQL不返回,这个连接就一直被占着,不会超时释放,也不会被回收。那些慢SQL,执行几十秒甚至几分钟,就一直占着连接,其他SQL就只能等着,直到连接池被占满,整个系统就卡住了。
而且,MyCat的前端连接,也没有设置超时时间,应用那边获取不到连接,就一直等,等到应用自己的连接池超时,才报错,这也导致了故障的影响范围扩大,持续时间变长。
还有一个问题,就是MyCat没有做SQL的限流和熔断,不管某个业务的SQL有多慢、有多少,都全部接过来,往后端数据库发,没有任何保护。一旦某个业务出现大量慢SQL,就会把整个MyCat和数据库都拖垮,影响所有业务,这就是典型的"雪崩效应"。
到这里,原因就完全清楚了:
- 某个业务最近加了一个查询条件,没有加索引,导致SQL变成全表扫描,性能很差。
- 运营活动导致这个业务的查询量暴增,大量的慢SQL同时涌进来。
- MyCat的后端连接池没有设置超时和回收,慢SQL一直占着连接,很快把连接池打满。
- MyCat没有限流和熔断,单个业务的慢SQL拖垮了整个中间件,影响了所有业务。
- 应用那边也没有设置合理的超时,一直等待,导致故障影响范围扩大,持续时间变长。
原因找到了,但问题还没解决,MyCat的连接池还是满的,业务还是超时,需要赶紧处理,恢复服务。
四、紧急处理
我们分几步来紧急处理:
第一步:先止住血,限制出问题的业务访问
当务之急,是先把那个出问题的业务的访问量降下来,不让更多的慢SQL涌进来,不然MyCat永远恢复不了。
我们做了两个操作:
- 联系运营那边,暂时把活动页面下线,或者把那个查询功能暂时关闭,减少这个业务的访问量。
- 在MyCat前面的网关层,对这个业务的接口做限流,只允许少量请求通过,其他的直接返回降级提示,防止大量请求继续打进来。
这两步做完之后,这个业务的访问量很快就降下来了,不再有新的大量慢SQL涌进来,算是止住血了。
第二步:重启MyCat,释放连接
止住血之后,MyCat里还是有很多被占住的连接,那些慢SQL还在执行,连接释放不了,MyCat还是卡住的。因为我们没有设置连接超时,那些连接会一直占着,只能等SQL执行完,或者手动重启MyCat来释放。
我们评估了一下,那些慢SQL,有的已经执行了好几分钟了,还不知道什么时候能完,等它们自己执行完,不知道要等到什么时候,业务等不起。所以,我们决定重启MyCat,强制释放所有连接,让MyCat恢复正常。
重启MyCat之前,我们先把应用那边的数据库连接池也重启了一下,或者把应用的流量先切走,避免重启的时候,大量请求涌进来,又把MyCat打满。然后,我们重启了MyCat的两个节点(我们部署了两个MyCat节点做高可用),重启之后,MyCat的连接数恢复了正常,后端连接池也空了,SQL能正常执行了。
重启之后,我们观察了一下,业务系统的接口响应时间恢复了正常,错误率也降下来了,用户那边也反馈系统恢复了。我们这才松了一口气,从故障发生到恢复,大概花了三个多小时,整个过程还是很惊心动魄的。
第三步:紧急加索引,优化SQL
恢复服务之后,我们没有掉以轻心,因为那个慢SQL的问题还没解决,如果活动再上线,或者访问量再上来,还会出同样的问题。所以,我们紧急处理了那个慢SQL。
首先,给那个查询条件加了索引,因为是大表,加索引花了一些时间,而且是在线加索引,要注意不要影响业务。加完索引之后,我们测试了一下,那个SQL的执行时间,从几十秒降到了几十毫秒,性能提升了几百倍,问题解决了。
同时,我们也检查了一下其他业务的SQL,看看有没有类似的慢SQL,没有索引的,或者全表扫描的,都赶紧加了索引,做了优化,避免再出类似的问题。
第四步:验证和观察
处理完之后,我们继续观察了一段时间,看MyCat和数据库的运行状态,看业务系统的响应时间和错误率,确认没有问题。同时,也让运营那边,把活动页面慢慢恢复上线,观察访问量上来之后,系统是不是稳定。
观察了大概两个小时,系统运行稳定,MyCat的连接数正常,数据库的负载正常,业务接口响应时间正常,没有再出现超时和报错,我们才确认故障完全解决了。
五、故障暴露的问题
这次故障,虽然最终解决了,但也暴露了我们在数据库中间件运维和系统开发上的很多问题,值得好好反思。
1. SQL审核和优化不到位
这是最根本的问题。那个慢SQL,加了查询条件,没有加索引,就直接上线了,说明我们的SQL审核和优化流程不到位,上线前没有检查SQL的执行计划,没有发现全表扫描的问题,也没有做性能测试,导致有性能问题的SQL直接上线,平时访问量小的时候没暴露,一到大流量就出问题了。
而且,我们也没有定期巡检慢SQL的机制,数据库里的慢查询日志,没有人定期看,那个SQL慢了很久了,也没有人发现和优化,直到出了故障才知道。
2. MyCat配置不合理,没有超时和保护机制
MyCat的配置,有很大的问题,后端连接池没有设置连接的最大空闲时间和执行超时时间,连接被占住之后,不会超时释放,一直占着,很容易被慢SQL拖垮。前端连接也没有设置合理的超时,应用一直等待,导致故障影响扩大。
而且,MyCat没有做SQL的限流和熔断,单个业务的慢SQL,能拖垮整个中间件,影响所有业务,没有隔离和保护机制。这说明我们对MyCat的配置和性能调优,了解得不够深入,很多关键参数都用的默认值,没有根据业务情况做优化。
3. 没有容量规划和压测
我们对MyCat和数据库的容量,没有做过详细的规划,也没有做过压力测试,不知道系统的瓶颈在哪里,能承受多大的流量,什么情况下会出问题。运营搞活动,流量暴增,我们也没有提前评估,没有做压测,没有做预案,导致流量一上来,系统就扛不住了。
4. 监控和告警不完善
虽然这次故障,我们是通过告警发现的,但告警还是太晚了,是业务系统超时了才告警,这时候故障已经发生了,已经影响用户了。如果能更早地发现问题,比如MyCat连接数升高的时候就告警,或者慢SQL增多的时候就告警,就能提前处理,避免故障扩大。
而且,我们的监控维度也不够,没有监控MyCat的连接池使用率、后端连接状态、SQL执行时间这些关键指标,出了问题之后,还要手动去查,不能快速定位原因。
5. 应急预案和演练不足
这次故障,我们是临时排查,临时想解决方案,没有应急预案,也没有操作手册,走了不少弯路。比如,刚开始的时候,不知道怎么快速释放MyCat的连接,查了半天资料,浪费了不少时间。如果有应急预案和操作手册,遇到类似的问题,就能按照预案快速处理,节省时间,减少影响。
而且,我们也没有做过故障演练,不知道MyCat挂了之后,怎么快速恢复,怎么切换,出了问题才手忙脚乱的。
6. 业务之间没有隔离
所有的业务,都共用同一套MyCat和数据库,没有做隔离,一个业务出问题,就会影响所有业务,这就是"雪崩效应"。如果能做业务隔离,不同的业务用不同的MyCat节点,或者不同的连接池,一个业务出问题,不会影响其他业务,故障的影响范围就会小很多。
六、后续改进措施
针对这些问题,我们做了一系列的改进措施,避免以后再出类似的问题。
1. 建立SQL审核和优化流程
我们建立了严格的SQL审核流程,所有上线的SQL,都必须经过审核,检查执行计划,确保走了索引,没有全表扫描,没有性能问题。复杂的SQL,必须做性能测试,确认性能达标才能上线。
同时,我们也部署了慢SQL监控和告警,数据库的慢查询日志,自动收集和分析,有慢SQL就告警,通知相关的开发及时优化。每周做一次慢SQL巡检,把所有的慢SQL都列出来,督促优化,避免积累太多的慢SQL,埋下隐患。
2. 优化MyCat配置,加超时和保护机制
我们重新梳理和优化了MyCat的所有配置,重点加了这几个:
- 后端连接池,设置了连接的最大空闲时间和执行超时时间,SQL执行超过一定时间,自动中断,释放连接,避免慢SQL一直占着连接。
- 前端连接,设置了合理的超时时间,获取连接超时,或者执行超时,快速失败,不让应用一直等待。
- 配置了连接池的监控,连接数超过阈值就告警,提前发现问题。
- 研究了MyCat的SQL限流和熔断功能,对核心业务和非核心业务做了区分,非核心业务的SQL,在系统压力大的时候,可以限流或者降级,保护核心业务。
3. 做容量规划和压力测试
我们对MyCat和数据库,做了详细的容量规划,测试了系统的性能瓶颈,知道了能承受多大的QPS,多大的连接数,什么情况下会出问题。根据容量规划,合理配置资源,预留足够的余量。
同时,我们也建立了压测机制,每次大的活动或者上线之前,都要做压力测试,评估系统能不能承受活动的流量,如果不能,就提前优化,或者做扩容,避免活动的时候出问题。
4. 完善监控和告警
我们完善了MyCat的监控,增加了这些监控指标:
- MyCat的连接数、连接池使用率、活跃连接数、空闲连接数
- 后端数据库的连接数、执行时间、慢SQL数量
- SQL的执行时间分布,慢SQL的数量和内容
- MyCat的CPU、内存、网络、IO
针对这些指标,设置了合理的告警阈值,比如连接池使用率超过80%就告警,慢SQL数量突然增多就告警,这样就能在故障发生之前,提前发现问题,及时处理,避免故障扩大。
5. 制定应急预案和操作手册
我们针对MyCat可能出现的故障,制定了详细的应急预案和操作手册,包括:
- 连接池打满的处理流程
- 慢SQL导致系统卡住的处理流程
- MyCat节点挂了的处理流程和切换步骤
- 数据库故障的处理流程
- 各种常用操作的命令和步骤,比如重启MyCat、查看连接、杀掉慢SQL等
有了应急预案和操作手册,以后再出类似的问题,就能按照预案快速处理,不用临时想方案,节省时间,减少影响。同时,我们也定期做故障演练,模拟各种故障,测试应急预案的有效性,也让大家熟悉故障处理的流程,出了问题不慌。
6. 做业务隔离和架构优化
我们开始推进业务隔离,把不同的业务,拆分到不同的MyCat节点,或者不同的连接池,避免一个业务出问题,影响所有业务。核心业务和非核心业务,做了隔离,非核心业务出问题,不影响核心业务。
同时,我们也在评估,对一些特别重要的业务,是不是不用MyCat,直接连数据库,或者用更稳定的分库分表方案,减少中间件的依赖,降低风险。当然,这个是长期的优化,需要逐步推进。
7. 加强团队培训和意识
这次故障,也反映了团队对MyCat和数据库的了解不够深入,很多人不知道MyCat的配置参数,不知道怎么排查问题。我们组织了培训,让大家深入学习MyCat的原理、配置、运维和故障排查,提高团队的技术能力。
同时,也加强了大家的线上安全意识,上线前要做好测试和审核,不能随便上有性能问题的SQL,运营活动要提前评估,做好预案,不能临时搞活动,把系统搞垮了。
七、经验和教训
这次故障,给我们带来了很多经验和教训,也分享给大家。
1. 数据库是系统的核心,一定要重视
数据库是系统的核心,数据库出了问题,整个系统都会受影响,而且恢复起来也比较麻烦。所以,一定要重视数据库的运维和优化,SQL审核、慢SQL优化、索引优化、容量规划、监控告警,这些都要做好,不能等出了问题才重视。
尤其是用了数据库中间件之后,中间件本身也成了一个核心组件,中间件出问题,也会影响整个系统,所以,中间件的运维和优化,也同样重要,不能只关注数据库,不关注中间件。
2. 慢SQL是万恶之源,一定要消灭
很多数据库故障,都是慢SQL引起的,一个慢SQL,就能把数据库和中间件拖垮,影响整个系统。所以,一定要重视慢SQL,上线前严格审核,上线后持续监控,发现慢SQL及时优化,不要等积累多了出问题。
而且,慢SQL的危害,平时访问量小的时候看不出来,一到大流量、活动的时候,就会集中爆发,所以,平时就要把慢SQL都优化掉,不要等到活动的时候才发现,那就晚了。
3. 任何中间件都要有超时和保护机制
不管是数据库中间件,还是其他的中间件,一定要配置合理的超时时间,连接超时、执行超时、读超时、写超时,都要设置,不能用默认值,也不能设置得太长。超时机制,是系统的保护网,出问题的时候,能快速失败,释放资源,避免故障扩大。
同时,也要有限流、熔断、隔离这些保护机制,防止单个业务的问题,拖垮整个系统。没有保护机制的系统,就像没有保险丝的电路,一个地方短路,整个系统都会烧掉。
4. 监控告警要提前,不要等故障发生了才告警
监控告警,一定要提前,要在故障发生之前,就能发现异常,及时处理,而不是等故障已经发生了,用户已经受影响了,才告警。要监控关键的指标,设置合理的阈值,提前预警,把故障消灭在萌芽状态。
而且,监控的维度要全,不仅要监控应用和数据库,还要监控中间件、网络、服务器等各个层面,出了问题能快速定位,不用一个个去猜。
5. 应急预案和演练很重要
任何系统,都可能出故障,重要的是,出了故障之后,能不能快速恢复,减少影响。所以,一定要有应急预案和操作手册,并且定期做故障演练,让大家熟悉故障处理的流程,出了问题不慌,能按照预案快速处理。
很多团队,平时不做预案,也不演练,出了故障才手忙脚乱,临时想方案,走很多弯路,浪费了很多时间,扩大了故障的影响。这一点,一定要重视。
6. 大流量活动一定要提前评估和准备
很多故障,都是在大流量活动的时候发生的,因为平时流量小,很多问题暴露不出来,一到大流量,所有的问题都集中爆发了。所以,大的活动之前,一定要做评估,做压测,做预案,准备好扩容和降级方案,确保活动的时候系统稳定。
不能临时搞活动,不做任何准备,直接上线,那样很容易出问题。活动之前,要和技术团队沟通,评估系统的承载能力,做好准备,才能保证活动顺利进行。
八、写在最后
这次MyCat故障,虽然过程惊心动魄,影响了几个小时的业务,也给用户带来了不好的体验,但也给我们上了生动的一课,让我们意识到了数据库中间件运维的重要性,也推动我们做了很多改进,从长远来看,是有价值的。
故障复盘,不是为了追究谁的责任,而是为了从故障中学习,找到问题,改进问题,避免以后再出类似的故障。每一次故障,都是一次成长的机会,只要我们认真复盘,持续改进,系统就会越来越稳定,越来越可靠。
最后,希望这篇故障复盘,能给用MyCat或者其他数据库中间件的朋友一些参考,也希望大家都能重视数据库和中间件的运维,做好SQL优化、配置优化、监控告警、应急预案,避免踩类似的坑。也欢迎大家在评论区分享自己遇到过的数据库中间件故障,一起交流学习。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录