目录

前面三篇从基本概念到具体实践,再到原理分析,我们大致了解了Prometheus监控告警系统以及周边技术。本篇干货不多,主要探讨几个发散性的问题并给出我个人总结和思考的结果

  • ELK也可以做监控,和Prometheus有什么区别?
  • Prometheus在多个数据中心怎么部署?
  • 哪些指标要监控?哪些问题要告警?有哪些最佳实践?

Prometheus方案与基于日志的监控告警方案对比

基于ELK技术栈统一收集的日志可以做很多事情,除了的日志分析、日志流式计算、链路追踪,也可以做监控告警。ElasticSearch的存储和查询能力加上Kibana不输Grafana的可视化能力,做监控毫无压力,Elastic官方也提供了更专业的全家桶方案:Metricbeat + ElasticSearch + Elastic APM + Kibana。这个全家桶没有用过,在此不做评价,这里讨论的是基于日志打点的监控和Prometheus监控方案的比较

ELK栈监控方案有哪些优缺点呢?

  • 优点1:对现有系统侵入小,比如监控QPS,只需要画一个某个业务日志关键字的搜索结果折线图即可
  • 优点2:可以做更具体也更灵活的事情来扩展监控,比如可以基于日志记录的TrackingId,做分布式链路追踪,或是聚合分析Json日志的多个属性
  • 缺点1:文本数据往往需要额外的数据清洗转换,才可以做复杂的业务监控,ELK栈各组件也都不是省油的灯,运维成本较高
  • 缺点2:日志的异步处理使得ELK方案的*实时性相比时序数据库方案稍差
  • 缺点3:Elastic的告警功能得花钱买商业版License,OSS版本或Basic License没有告警功能

所以实际场景中,二者并不矛盾,往往是结合两种方式,在不同层次上用更合适的方案,实现功能互补,自底向上推荐这样使用:

  • 物理机/虚拟机节点硬件指标 - Prometheus / 云服务自带的方案
  • 容器以及容器编排系统 - Prometheus
  • 依赖组件或中间件(DB, Cache, MQ等) - Prometheus / 云服务自带的方案
  • 应用服务的Runtime - Prometheus集成对应语言或技术框架的特有方案,如JVM的JMX
  • 能够输出日志的具体业务 - Prometheus & ELK 并用
  • 更加宏观的应用性能管理(APM)时序数据 - Prometheus & ELK 并用

多数据中心监控告警方案的实践和思考

多个数据中心的情况下,需要有一个统一化的监控告警,实现多级、立体的监控告警。在大于两个数据中心的生产环境中,Prometheus用起来就没有那么方便了:

  • 每个DC部署一套:数据分散,没有整体监控入口
  • 只部署一套收集所有DC的监控数据:可用性相对较低,容易遇到Prometheus HTTP方式收集监控数据导致的性能瓶颈
  • Federation模式:N+1部署加上数据同步,相对复杂而且数据复制到顶层Prometheus的可靠性有待考证(https://www.robustperception.io/federation-what-is-it-good-for

虽然理论上Federation模式是个不错选择,但在实践中我们用了一种更加接地气的方案,这里分享一下。

  • 对于监控:每个DC一套2实例Prometheus,不部署顶层Prometheus,但把Grafana部署在全局,配置N个Prometheus数据源,创建跨DC监控图表选择Mixed数据源即可
  • 对于告警:每个DC部署3实例AlertManager,告警规则在统一的Git仓库维护,核心指标搭配Zabbix双路告警确保告警通路

这套方案实践起来效果不错,一方面DC独立的Prometheus确保的收集性能,全局Grafana虽然查询稍慢但能够统一入口;另一方面DC内部的AlertManager直接告警,使得告警链路最短,搭配冗余告警策略解决告警系统的可用性和自告警问题,并且不用废弃遗留的监控系统。

期间走了一个弯路:在Grafana上配置统一告警。Grafana非常易用,做图表可视化一流,但的确不适合告警,原因由这些:

  • Grafana的Alert并不支持分布式特性,因为每个实例都会计算所有告警规则https://grafana.com/docs/tutorials/ha_setup/—),多实例部署Alert会有问题,而且密集计算也不是NodeJS擅长的事情
  • 违背了尽量减少链路上可能的故障点这一原则,多一层Grafana挂了导致收不到告警的风险
  • Grafana缺少对告警的分组,静默,抑制等功能特性,不满足需求

因此我们最终使用了统一的Git维护告警规则,分散部署AlertManager的方案。如果业务体量再大一个数量级,开源方案就不合适了,比如国内外各大厂都是自研或二次开发自己的监控告警系统。

监控告警策略最佳实践

通过学习和实践,最终会沉淀一些道理和普适经验,也就是所谓的”最佳实践”,这里再分享几个监控告警相关的最佳实践

  • 避免”狼来了”问题,减少虚警。 哪些指标应该告警?这个问题可以转换成”哪些指标会影响到用户?”,最终我们可以提炼出来四个核心指标”延迟,流量,错误,饱和度“。
    • 延迟和错误直接影响了用户,添加告警时尤其要注意延迟中的长尾效应
    • 流量指标比如PV、UV、QPS、TPS其重要性不言而喻,是商业和技术决策的核心指标,并且与饱和度相关联;
    • 饱和度可以理解为当前实际负载占最大承载能力的比例,一旦超出某个界限可能导致雪崩效应。根据历史指标数据预测承载能力的临界点,能够防患于未然,比如预警磁盘什么时候将要写满,预测几个月后的用户量是否会让CPU处于高负载等等。
  • 分级响应,设置轮值机制。小问题不应该惊动所有人,大问题应当尽早通知到所有相关人员,明确分工,确保无障碍沟通,这与抗疫的道理是一样的。
  • 先解决问题,后排查问题根源。遇到影响用户的问题首先是解决问题,不管是重启,降级还是主备切换,应该当机立断采取措施,而不是保留问题现场找原因。
  • 交叉监控,增强监控的纵深和层级。告警越少越好,监控多多益善,监控指标之间的相关性也是定位根源的利器,举几个例子:
    • 只做QPS监控,对比QPS监控 + Cache查询监控 + DB监控,显然后者才能更快定位出缓存击穿或雪崩问题;
    • 外部巡检+内部自检交叉监控可以防止内部监控Agent挂掉无处查询监控数据的问题;
    • 传统运维大多只监控机器的CPU、内存、网络、磁盘四大件,定位问题的手段就会有限且低效,这也是传统模式下开发与运维之间的鸿沟导致的。
  • 监控图表立体化,根据关联性对图表分组和并建立层级关系。例如Prometheus Operator自带的Kubernetes Dashboard做的就非常棒,从顶层整个Cluster到底层Pod的关键指标,能够很容易下钻查询到问题所在,Dashboard应该是N维数据立方,而不是一堆孤零零的二维图表。监控图表的聚合、分组、立体化快速定位问题根源是非常关键的。

除了这几条,最佳实践还有很多,不同的人也有不同的观点。其实有很多道理我是学习了《SRE:Google运维解密》之后在实战中明白的。《SRE》是一本好书,浓缩了Google保障服务可靠性实践经验的精华,之前写过一篇读后感 http://code2life.top/2019/05/04/0041-goole-sre-thinking/。也许对于做业务功能开发的程序猿来说,很重要的一点是不要划清和运维的界限,了解到做好运维甚至比业务编码要难,开发-运维闭环互相反馈不断成长,才能构建出抗得住狂风暴雨的服务端