天下java本站尽知

超级管理员

35605

帖子

9

回复

54

积分

楼主
发表于 2020-01-02 09:00:05 | 查看: 179 | 回复: 0

本篇开始介绍具体的实现过程,为表述方便,先定义一些名词,

  • AutoRepairSystem: 故障自动维修系统, 缩写为ARS

  • 原子操作:任务的最小操作,机器任务通常是指重启、重装

  • 运维人员:运维工程师= SRE = OP,系统工程师 = sys

  • 远程管理工具: 远程控制操作物理机器的工具,如ipmi、ilo

 

先来看ARS的整体视图和流程图,

 

 

 

 

 

 

 

 

ARS的工作流程,

  1. 故障检测: 每5分钟发起一次故障检测,获取当前时刻整个集群的故障机器列表,推送到工作流子系统

  2. 安全策略: 遍历故障机器列表,依次执行安全策略,过滤不符合要求的机器,得到一个可安全执行重启、重装的机器列表

  3. 服务离线: 遍历可安全操作的机器列表,执行服务离线

  4. 故障维修: 服务离线后,发起重启、维修操作,轮询机器状态,直至重启成功或维修完成

  5. 环境初始化: 执行环境初始化,保证机器环境符合业务需求

  6. 服务上线: 恢复服务,检查服务达到可服务状态,流程结束

 

接下来将介绍工作流子系统,这是所有具体操作任务执行的基础;

再依次介绍上述流程中的关键环节: 服务上下线,故障检测,安全策略,维修工具及SLA;

然后通过一个线上例子,说明整体的工作流程;

最后分享系统上线后的运行数据。

 

2.1 工作流子系统

工作流最基本的功能,是驱动一系列预定义任务顺序执行,达到明确的结束状态;在机器故障自动处理这个问题域里,对工作流还有闭环、扩展性的要求(详见第一篇的分析).

 

经过分析统计机器相关的操作任务, 比如机器重启、重装、初始化环境、启动/停止服务、查看信息等,抽象出机器操作的任务模型,即”对一组机器执行相同的任务,且任务可以进一步拆分为一系列更小的原子操作组合”,如图所示,

 

 

上图表示对一组机器执行相同的任务,下图表示,这个任务具体有4个原子操作。

由此,我们可以定义工作流的几个关键类,以及他们的关系,

 

 

 

 

 

注:为了简化表述,这里只列出和流程执行、任务分支、通用性相关的字段和逻辑,工作流子系统的完整信息,后续会另写文章介绍。

 

  • Job,定义了任务类型以及要操作的目标集合

  • Task,定义了一个具体的操作目标,以及action_tree的root节点

  • Action,定义了业务逻辑的内容和加载方式

  • Scheduler, 调度Job的运行

  • Monitor, 监控 Job、Task、Action 的状态

  • Executor, 控制Job下的task/action 的执行顺序、并发等

 

接下来重点看看工作流系统是如何达到前文提到的扩展性、闭环要求的。

 

第一点,扩展性。

 

 

扩展性需求,最初来自于不同服务上下线操作的差异,主要是有状态服务。

它们之间的差异,体现在操作步骤的数量和顺序不同。例如,

  • 推荐模型服务,要求先寻找可用的机器资源,在新资源上部署相同版本的服务,启动服务加载数据,判断数据加载进度,直到达到某个阈值,才算是完成“迁移”,此时才达到可维修的状态

  • Docker服务,相对简单,只需向docker发起迁移命令,等待docker返回迁移进度,迁移完成后即可维修

  • Hadoop服务,主要痛点在磁盘故障上,要求维修过程中不能长时间停服,所以维修逻辑很复杂,要先停止本机服务,umount故障磁盘,启动服务,维修故障磁盘,修复之后再停服,起服,让Hadoop重新使用这块磁盘

  • 其他无状态服务相对简单,通常直接维修即可

 

 

可见,不同服务的差异化是不可穷举的,如果ARS要介入具体的维修逻辑,无异于“揽屎上身”,最终陷入泥潭里无法自拔。

 

我们的思路是: 对外提供一套机制,能简易地将维修逻辑嵌入工作流子系统,实现步骤如下,

  1. 将复杂任务拆解成多个原子操作,每个原子操作实现为一个python方法,返回值格式固定

  2. 定义原子操作的执行顺序以及分支

 

只要满足上述条件,系统就能支持任意数量、任意顺序的原子操作集合。

 

原子操作的python实现如下图所示,

 

 

