
背景
之前介绍了国内酒店稳定性治理实践之系统间依赖治理,我们对系统间的依赖进行了专项治理,涉及通用的限流、缓存、Dubbo、Http、DB、MQ 等。但是光治理系统间的依赖是不够的,我们还对系统内部资源进行了分析和治理。

本篇文章重点讲述对系统内部资源的治理,主要包含使用降级、熔断、隔离、同步转异步等手段控制流程(限流在上篇已经介绍,本篇就不重复了),以及对线程池等核心资源进行治理。
治理手段及方案
降级、熔断
这个主要应对的是外部接口或资源出现问题的场景。提前考虑一些处理方案,保证主流程不会因为异常情况中断。比较典型的是 P1 应用接口调用的 P3 应用接口,要保证 P3 接口出任何问题都不会影响 P1 应用接口的核心流程处理。
1)核心接口内部涉及的外部调用做好降级调研及处理,优先无损降级,核心调用准备好有损降级的手段。
2)非核心场景查询外部接口做熔断处理(主要根据失败率和响应时间),这里要注意熔断后的处理,提前定义好返回的默认值或者定义的异常。
3)关于熔断,推荐提前准备熔断后的替代接口、替代资源或默认值返回,并且能动态调节熔断阈值。
4)规范(不强制):新需求及重构支持降级回修改之前,新增功能支持下线,这样能大幅度降低发布的风险。


隔离
这个主要应对的是相同资源中部分资源出问题影响其他资源的场景。
1)线程池隔离:这个出问题影响很大,主要涉及 dubbo 线程池、自定义的业务线程池、jdk8 并发流使用的线程池(jdk8 的 parallelStream 默认共用的同一个线程池)。
2)数据存储隔离:主要指核心数据与非核心数据隔离,核心数据也可以考虑分片。
3)核心接口与非核心接口隔离:可以通过使用不同应用、不同 group、不同线程池、不同的 client 等,根据业务需要使用隔离手段。
4)只要有核心与非核心的区分,都可以考虑隔离。

同步转异步,串行变并行
这个主要应对同步操作出问题时阻塞整体流程的场景。
1)主流程一般选择同步处理,涉及的辅流程考虑异步处理。辅流程要做好异常和兜底处理,出问题不要影响主流程。
2)核心接口相关流程考虑并行处理,降低接口返回的时间。
3)dubbo、http 等接口也考虑异步调用及处理。

线程池治理
系统中线程池的资源是非常宝贵的,也需要被管控和治理。
1)所有自定义线程池要有相关的线程池监控(活跃线程数、队列内 task 数量、已完成任务数量等)。通过监控,可以查看线程池的资源使用情况,方便提前治理,新需求做资源评估时也会更准确。
2)核心线程池允许动态调整核心参数(核心线程数、最大线程数、工作队列长度等)。这样可以在线程池线程不够用或者线程池占用资源过多时,动态在线上进行调整,而不需要通过发布修改,大幅度降低影响的时间。
3)核心业务建议使用不同的线程池,参考上面介绍的隔离策略。

JVM 及硬件指标治理
1)fgc 次数监控,设置合理的单机报警,比如 5min 内 fgc 次数不能大于等于 2 次。
2)ygc 次数监控,设置合理的单机报警,比如 1min 内 ygc 次数不能超过 10 次。
3)gc 时间监控,比如每次 ygc 时间不可以超过 0.7sec,个别应用可设置更符合自己的指标值。
4)普通虚机上 tomcat 应用的活跃连接数不要超过 300,个别应用可设置更符合自己的指标值。
5)I/O 密集型的应用 cpu 使用率不要超过 60%,个别应用可设置更符合自己的指标值。
6)监控 blocked 状态的线程,配置报警并打印堆栈。防止个别线程持续占着资源无法释放,影响应用对外服务能力。
日常运维
1)报警治理(长期):控制应用每日报警次数,优化报警指标配置,尽可能保证报警就是有问题的、需要人工处理的。
2)异常治理(长期):持续关注核心应用 top5 报警及偶发的 RuntimeException,不断优化与修正。
3)服务巡检:每天高峰期后、每次发布后做好服务检查,对异常指标要确认原因并尽快优化。
4)故障自动定位:目前我们正在基于应用的监控报警、异常及 trace 链路分析等做故障自动定位,已经取得一些进展。当故障原因可以直接被自动定位,结合我们准备好的处理手段,对于同样的故障,故障的影响就可以越来越小了。
5)定期对核心系统进行压测,根据实际流量情况做好机器扩容和缩容的评估。目前 Qunar 内部可考虑使用流量调权压测系统 。

总结
本次稳定性治理已经告一段落,从日常运维和治理手段做下回顾:
日常运维方面,提前做好核心应用的跨机房部署、相关组件的高可用及服务冗余,发布及高峰期后做好服务巡检,通过定期的压测及故障演练去验证应用的健壮性及相关工具的可用性,并尝试引入 AIOps 自动定位故障原因。
治理手段方面,借助降级、熔断、限流、隔离、多通道、多副本等手段对核心资源进行治理。

想让一个应用永远不出故障很难,但是提升应用高可用的手段很多,这些手段的合理使用对应用的稳定性特别重要。同时,稳定性单独治理一次也是不够的,需要组内每个成员不断提高这方面的意识和能力,并在日常工作中将这些治理项及注意点落实。
最后,希望这次实践能对更多的人有指导作用。
作者介绍:
郑吉敏,2019 年 8 月加入国内酒店报价中心团队,主要负责报价相关系统开发及架构优化。对高并发高可用有浓厚兴趣,有日订单千万分布式系统高可用建设经验。喜欢钻研算法,acmicpc 程序设计大赛两次进入亚洲区预选赛。曾在 Qunar 首届 Hackathon 大赛中获得一等奖。
评论