【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

从二十个严重的配置故障中我们能学到什么?

  • 2019-12-24
  • 本文字数:4293 字

    阅读完需:约 14 分钟

从二十个严重的配置故障中我们能学到什么?

配置故障是运维人员在工作中经常会遇到的问题,如何才能避免配置故障的发生呢?本文作者列出了自己职业生涯遇到的 20 个不同类型的配置故障,并分析了故障发生的原因,提出了相关的解决方法。

配置变更的痛点

时效性,很多配置变更的场景,其生效时间是有明确要求的,尤其是止损相关的操作。如流量调度的配置生效时间不超过 5min,这是由 SLA 所决定的。因为 5min 的生效要求,所以这类配置变更基本上不会进行灰度,直接就全量生效了。


动态化,在上下游关联关系的场景中,服务的 IP 地址列表和数量均会发生变化的,站在整个系统角度去看,可能每时每刻都会有服务因扩容、缩容、故障转移而产生 IP 列表的变化,加之这类配置是最终一致性的特性,因此,就很难对语义内容的正确性做及时准确的判断。


差异化,同一服务的不同实例或者不同集群间,配置会有一定的区别。以监控系统为例,因为每台机器上部署的服务组合不相同,那么每台机器上需要采集的内容就不相同,那相应的监控配置也会不同。许多的机器生效的配置不同,版本不同,那么要想检查哪些机器未生效最新配置,未完全生效配置,就有困难了。


碎片化,每个服务都需要配置管理,但现实却是大多数服务都是自己写的这套逻辑,且实现非常之简单。如果现实是建立在大多数服务自己实现配置管理的基础上,那么想要做到相对统一的标准规范,你就需要做各种对接和适配,开发各种外挂,持续处在一个较低的层次上。配置中心成熟的开源解决方案有很多,因此内部开发人员也少有动力基于现状写一套适配的方案,大家都会说推动改造是最好的,那改造之前呢怎么办呢

二十个严重的配置故障

笔者曾长期负责配置服务的运维工作,也经常参加公司的故障复盘会,感慨于配置故障影响的严重程度,因此将过去多年和配置相关的各种服务故障脱敏后进行罗列,希望对大家有所帮助。限于篇幅的关系,无法对每个 case 进行准确详尽描述,仅描述故障原因部分,因此阅读下面的 case,需要读者具备一定的相关背景才能更好的理解(本文中罗列的 case 较多,有内容不合适的地方,可直接联系笔者处理)


case1:在 WAF 中部署了配置错误的规则,其中一个规则包含有一个正则表达式,导致节点 100%CPU 占用。和 CloudFlare WAF 的故障是较为相似的


case2:某服务访问数据库错误,获取合法用户列表的结果为空值,该服务认为没有合法用户,将所有的用户请求全部封禁,导致系统完全不可用。和阿里云 20180627 的故障较为相似的


case3:每台物理机上均有一个单机部署器,单机部署器定期从服务端同步配置,用以在单机上部署需要的客户端列表。因为网络的问题,配置被截断,部署器只获取了上半部分配置,部署器基于此进行更新,所有未在配置中的服务被全部卸载,影响极为严重


case4:计算模块对加载的处理规则数量进行了限制,单个租户最大可处理 1000 条规则,经过几个月的使用后,某个租户的规则数超过 1000 条,计算模块全部 coredump


case5:服务启动前需要从远程加载相关配置,某次变更添加配置条目较多,服务请求配置超时后,不断重新启动,直至将配置中心打垮,进而影响多个业务,导致系统彻底崩溃


case6:Zookeeper 的 initlimit 设置为 5(意思是实例启动后可以有 10s 的时间来同步数据),该数值对于大部分集群来说,都没有问题,但是如果 ZK 集群的快照体积超过 1GB,那么节点重启后就可能无法在 10s 内同步完数据进而导致节点异常


case7:Agent 上传给服务端的数据包出现了异常,在头部信息中,100KB 的体积变成了无限大,然后后端模块就按照该值进行内存分配,因为超过 Ulimit 的限制,所以 coredump 了,一部分服务器异常后,Agent 继续将请求发送给剩余的服务器,直到集群全部被打死为止


case8:通过配置服务获取下游服务列表,运维人员误将服务下所有实例从配置中删除,而该服务也未使用系统提供的熔断阈值,导致从配置服务中获取该服务列表为空,其他依赖服务加载了该配置后,导致服务整体故障


case9:新上架的交换机未添加完整的 ACL 规则,导致线下服务请求到线上集群中


case10:用户提交了语法结构不正确的配置,然后该配置下发到了后端,所有加载该配置的后端模块全部 coredump 了,后端模块使用了通用的语法校验库,但和前端使用的校验库不同


case11:后端服务异常后,触发了自动降级(通过修改 Nginx 的配置文件来实现),修改配置文件出现了逻辑错误,该配置通过了语法校验并立即进行了全量自动更新,导致集群整体崩溃


case12:将某台服务器上的 stats.conf 文件同步到全部 nginx 集群上,忽略了 allow 字段的 ip 地址不同,致使 lvs 认为监听的后端 nginx 全部故障,系统直接出默认页面了