action1为原子操作名字,do_hard_work()方法由业务sre 完成,工作流子系统只负责调用, is_succ表明本次操作是否执行成功,result通常是操作结果信息。

 

只要按照这个约定编写的任务,都可注册到系统里被执行,哪怕提交人只是用python 包了一坨 shell 脚本,也是可嵌入系统的,虽然我们在review的时候会“建议”他重写。

 

有了原子操作的实现,就可以定义它们的执行顺序,我们使用了“树”的概念,如下图json配置示例所示,

 

 

 

可以看到,整棵树有多棵子树组成,每棵子树指向一个nodes list,每个node就是一个action, action的数量和顺序可以在nodes list里任意配置扩展。

在example_trees里, action1~action6就是原子操作,执行的顺序有两种可能分支,

action1-> action2 (true)--> action3->action4->结束;

action1-> action2 (false)--> action5->action6->结束;

 

假设现在业务有一个大的改动,需要在action2之前增加一个操作action7, 并在action6之后,增加一个分支action8,  这只需在配置上小改动即可实现,

 

 

 

example_trees 会被保存在Action类的action_definition字段里,这个配置记录了执行逻辑的python 文件,类和方法; 工作流在运行时,会动态加载相应的类,根据方法名调用方法,如下图所示,

 

 

 

 

凭借这些特性,业务sre可以灵活多变的定义自己的任务树,其中公共部分,由平台sre编写,与业务相关部分由业务sre编写。

 

第二点,闭环。

以无状态的 web机器的宕机自动处理流程为例,(这里为了方便表述,做了简化)

  1. 检测宕机的机器

  2. 重启机器

  3. 如果能起来,检查程序版本,启动web 服务,流程结束

  4. 如果不能起来,则报修硬件故障

  5. 如果能修复,回到第3步

  6. 如果不能修复,则检查是否过保,如果是,则下架机器,流程结束

 

其流程树的配置如下,

 

 

 

 

 

可以看到,reboot_host、check_host_alive、repair_host等action为原子操作;

这棵树有两个分支节点,

如果 reboot_host之后 check_host_alive为Ture, 则执行online_service 分支,流程结束; 

如果为false, 则执行repair_host 分支,如果能修好,则回到 tree2 ,最后也达到 online_service的状态,  流程结束;(只要是没过保,都能修好)

如果修不好,那么则进入 off_rack 下架流程,流程结束。(通常是机器过保)

 

这里之所以反复强调任务分支,是因为有了任务分支,就可以在各个可能执行失败的环节,指定下一步的操作,最终将目标操作到一个可预期的状态(机器要么被修好重新投入使用,要么修不好被下架),形成闭环,不用人工介入,真正提高自动化程度。

同时,由于在一开始就设定了维修只有两种操作:重启,重装,这两种操作都由sys来保证交付时间,所以这棵树能保证流程是闭环的。

 

在ARS上线之前,早期的自动工具发起重启命令之后,机器起不来,通常是人工通知sys 报修,报修之后 sys 再根据机器是否过保来给sre 反馈维修状态,这个过程,如同黑洞,吞噬了rd-sre-sys-机房外包四方大量的沟通时间, 如图所示,

 

 

工作流子系统还涉及状态机、并发控制、重试、任务重入、超时、执行进度等,后续另写文章介绍。

 

在下一节里,将介绍故障检测、安全策略等内容。

 

2.2故障检测

故障检测的完整性、正确性是故障维修自动化的前提。

通过分析历史机器故障类型,可将故障分为5个层次,如下表,基本覆盖了sre日常处理的故障。

 

层次

异常类型

常见问题

检测方式

业务相关

执行异常

磁盘空间不足、部署时调用的control脚本返回值异常、目录权限

Falcon

运维系统

平台自身异常

帐号异常、Executor执行任务异常、部署系统异常

Falcon+运维系统接口

基础环境

依赖异常

环境异常(依赖库/文件缺失)、版本不符(内核/python/perl)、limits.conf不符

Falcon+shell/python

系统层

读写异常

文件系统错误(Input/Output Error)、文件系统挂载错误(read-only、home未挂载)

Falcon+shell/python

机器层

连接异常

硬盘故障, 宕机故障, 内存故障, 电源故障, 风扇故障, CPU/GPU故障

ping/ssh/Falcon+ipmi

 

ARS主要覆盖了机器层、系统层,下面分别做说明。

 

磁盘故障

