消息队列 | 服务升级翻车导致的血泪教训
消息队列 | 服务升级翻车导致的血泪教训
前言
题目为什么叫“消息队列 | 服务升级翻车导致的血泪教训”,一个重要原因是我的解决有些理念和前面我讲的这种消息队列的架构模式很像,因为我当时确实想到的就是消息队列削峰填谷的作用,虽然我用的是定时任务,但也确实实现了异步的处理过程,大同小异,大同小异,毕竟在线修bug
,要求不能太高,要啥自行车😂
事情经过
事情经过是这样的:最近我们服务升级,因为升级前没有考虑影响范围,没有做相关准备工作,所以升级的第二天,整个业务系统就炸锅了,升级的那个业务系统所有服务基本上五分钟就宕机一次,影响特别严重。
首先升级这件事,除了升级的同事知道,其他人都不知道这个事,所以也没有进行过内部讨论,所以也就不存在应急方案,因为升级过程修改了核心表数据,还没做备份,所以也就意味着升级过程不可逆,升级只能成功,不能失败,风险是不是很大,我也只能说心大、胆大,让我这么搞,提交的时候我会手抖,我怕我一下终结了自己的职业生涯。
然后升级的第二天我请假,当我早上得知升级这个事的那一刻,我就知道完了,这回要炸锅了,然后虽然这个问题不是因我而起,但作为项目上的技术担当(请允许我装个13
,渣渣😂),休假那天晚上我还专门总结了,然后想了一些解决方案,刚开始以为服务宕机是因为没有缓存的问题,上班才知道是请求并发量太大,服务根本就扛不住。
先介绍下这个接口,这个接口是这个系统最基础的接口,调用方在调用其他业务接口之前,必须通过这个接口上传自己的基础数据,本次升级导致所有已经上传的数据全部作废,也就是说所有的调用方都必须重新上传,升级前已经上传的数据量是400W
,算上系统处理过程的数据,应该在400W*20W*调用方数量
,调用方大概3000~5000
,当然这个并发量对现在微服务架构的系统而言,应该是扛得住的,但是我们的系统还是单体架构,虽然做了负载,用的还是F5
,但是没啥卵用,还不如我用nginx
做的,渣渣负载加渣渣系统,最终的结果只有一个——升级当天就被吊打,按到地上摩擦。那一天,我的兄弟们当了一天的人肉运维,五分钟重启一次服务(小声逼逼🤭,还好我请假了)。
上班以后,我首先想到的解决方案是接口限流,采用分批限流的方式,也就是一个调完一个掉,但是效率还是低,而且最主要的是服务依然不稳定,还是会宕机,而且好多调用方反馈调用超时,然后我采取了第二步:优化负载。
我优化的方式很简单,就是在原有负载的基础上,针对请求量过大的服务采用二次负载,即将负载之后请求量依然大于其他服务的应用的请求再次分配到其他几个服务上,负载模式也很简单,就是简单轮询,这时候还是有调用方反馈调用超时。
这时候我分析了业务代码,发现是数据上传之后的业务处理时间过长,导致调用超时,所以我的解决方案就是拆分业务,他原来的业务处理流程就是我们前面说的串行方式,也就是数据上传成功后,需要等后续的数据处理完成后才会返回上传结果,但是由于调用量大,而且后续操作耗时特别长,根据后续的监测,发现部分数据查询就需要200s
,还不算四五层for
循环,而且循环次数取决于数据量。在整个业务处理过程中,调用方关注的是上传结果,调用这个接口只是上传数据,至于上传数据之后的处理和他们无关,主要是他们并不需要实时获取处理结果,但就是这些无关的业务操作,导致最终调用超时。
所以最后,我把业务拆成两部分,一部分就是数据上传,一部分是后续数据处理,前一部分放在原有接口中,后一部分我通过定时任务来跑。肝到12点,整个方案终于搞完了,测试也没有问题了,然后发布上线,服务终于稳定了,调用方反馈反应也快了很多,再没有超时的了。在后续的数据处理服务监测中,我发现如果一个调用放上传的数据是7000
条左右,那这个数据的处理过程大概需要一个小时,也就是说我在拆分业务前,这种数据量下,系统处理过程需要一个多小时,这么长时间,请求能不超时吗?
这个图就是我们业务拆分前的系统架构
业务拆分之后,系统响应自然提高了:
总结
写这个事件的原因就是希望大家引以为戒,在日常工作中一定要谨慎严谨,特别是在正式环境,如果事件影响特别严重,给公司带来严重损失的话,那真的就断送了自己的职业道路了,保不准牢饭吃够😂当然,我也没有责怪这个同事的意思,毕竟真的让我来做这个事我也不见得能做的完美,只是希望我们每一个人都能西区这个教训,好好总结经验,在工作中严谨严格,虽然我们都是初生牛犊,但不能在同一个地方一次次跌倒,错的多了真的就把自己错没了。既然事情做了就做好,尽可能做到完美,别事没少干,然后还给自己带来了无穷无尽的加班(加班当然是为了修bug
呀,自己坑自己最狠),最后呢,我再分享下自己总结的教训:
- 任何系统升级之前,都要想好有效的应急方案:这一点我前面也说了,如果
bug
确实一时半会修不好,那就采取有效的应急方案,保证系统受影响最小,如果没有真的能坑死人,坑自己,坑别人; - 系统升级前,一定要提前通知调用方,收集升级意见,做好前期准备工作:这个我确实没想到,升级前没有和调用方沟通就直接升级,如果调用方让你赔偿损失,你也没脾气;
- 升级前,一定考虑影响范围,预知相关升级风险:这一点主要是为了升级前告知客户可能的影响范围,方便客户决策,毕竟在技术上我们比客户更专业,客户关注的只是业务;
- 一定要进行有效的测试验证:升级前一定要做测试验证,而且一定要调用方参与,自己模拟的和调用方环境的差距真的不是一丁半点。