保证系统稳定性,是系统研发的底板思维。
系统部署到客户那里,最基本最重要的要求就是系统稳定性。系统稳定性差,那么系统功能再丰富界面再美观,也无法补偿稳定性差给客户带来的负面影响和损失。
保证系统稳定性,是系统研发的底板思维。
稳定性问题
- 系统频繁重启
- 系统直接崩溃
- 系统严重阻塞,无法响应和处理请求,基本不可用
根因分析及思路
导致系统出现稳定性问题的两大原因:
- 流量过大,远超过系统能够承载负荷(反过来说是系统性能不足);
- 系统内部存在死循环或死锁,锁住了线程,使得无法向前推进。
大数据量的源头:
- 大量瞬时请求:比如大量 agent 同时发送规则拉取请求。
- 大量瞬时消息:比如配置了宽泛规则导致瞬时大量告警上报。
- 批量级联变更:比如批量变更主机 IP、业务组导致的级联更新风暴。
- 异常时的全表更新:比如根据 MD5 更新文件上传任务表,如果发生异常时, MD5 值为空,就可能导致全表更新。
- 弱条件查询或更新。
思路:
- 避免或减少大流量的产生(尽量避免大量级联变更,比如快照信息没必要更新);
- 控制大流量的流入(限流);
- 弱化不稳定依赖的影响(降级);
- 降低高负荷运行的持续时间(动态控制速率);
- 检查并消除死循环或死锁(复杂业务逻辑、加锁逻辑检查)。
稳定性风险分析与检查
稳定性风险分析包括四要素:
- 风险类别: 存在哪些导致服务不稳定的风险情形 ?
- 风险表征: 通过什么特征来识别这些风险 ?
- 风险根因: 引起这些风险的根本原因是什么 ?
- 风险对策: 若风险发生,如何及时提前处理,将问题掐灭在摇篮期间 ?
稳定性风险检查需要找出影响系统稳定性的因素:
- 接口是否会面对大流量?是否有限流措施?
- 消息处理是否有削峰措施?
- 是否有潜在的大数据量的表更新?
- 是否有大对象的非受控的持续创建?
- 对于系统的各种非强依赖项,是否有降级措施,保证基本功能始终可用?
- 是否存在弱查询条件,导致一次加载大量数据到内存里?
- 发生异常时是否可能有全表更新的隐患?
- 是否存在死循环的可能?
- 是否存在死锁的可能?
入侵APP 的稳定性检查
- 大量 agent 拉取规则的接口稳定性问题:采用异步任务方案。
- 瞬时告警流量问题: ids-endpoint 接口已加限流措施,kafka 可以进行削峰。如果 kafka 消息堆积,可以通过告警过滤表达式快速丢弃指定的告警。
- 批量级联变更: 目前主要是主机 IP/主机名批量变更 导致告警表中的主机 IP/ 主机名变更 ;业务组批量变更导致告警表等的业务组ID变更。已经做了分批处理,限制只处理一个月的数据。
- 异常时全表更新: 主要是文件上传失败时。已确认上传失败的时候 sha256 都有值,更新是按照这两个值进行的,应该没问题。
- 死循环: 目前只有构建有序进程树时可能存在,之前已经遇到过 pid = ppid ,已经做了处理,遇到这种情况打日志,并 break。
- 死锁: 大多数分布式锁都是针对定时任务,不存在两个锁申请。 病毒检测需要多个子任务锁,子任务锁有任务创建锁和检测锁。任务创建锁是 type + md5, 检测说是 taskType + sha256。由于子任务创建顺序是不固定的,而进程检测有很多重复情形,可能存在 某个检测 A 先申请了 avira 任务锁,再申请 tav 任务锁, 某个检测 B 先申请了 tav 任务锁,再申请 avira 任务锁。这两个检测的数据是完全一样的。不过病毒检测不是在同一个流程使用多把锁。A 在申请 tav 锁的时候,已经释放了 avira 锁,同理 B 在申请 tav 任务锁时,已经释放了 avira 锁。因此不会有死锁。
- 更新加防御式检查: 如果用于更新的条件来自外部系统,那么更新时必须加防御式检查(不要信任外部的数据)。登录事件/检测消息消费更新加防御式判空检查,因为更新条件是来自大数据或引擎检测的结果数据,不能完全信任。如果有问题,可能会导致大量错误数据。
- 弱条件查询检查。
- 不必要的强依赖检查(比如定时任务依赖 redis)。
- 内存问题。
具体方法与措施
- 代码健壮性。做好数据兼容工作。比如,不能因为某个字段问题导致整个告警详情展示不出来,或者因为某个告警有脏数据导致整个告警列表都展示不出来。
- 削峰。对于大流量消息进行削峰,保持在系统能够处理的范围内;
- 限流。对于瞬时大流量接口请求,控制系统流入量。
- 降级。弱化依赖的影响,避免依赖服务跪了的级联影响。
- 异步。如果接口比较耗时,可以将同步改成异步任务,异步处理,快速响应。
- 减少依赖。尽可能减少不必要的外部依赖。
- 分批,分页,流处理。使用游标或 stream 查询数据库,分批处理数据。
- 避免在方法里动态创建线程或线程池。
- 异常更新避免全表更新。异常情形进行查询或更新时,尤其要注意条件是否可能为空,避免全表扫或全表更新。
- 弱条件分页查询。有弱条件时,要使用分页来查询大量数据。
- 重试补偿机制:基础服务的某次处理失败不可避免,因此要有自动的重试补偿。比如大流量写入 ES 导致 ES 失败,则要有重试补偿。对于 HBase 和 API 访问相同。
- 避免消息堆积和阻塞: 消息消费型应用要避免消息堆积和阻塞,尽可能自动过滤掉脏数据。
- 避免死循环。检查是否有复杂的 while 循环,for 循环,提交 AI review 下。
- 避免死锁。检查是否有复杂的加锁逻辑。
- 非核心应用的访问限制。如果两个应用(一个核心,一个非核心)同时依赖某个中间件的服务,那么非核心应用的访问应当加以限制。比如订单详情和订单导出都访问 HBase 主表服务,由于订单详情的影响范围很大,因此要对订单导出访问 HBase 服务加以限制(从访问频率和访问数据量)。
- 监控:密切关注业务监控(峰值 QPS,RT 突涨、同比环比)、异常监控、服务器监控、Java 监控、消息堆积报警等。
参考文章
标签:增强,系统,稳定性,更新,死锁,任务,告警,方法 From: https://www.cnblogs.com/lovesqcc/p/17520135.html