磁盘故障率高的业务类型很多, 如hadoop、索引服务、分布式文件系统服务、机器学习模型训练服务等,这些服务的机器,磁盘块数最高多达36块,大量读写磁盘,造成磁盘故障率很高。

常见的磁盘故障类型有掉盘、读写错误(Input/Output Error)、漂盘、挂载错误、 read-only错误、性能剧降(ls /disk/ 超过10分钟无反应);

磁盘故障的积累,有可能会导致数据丢失,以及拖慢整个系统的性能,所以要尽早检测到尽早处理。

 

宕机故障

宕机故障分为完全死机,假死。

完全死机(指连续3个小时失去心跳,并且主动ssh 探测失败的机器),这种情况容易处理,直接进入自动重启流程;

假死,有如下类型,

l  Connection timed out

l  Connection closed by remotehost

l  Connection reset by peer

l  Connection refused

l  Connection closed by

 

这些假死状态,可能会造成业务受损。

比如机器假死,服务端口还能连接,但实际业务进程内部无法正常工作,如果是前端web机器出现这种情况,会导致业务5xx监控飙升;此时,想手动重启,ssh已经无法连接,只能通过ilo重启,或者紧急联系机房,处理耗时往往超过半小时。

 

 

内存故障

内存故障时,通常机器还没有死机,(在/var/log/message 里显示CE error on CPU#1Channel#2_DIMM#1)

 rd认为机器还能跑,不愿意停服务;

如果积攒到多台机器出现类似错误,极有可能在短时间内出现连续死机,导致服务容量突然减少,服务性能大幅下降的业务故障,所以对于一些敏感服务,出现这种故障,还是要当作死机来处理。

 

电源故障

双电源是突然断电、市政施工的保障,如果电源坏了不修,在这种情况下,机器会断电关机,如果积攒多了,服务容量会突减,影响业务。

 

风扇故障

不会马上造成死机,但是会产生连锁反应。风扇故障会导致cpu温度升高,引发死机。

 

 

上述故障检测的实现,主要是通过 Falcon监控系统 + scripts 实现,涉及了 ping/ssh/ipmi/dmesg/proc/sar…等大量系统命令和系统信息。

Falcon 运行这些scripts,检测故障,外部应用就可以从接口里查询故障列表信息,如下,

 

 

ARS从Falcon拉取当前时刻集群内所有故障机器的列表,附带了相应的故障信息,推送到工作流里,进行维修。

 

 

2.3 安全策略

对机器的操作,通常是重装、重启、root环境修改、部署基础agent等;此类操作往往不可逆且无法暂停,所以需要严格的安全策略保证机器操作不影响线上服务或影响最小。

 

经过“故障检测”这个环节后,得到一个当前时刻所有故障机器列表,安全策略会对这个列表进行分析过滤,下表是我们使用的安全策略列表,

 

策略

作用&应用场景

实现

filter_bw _lists

黑白名单;

通常用于敏感服务,如支付、隔离环境服务

只处理白名单内的机器

跳过黑名单内的机器

filter_alive_hosts

过滤掉处于非死机的机器;

防止误判,重启了非死机的机器

1、3分钟内连续ping机器,如果有响应,则过滤机器

2、过滤可以响应 ssh 请求的机器

3、防止网络抖动误判,在多个机房 ping,交叉验证

filter_switch_fail

防止交换机故障引起误判,比如批量机器无法联通

按分钟统计机器的故障时间,如是同一分钟内报上来的(falcon采集周期是1分钟),本次就不会向后端推送任何机

filter_base_agent

过滤掉基础agent端口存活的机器;

某些特殊服务会禁止ping/ssh命令,所以通过基础agent端口来判断存活

通过 telnet/curl  ip:port 判断基础agent是否存活,基础agent存活代表机器存活,过滤机器

filter_running_service_hosts

过滤掉有服务处于running状态的机器;

防止误判,操作了服务还在运行的机器

检查机器网卡流量、磁盘io等指标,超过阈值则认为存在服务,过滤机器

filter_capacities

根据服务容量过滤;

防止因操作了机器,导致服务容量不足

计算服务容量, 当前running实例数/总实例数  < 阈值(90%),过滤机器

filter_duplicate

去重,保证同一时刻同一台机器只有一个操作任务在执行;

防止多个任务叠加到同一台机器,出现未预期结果

遍历系统所有任务,如果此机器有处于running的任务,跳过此机器

filter_pattern

过滤指定patterns的机器;

这是最严格的过滤器,通常是单点服务使用此策略

对机器的机器名、节点名、运行服务名、在各类配置中心注册名进行正则匹配,如果匹配,则过滤机器

filter_threshold

阈值保护,保证同时进行的机器操作任务数低于允许维修的数量

1、按机房粒度,对于不同的任务类型,如果当前此机房的机器操作任务数大于阈值,跳过此机器

2、按服务(app)粒度,如果当前此服务(app)的机器操作任务数大于阈值,跳过此机器

例如这个例子,当前app1任务数是3,而允许维修的阈值是5,所以只能再发起2台机器的维修

current_repairing/beijing/app1: 3  

threshold /beijing/app1: 5

filter_by_date

遵循分级发布原则,在一个星期内的某一天,只能维修对应机房的机器

1、指定每天允许维修的机房

2、遍历所有机器,如果一台机器所属的机房不是当天允许维修的,跳过此机器

 

这个安全策略表,是总结分析多个业务线的历史case study得出来的, 在线上运行以来,未出现过误判,保证了自动任务的安全性。

 

每一个安全策略,实现为工作流里的一个原子操作,即action,结合上述重启的例子,json配置如下,(维修的流程也可以使用这些安全策略,这里不再单独列出)

 

 

这些策略,可复用也可自由组合、调整顺序,这对于接入不同业务的机器进行自动维修,有很大的便利性和灵活性,同时降低了接入成本。

 

如果业务有自己的安全策略需求,只需按照上述的action 方法规范,自己写一个安全策略方法,在配置里指定即可使用。

 

 

2.4 维修工具及SLA

 

机器硬件故障维修,是真实世界中的事件,这个过程需要人去到机房现场,从仓库拿出配件,走到机架旁边,拆卸机器,装配硬件。

所以这个环节是“不可抗力”产生的地方,比如配件备货不足;节假日厂商人员放假,无法赶赴机房;赶上两会,机房封禁,不让进入等各种问题。

 

1  交付时间

为了达到流程闭环,我们(甲方)和机器厂商(乙方)约定机器维修交付时间, 通常是36小时交付(不同公司、厂商可能不一样),至于怎么解决上述“不可抗力”,由乙方负责。

 

2  远程管理工具可用率

远程管理工具是机器操作自动化的必备工具,reboot_host/repair_host底层调用的就是ipmi;

为了尽可能地减少机房现场人员操作,我们要求sys保证远程管理工具可用率达到 99.9%,比如,ilo,ipmi

 

有了这两个SLA,我们可以认为 reboot_host、repair_host 这两个原子操作的最长耗时为36小时,所以维修流程是一定可以闭环的,避免了因任务中断导致的人工介入。

 

当然,有了这些,也只是修复了硬件,还有系统参数设置、环境初始化、基础agent的问题,这个内容比较多,在下一篇讲。

 

将上述提及的技术细节汇总,得到ARS的完整视图,

 

 

 

最后,看一个自动重启的例子,

可以看到任务树定义的actions 是怎么执行的,先是执行一系列的 filter_*安全策略,然后屏蔽报警,执行服务离线,发起重启,然后轮询机器状态,直到任务结束。

 

 

 

 

2.5 系统运行数据

 

ARS上线后,覆盖数万台机器的故障自动处理,死机数量保持在10台左右,所有硬件故障总数量保持在100台以下,这对于一个数万台机器的集群来说,是非常理想的状态了。

 

人力方面,对于20人的sre 团队,机器故障只需要 0.5人力维护系统正常运转,例如新服务的接入、业务要求紧急修复之类的情况;当机器规模增长时,人力并不需要相应的增加。

 

2.6 总结

最后,总结一下几个关键点,

  • 标准,定义了有哪些类型的故障,什么故障执行什么样的修复,修复的标准流程

  • 闭环,对于机器的操作,用任务分支覆盖操作成功或失败的情况,用SLA约束厂商在约定时间内交付机器,保证流程可达到明确的结束状态,避免人工介入

  • 安全,10个安全策略组成的过滤链,并支持低成本的增加新策略,保证自动化任务是安全的

 

在本文中,有一个重要的事项没有提到,就是环境初始化,这个再下一篇文章讲述。

 


 

排列文字,重组感受。

我是曲行人,日常写码,闲时写点儿文字,

如果你觉得有点意思,或者有点用,可以关注我,

我将在大脑里的思维原子做布朗运动时,输出文字。

公众号: qxren7

二维码: 

 


您需要登录后才可以回帖 登录 | 立即注册