发生故障,服务能承受住考验吗?

故障,是一个验金石。

一、背景

今天同一时间发生了两起故障,先记录下第一起已经解决的故障,晚几天再记录另外一起。

解决故障的过程中,我领悟到一个道理:平时不管服务宣称的多好,都不好证明。出问题时,才是承受考验的时刻

二、服务架构

我们的服务架构其实很简单,一个接入层(我负责)、一个缓存层(项目核心人员负责)、底层很多数据源。

服务其中一个很重要的作用是,对读数据的业务屏蔽数据源细节。

例如对于视频表,可能是下面的样子。

视频基础资料数据,A 团队负责,储存在 a DB中,字段名是 A 团队自定义的。

视频播放量数据,B 团队负责,储存在 b DB 中,字段名是 B 团队自定义的。

视频付费数据,C 团队负责,储存在 c DB 中,字段名是 C 团队自定义的。

我们的这个服务统一来读取这些数据,然后输出给使用方。

图片

设计这个系统的时候,发现会遇到储存字段名变化的情况。

变化的原因有很多,如下

1、不同团队 DB 中的字段名会冲突。

2、储存中的字段名起的不规范。

3、储存中的字段名可能换名字。

4、一个储存的字段可能突然废弃,切换到另外一个储存。

上面是常见的原因,可能还有其他原因。

总之,我们不能因为储存的名字发生变化,就影响业务读业务方。

所以,我们的服务其中一个很大的特点是分为读字段名和储存源字段名(写字段名)。

使用数据方只关心读字段名,不需要关心数据在哪里储存,名字是什么。

图片

就是在这样一个背景下,今天出现了一个故障。

三、服务 coredump

16:20 的时候,我收到多条告警,是接入层读缓存层存在失败率。

于是赶紧通知缓存层的核心开发人员,问是否有发布,线上存在失败率。

几分钟后,缓存层回复:没发布,发现服务存在 coredump ,在读 redis 的地方挂了。

我马上说电话 redis 的开发同学看下,是否是 redis 有变更导致。

几分钟后,回复:redis 那边没有变更。

16:27 拉了一个群,贴出了core 截图,我便看有什么特征。

看到图中没有堆栈时,我赶紧说:把堆栈发出来,甚至看能不能把redis请求与回包打印出来。

图片

缓存层核心负责人发出堆栈截图后,补充道:好像死循环了,堆栈的函数都是同一个。

而我则观察到,函数最后一个参数是包的长度,很大,足足有 1M

于是大家都猜测可能是大包的问题,触发RPC框架的BUG了

四、紧急处理

缓存层核心负责人把所有堆栈打印出来后,找到了一个异常字段。

我问写负责人,这个数据是今天上线吗?

得到的回复是上线好几周了。

于是,我们做出了一个合理的猜测:只有这一个字段有大包问题,然后触发了RPC框架的BUG(事后,我甚至猜测只有一条数据有问题)。

接着做出了一个合理的措施:下掉这个字段

还是看架构图,下掉这个字段有两个方法。

一个是修改读字段名,这样业务请求的时候就报错,会触发失败率告警。

另外一个是修改写字段名,这样不会报错,储存中会读出空数据,之后流程完全无感知。

图片

为了不触发告警造成骚扰,我提出方案一:赶紧修改储存源字段名

在这个服务重构前,底层储存出问题时,我经常这样搞,解决了无数问题了。

修改完写字段名后,等了几分钟,从接入层看监控依旧有失败,缓存层核心开发人员也反馈依旧在 core。

缓存层不是我实现的,所以我不清楚原因,也没时间去看源码。

缓存层核心人员说可能生效需要时间吧,于是等了很久,迟迟没有彻底恢复(事后看监控,可能真的生效慢)。

于是,我提出方案二:修改读字段

修改后,刷新监控,失败率已经下降,恢复正常。

之后也符合预期的收到一个失败率告警

原因是有些业务只读这个表的一个字段,现在字段不存在了,命中了字段全部非法的错误码逻辑。

五、流量调度

故障恢复平静后,领导说:接入层之前不是实现了流量调度能力吗

可以把这个异常表的请求都路由到一个只有一个业务的小众集群去,这样即使再出问题,也不会影响到大众业务。

说起流量调度,还是需要看架构图。

图片

实际上,我们部署了多套物理隔离的集群(来源除外),给不同业务提供服务。

面对 A 集群流量暴涨,B 集群还有充足容量时,如果能够把 A 的部分流量调度到 B 时,就可以让 A 集群的服务质量。

所以我们做了一个流量调度能力。

当然,最理想的流量调度是在客户端实现,但是依赖的路由发现中台还在开发中。

我们便在接入层实现了这样一个基于业务标识的转发功能。

面对领导的这个要求,我说没问题。

说干就干,操作之后,看监控,流量都符合预期的到达那个小众集群去了。

刚开始因为小众集群没缓存,还收到一波告警。

不过超时率也在快速的衰减,这个超时也算符合预期。

六、最后

当然,我们发现字段有大包问题时,也在让写服务的核心开发去联系具体问题数据表的业务负责人,咨询是否可以直接从储存中删除大包数据,得到确认后手动删除了

另外,我们把这个问题反馈给 RPC 框架时,框架的开发人员说最近正好解决了一个类似的问题,建议我们升级到最新版本

最后,当缓存层核心开发升级到最新版本后,我又取消屏蔽这个字段了。

初步验证没有再 coredump ,问题算是解决了。

之后,还需要构造出删除前的数据样例,具体测试下,否则可能是因为没有大包才没 coredump 的。

吃饭的时候,我便想:异常情况才能真正检验平常做的功能是否有效。

比如我们为了应付紧急问题,平常预备了方案一二三。

可能自测这些方案,宣称是有效的。

可能演习这些方案,宣称是有效的。

但是否真的有效不好说,当线上来了真实的问题时,才是考验这些功能是否有效的时候。

加油,工程师。

《完》

-EOF-

题图:来自朋友圈。

发表评论

登录后才能评论
网站客服
网站客服
申请收录 侵权处理
分享本页
返回顶部