case13:批量删除线上服务器的日志,因路径中包含特殊字符,运维系统未能很好的处理该字符,只保留了特殊字符前的路径,导致线上服务器根目录被清空


case14:配置项结尾多了特殊字符,导致策略匹配全部失败。原因是 windows 下的文本文件换行符是\r\n,linux 下的换行符是\n,在 linux 下 vim 打开 windows 的文本文件,在行尾会显示^M 字符


case15:通过配置服务获取下游服务列表,因下游服务列表包含了四万多个 IP 地址,导致获取超时,服务继续使用过期的下游列表,而该过期的下游列表中无效实例逐渐增加,最后导致服务连续重试到无效实例,流量被丢弃


case16:配置中心对外提供配置下载服务,其 LB 的负载均衡策略使用了随机策略,因下载集群规模超过百台机器,配置更新需要一定时间,在此期间,请求配置中心获取的配置会不停的在新旧版本之间变化,导致相关的服务被不停的卸载,升级,无法提供服务


case17:配置中心的负载均衡策略使用了 Ip_hash 策略,部分下载集群数据未更新,导致被分配到这些集群的服务,无法获取最新配置,且多次重试依然无效,导致流量统计始终缺少 20%的流量,对收入造成严重的损失


case18:高防回源携带的头部字段中新增的内容与源站 iis 配置不兼容,导致回源请求被拒绝


case19:named 服务在重载配置时,产生了新的进程但老进程没有正常退出,服务请求数据时,将请求打到了老 named 的进程,该进程的配置没有更新,导致用户拿到的结果不符合预期。类似的问题,nginx 也有,在很多开源软件上也都有存在


case20:自研 nginx 的扩展来实现 upstream 的定位,hash 桶的大小设置为 1024,因 ip 重复个数较多,超过了 hash 桶的大小,导致 hash 分桶策略不断的进行 rehash 任务,请求全部被卡死

故障改进

对于上述的故障,我们从加强测试,加强数据校验,集群隔离,灰度发布,缓存和熔断六个维度来看各个 case 的适用性,结果如下图所示。


加强测试加强校验集群隔离灰度发布缓存熔断
case1适用适用适用
case2适用适用适用适用
case3适用适用适用适用
case4适用适用
case5适用适用适用
case6适用适用
case7适用适用适用
case8适用适用适用
case9适用适用
case10适用适用适用适用适用
case11适用适用适用
case12适用适用适用适用
case13适用适用适用
case14适用适用适用
case15适用适用
case16适用
case17适用
case18适用适用
case19适用适用
case20适用适用
17137764


假设笔者的给出的改进方案是正确的,对统计结果做如下分析:


  • 加强测试,从有效性来说,该方案可以搞定 85%的故障,如边界值的问题,异常输入的问题,特殊字符串的问题等。但是对于部分场景,加强测试可以搞定,但成本非常高,例如 WAF 的规则问题,不同的用户,配置的规则不同,如果要在测试阶段解决,那就需要对所有用户的所有规则进行测试,且要有足够丰富的请求组合,这时候,可行但成本很高。还有,加强测试虽然可以解决很多问题,但没有从本质上彻底消除问题,且依赖于测试团队的经验和能力,结果并不可控。

  • 加强校验,从有效性来说,该方案可以搞定 65%的故障,以 case2 获取空值的故障来讲,对请求结果进行校验,完全可以避免该问题,且这是程序机制天然具备的,并不依赖于人的经验和能力,因此效果更好。另外,加强校验,并非局限于对空值的校验,还包括配置文件完整性的校验,数据包合法性的校验,配置文件的版本、时间戳、更新时间的校验,对特殊字符串容错的能力,还提供一些故障场景下的兜底访问策略,同时还可以将配置变更的信息以 http 接口进行暴露,便于监控。美中不足之处在于,如果对每个模块分别实现上述的功能,那成本太高了。

  • 集群隔离,笔者之前最为推荐的能力建设内容之一,本次居然只能解决 35%的故障,究其原因,主要在于很多业务虽然隔离部署,但依赖了相同的配置文件,且大部分是高频热加载的,因此集群隔离在此处,略显苍白。

  • 灰度发布,这也是笔者最为推荐的能力建设内容之一,本次也只能解决 35%的故障,主要是因为大部分的配置变更是没有灰度发布的,直接靠程序的定时轮询热加载,因此灰度在此,也略显苍白。


综合来看,三个建议:


  • 将校验,缓存,熔断等相关的能力合并在一起,在通用的配置服务中实现,会是比较好的方案,退而求其次,如果没有通用的配置服务,也应该具备这些能力。

  • 将配置变更尽可能的视为一种上线,涵盖从版本提交,代码检查,测试,灰度发布,效果监控等各个环节,也能够更好的保障稳定性,毕竟很多配置是最终一致性,而非强一致性的,因此,用时间来换取稳定性,也是值得的

  • 将强一致性转为最终一致性,问题就不会那么棘手了。以账号密码变更为例来说明,账号密码变更是强一致性要求的,但是如果通过新增一组账号密码逐步进行替换,全部替换完毕后删除旧的账号密码,则就将强一致性转为最终一致性了。


