大型商用平台线上数据库故障恢复纪实
一切要从2023-12-13早上说起。
每周的1、3、5早上09:15,是我带的项目固定开晨会的时间。从2021年到现在,只取消过两次,一次是阿根廷夺得世界杯次日的早上,一次是v3.4版本发布,攻关解决harbor问题到凌晨03:30,早上太多人缺席,没有开晨会。
12-13早上,照例开完晨会,用户从各种渠道反馈,现网的报表查询功能严重卡顿,查询结果半个小时都无法生成。运维同事反馈,存储报表数据的clickhouse的数据库连接冲到了400个以上,内存也在飙升。临近年底考核,用户需要查询报表分析他们的经营数据,服务出现长时间异常很容易引起客户的不满情绪。
开发同事分析发现,查询clickhouse数据库卡顿主要是三个慢查询语句造成的,这三个语句已经执行了将近1个小时。按照之前的经验,只要这三条报表查询语句顺利执行完,数据库性能将快速恢复。但是,现在不是平常,是年底考核的关键时期,用户对服务异常的忍耐程度是不一样的。
谈到服务稳定性,通常是4个9或者6个9这种指标,达到4个9一年服务不可用的时间不能超过若干分钟等等。现实情况,在不同时期,用户对服务稳定性的要求是不一样的,甚至差别很大。数年前在一家通信公司,公司的产品支撑欧洲某国客户4G通信,承诺的一年服务不可用时间不超过24小时。该产品研发过程质量要求很高,发布后也很稳定,但是偏偏2012年欧洲杯决赛那天业务出现了若干小时的中断,虽然最终全年的服务不可用时间达标了,但是热爱足球的欧洲客户还是表达了强烈的不满情绪,给公司名誉造成了不好的影响。
所以,这次的服务卡顿问题要快速解决,不能再等!
既然服务卡顿的原因很清楚,是那三条慢查询导致的服务雪崩,那么解决问题的策略很简单:“停止这三条慢查询,让其他请求得到响应”。
如何停止这三条慢查询?
使用clickhouse的命令,kill掉正在执行的语句,不起作用。
运维同事给了一条命令,可以看到当前clickhouse正在执行的查询进程。在数据库表里查看,pid也能对应上。这时候已经是上午10:30了,负责运营的同事已经快顶不住用户的轮番轰炸了,这种压力也传递到了运维和研发团队。
确认下是不是这个进程?是的。好,杀掉这个进程!
正是这条kill语句造成了接下来将近60个小时的艰辛,暂且不表。
什么?kill这个进程导致整个clickhouse server进程成为僵尸进程了?
完了,情况变的更糟了。。。
从事过软件开发的读者们都知道僵尸进程意味着什么,意味着只能重启服务器了。。。
这时候是2023-12-13 上午10:45分
没有办法,联系运维同事重启服务器。
5分钟后,服务器正常启动了,但是数据库怎么都启动不了了。
这时候已经是2023-12-13 上午11:00
唯一令人欣慰的是,clickhouse数据库上线时做了读写分离,现在不可用的是读节点,写节点还能正常工作。
不能再等了,必须要拿出紧急预案了。
商用系统的复杂就在于你通常面临的不仅仅是一个技术问题。战场上射击和靶场打靶完全是两个概念。
和研发、运营、运维做出紧急预案如下:
- 给用户发布道歉通知,当前用户查询请求量较大,造成服务暂时不可用,团队正在紧急恢复,请大家耐心等待。
- 用户线下将查询需求反馈给运维同事,如果查询数据范围较小,能够保证命中索引的,运维同事在后台连接clickhouse写库查询响应客户;其他查询需求暂不响应。
- 停止后台所有使用clickhouse的非关键业务,保证clickhouse写库稳定
实施三条紧急预案后,继续寻找恢复写库的方案。
尝试再次启动数据库,经过多次尝试后,谢天谢地,这次数据库正常开始启动了,但是启动后一直连接不上。
这时候已经是下午15:00了,有午休习惯的处理故障的同事,脸上写满了疲惫,思路感觉也不太清晰了。
下午15:30,数据库还是连接不上,查看日志发现数据库在反复重启。报错日志有很多Error,有的问题能找到解决方案,有的Error查了官方文档,问了chatgpt,看了源码也没有思路。团队的clickhouse专家这时候说,clickhouse反复重启是因为启动设置的超时时间太短了,是否将这个时间修改的长一些,暂时先忽略那些Error日志?
没有更好的办法,先这么干。
将启动超时时间延长后,数据库终于成功启动了,也能正常连接了,但是查询速度很慢。我们几个紧急处理故障的几名同事都乐观的认为,数据库刚启动,几个T的数据还在加载中,需要一个过程,从后台看也有数据加载的打印,和大家的分析能对应上。我们唯一能做的就是等待。
等数据全部加载完成,这个问题应该就解决了。紧急处理故障的几名同事开始投入其他工作任务。
这时候是12-13号下午18:00
但是,接下来发生的事情说明我们还是太乐观了,更多的挑战的还在后面,当前遇到的问题只是个开始。。。
12-13号晚上21:00
看了下clickhouse server的日志打印,还在加载数据,留在公司似乎也只能等待,决定让大家回家,带着笔记本回,晚上23:00再看看。
12-13 23:00
后台打印还是在加载数据,同时也有很多Error,很多无能为力的Error, 数据库能连接,也能查询,但是很慢很慢。
2023-12-14 早上09:00
到公司后,发现后台没有加载数据的打印了,但是还是有很多Error,数据库能连接,也能查询,但是还是很慢。
更糟糕的是,安装数据库的这台机器的cpu,内存,IO指标都很高,整个集群也不太正常,怀疑是这台机器对共享存储的不正确使用导致的。
运维同事反馈,这台机器必须得停掉了,不然整个集群都有down掉的风险。
两害相权从其轻,停掉了这条机器,集群状态果然正常了!
接下来怎么办?
只能新建读库节点了,从写库同步数据。
运维同学重新给分配了一台机器。
安装clickhouse数据库,配置zookeeper,等等,一切就绪,开始同步数据,先同步一张只有25条记录的表,瞬间成功!这说明我们的方案是可行的!
这时候是2023-12-14 中午13:40
办公室其他同事都在午休,我、XB,XL到公司楼下对面的牛肉拉面馆各自点了一碗拉面。边吃边复盘这次故障处理过程,预计最晚下午18:00可以恢复所有的服务。
吃完拉面,立刻回到办公室接着干。还有2张表,一张表31G数据,一张表744G数据。
先同步31G数据的表,大约20分钟完成。
开始同步744G这张表,刚开始的半个小时同步速度很快,半个小时后同步速度下降很明显,但是鉴于操作的重要性,我们也不敢做什么干预动作,只能等。
一直到晚上21:00,
clickhouse读库的server日志开始出现大量连接超时问题,IO流入指标也很低,这说明数据同步基本暂停了。
尝试重启clickhouse读库,启动失败,又出现了僵尸进程,只能重启机器。
重启机器后,clickhouse启动成功,数据同步开始恢复,IO流入指标也增长很明显。
今晚24点前回家可能有戏!
不停刷新数据同步进度,总共4亿7千万条数据,到23点时同步完成17万条。
24点可能回不了了,楼下的保安数次上来问,你们还回不?
接近2023-12-15 零点时让XB、YQ先回,我和XL在公司继续观察。
YQ回家后不放心,开了个视频会议和我们一起分析。
2023-12-15 凌晨2点
数据同步完成370万条,距离4亿7千万还差很远。凌晨2点,系统的各种定时任务开始执行,出现资源抢占,clickhouse数据同步又几乎停滞。
2023-12-15 凌晨2点30分
系统的各种批量任务顺利执行完成,但是clickhouse数据同步速度也没有恢复。server日志再次出现大量连接超时问题。
尝试在运维群里问了下,是否有值夜班的同事?很快有运维人员回复,再次帮我们重启读库机器。
重启很顺利,重启后数据同步速度也开始恢复。
但是,几乎又是重启半小时后,数据同步速度开始下降,一直到凌晨5点,完成大约2000万条数据同步,距离4亿7千万仍然很远。
2023-12-15 05:30
我自己不敢再撑着了,也不敢再让团队的小伙伴撑着了,撑着也没有意义。安排大家休息。
数据同步这条路看来也走不通了,需要思考新的解决方案。
数据同步为何失败?
因为这张表数据量达到了4亿7千万,744G。
这张表为何数据量这么大?
因为有两个json大字段。
这两个大字段是否可以不同步?
90%以上的业务场景不需要这两个字段,少数场景需要。
那么,是否可以不同步这两个字段?90%的业务场景查询读库,剩余10%的场景查询写库。
和XL讨论到这里,又兴奋了起来,似乎是一个可行的解决方案。
- 在写库新建表A_lite, 表结构和巨量数据的A表一致
- 在写库将A表中除了两个大json字段的其他字段拷贝到A_lite表
- 在读库新建A_lite表,新建后写库的的A_lite表数据会自动同步到读库A_lite表,不再同步A表到读库
- 修改上层业务代码,消费读库A表数据的逻辑修改为消费A_lite表
- 在写库,每日定期同步A表数据到A_lite表,写库的A_lite表数据会自动同步到读库的A_lite表。
不过还是先休息,休息一会儿再说。
2023-12-15 07:30
在办公室的午休床上睡到早上7:30,被冻醒了。和XL下楼吃早餐,一碗胡辣汤下肚,暖和了不少。
回到办公室开始实践05:30想出来的方案,很顺利,排除那两个大json字段后,同步一天的数据一分钟内可以完成。根据业务要求,我们同步过去45天的数据即可。
2023-12-15 09:00
团队人员都上班了,组织会议分析新方案各个模块的改动点。
2023-12-15 16:00
45天数据同步完成,至此clickhouse数据库问题得到解决!
2023-12-15 17:00
各个模块改动完成,验证通过,部署上线,给客户恢复查询服务。
历时两天多的问题紧急攻关顺利完成。
整个问题解决过程中,写库一直在线,因此并没有对用户的业务造成影响。读库无法响应,用户的查询请求通过让运维人员后台查询写库的方式基本得到满足。
写到这里,其实我想说一些什么,但是又说不出来,本身这份工作就是打工赚钱,达不到保家卫国这种高度,谈不上有多高尚,没必要标榜自己。商用系统的复杂度懂的人自然懂,没有亲身经历的HelloWorld从业者也懂不了。存储1万条数据的经验理解不了存储10亿条数据的复杂度。