还有兜底建议:


  • 通过资源限制+SSH+Puppet 多种方式的互备,确保任何场景下,不论是 sshd 异常,还是 cpu 打满,都能够通过批量操作服务器快速止损,决不要出现无法登录服务器的惨剧

场景化建议

热加载配置的场景,尽量使用配置中心这种解决方案,类似于上文的加强校验,缓存,熔断等等,都是标配能力了,而且一旦发现了潜在的隐患,通过升级 lib 库,大家都能避免发生同类问题,效果极好。当然,你得用好才行,胡乱使用 zookeeper,最后导致各种故障,然后怪罪于 zookeeper 有问题,人家很冤枉啊。


需要通过重载配置文件才能生效的场景,则尽量使用集群隔离+灰度发布+加强校验的解决方案,以 DNS 为例说明,不同的 zone 由不同的集群来处理请求,每类 zone 再按需实现同城多活/异地多活,并新增小流量集群,尽量杜绝跨集群的变更操作,对每次变更都要进行严格的自动化校验,并分批次灰度生效,通过提升实时监控能力来降低批次间的时间间隔,进而减少故障的发生。


在整理上面资料的同时,配置故障让我联想到和无性繁殖有些类似,文末的参考资料中附带了香蕉和咖啡树的故事,有兴趣的读者可以看看。


扩展阅读:


香蕉可能要灭绝?还不是第一次?香蕉:救救孩子吧…


为什么英国人对茶情有独钟而不是喜欢咖啡?背后原因你一定想不到


2019-12-24 09:401991

评论 3 条评论

发布
用户头像
多级缓存也应该是配置类服务的一种兜底能力
2022-05-30 21:30
回复
用户头像
需要把改进能力放在case后面进行下标注,让大家在当时就能够认可改进内容,从而认可统计结果

2020-04-13 19:16
回复
用户头像
google在2020.03.26的服务故障可以更新进来
2020-04-13 19:13
回复
没有更多了
发现更多内容

JVM调优简要思想及简单案例-JVM分代模型

zarmnosaj

6月月更

在线JSON转TSV工具

入门小站

工具

scanf的使用,cin和scanf的区别

工程师日月

6月月更

Linux开发_采用线程处理网络请求

DS小龙哥

6月月更

redis内存优化

乌龟哥哥

6月月更

解决k8s调度不均衡问题

劼哥stone

Kubernetes 云原生 调度 调度不均衡 kube-scheduler

敲了几万行源码后,我给Mybatis画了张“全地图”

小傅哥

源码分析 面试 小傅哥 mybatis 大厂面试

【愚公系列】2022年06月 通用职责分配原则(八)-中介原则

愚公搬代码

6月月更

echo命令实用技巧

Nick

Docker 镜像源 echo 6月月更 tldr

我理解的微服务 -- 读《微服务设计模式》总结

潜水员

golang 微服务

618战报销冠谜底:“收割机”联想屠榜背后的三大利器是什么?

脑极体

【Python技能树共建】字符编码与解码

梦想橡皮擦

Python 6月月更

IAST 初探:博采众长、精准定位、DevOps友好

SEAL安全

DevOps 安全 IAST 应用安全测试 开源软件供应链

【作业四 千万级学生管理系统的考试试卷存储方案】

wuli洋

Python 设计模式:原型模式

宇宙之一粟

设计模式 原型模式 6月月更

ImportSelector与DeferredImportSelector的区别(spring4)

程序员欣宸

Java spring SpringFramework 6月月更

《网络是怎么样连接的》读书笔记 - Tcp/IP连接(二)

懒时小窝

TCP 网络编程 IP

DOM核心——Element类型

大熊G

JavaScript 前端 6月月更

C#入门系列(二十) -- 面向对象之封装

陈言必行

C# 6月月更

DOM

Jason199

DOM js 6月月更

远程办公三部曲 - 如何提高工作效率| 社区征文

耳东@Erdong

工作效率 远程办公 6月月更 初夏征文

vivo 容器集群监控系统架构与实践

vivo互联网技术

云原生 监控 系统架构 Prometheus

读书笔记之:麦肯锡高效工作法

甜甜的白桃

读书笔记 读书 笔记 6月月更

架构实战营模块4作业

挖了蘑菇哩斯

架构实战营 存储方案

Jenkins 通过检查代码提交自动触发编译

HoneyMoose

面试突击58:truncate、delete和drop的6大区别

王磊

Java java常见面试题 常见面试题

课程背景

IT蜗壳-Tango

6月月更

uni-app进阶之生命周期【day8】

恒山其若陋兮

6月月更

初创公司,如何拥有企业级Java脚手架

昵称不能为null

Java脚手架 企业级代码架构

【Spring 学习笔记(十四)】Spring AOP 通知中获取数据

倔强的牛角

Java spring 6月月更

dart使用技巧集合【01】

坚果

6月月更

从二十个严重的配置故障中我们能学到什么?_软件工程_焦振清_InfoQ精选文章