$ ls ~yifei/notes/

监控系统基本概念

Posted on:

Last modified:

“你说说,没有仪表盘的车,你敢开吗?”

按照层级,监控大概分三类:

  1. 业务逻辑:项目所对应的服务其承担的业务逻辑,通常需要对其进行度量。例如:每秒的下单数等。
  2. 应用程序:应用程序。例如:http 请求数
  3. 硬件资源:服务器资源情况等。例如:Kubernetes 中的 Cadvisor 组件便会提供大量的资源指标。

监控系统基础原则

  • Dashboard 尽量简单,不要总想搞个大新闻,花里胡哨喧宾夺主
  • 告警也尽量简单,只发需要处理的告警
  • 简单的架构就是最好的架构,业务系统挂了,监控也不能挂

不要想着把所有的数据都显示到监控上,太多了反倒让人失去重点。想象一下最容易出错的情况, 以及在这种情况下你应该怎么用监控来排错,把这些数据列上去就行了。

  • 一个控制台不要有超过 5 个图。
  • 每个图上不要有超过五条线。当然堆栈图和饼形图除外。
  • 当使用提供的模板时,避免在右手边的表格里有多过 20 个条目。

系统的每个部分都应该有一个监控,至少让你大概知道这个系统现在的情况如何。

也不要想着把特别复杂的业务数据画到监控系统上,监控是监控,业务是业务,不能相互替代。想要 查询业务数据应该用 BI 系统,而不是监控系统。

监控系统的组成

监控系统的基础是时序数据库,现代的监控系统一般都有如下几部分组成:

指标收集 + 时序数据库 + 前端显示 + 报警系统

一般需要实现的功能:

  • 度量数据收集和可视化
  • 收集尽可能多的性能和状态数据
  • 图形化做有意义的展示
  • 如果发现可疑问题,可以关联其他图表找到原因
  • 错误检测
  • 按需告警,触发条件越宽松则告警应该越少
  • 避免误报

从监控的层次划分的话,一般包含三层监控:

  • 基础层:主机的 CPU, 内存,网络及 IO 等
  • 中间层:应用运行的中间件层,Nginx, Tomcat, MySQL, Redis
  • 应用层:服务端及客户端性能数据,如 API 访问次数和响应时间等

现代的监控越来越关注应用层和其他层数据的整合能力,具有快速找到系统瓶颈,方便扩容或代码优化。

时序数据库的选择

监控数据往往都带有时间戳,其实就是一种典型时间序列数据,而这方面已经有很多专门的存储系统, 如 opentsdb,influxdb,prometheus 等。相比 mysql 这样的关系数据库,这类系统在存储、查询上 针对时间序列数据都做了特别的优化。

其中 opentsdb 基于 hadoop 生态系统,考虑到搭建的复杂度,暂时不考虑了。influxdb 和 prometheus 都是 Golang 编写的,直接一个二进制文件就可以运行。两者的区别有:

  • influxdb 采用 push 模式,而 prometheus 是基于拉 (pull) 模式的,也就是说程序不能直接 写入 prometheus,而是需要由 prometheus 去定期拉监控数据,太反人类了。
  • influxdb 的查询类似 SQL,而 prometheus 的查询语法更加简洁,但是有学习成本,各有千秋吧

如何选择监控指标

首先问自己一个问题:当我的程序出了问题的时候,我需要哪些数据来 debug 呢?

Google SRE Book 中提出了四个黄金原则:延迟、流量、错误数、饱和度(需要排队无法提供服务的 时间)。实际使用中对于资源可以使用 USE 指标,对于在线服务可以使用 RED 指标。

  • USE 指标:Utilization、Saturation、Errors。如 Cadvisor 数据
  • RED 指标:Rate、Errors、Duration。如 Apiserver 性能指标

被监控服务的类型

就监控而言,服务大概可以分为三类:在线服务,离线处理 和 跑批任务。

在线服务

此类系统的关键指标在于 QPS, 错误率和延迟。正在进行中的请求的数量也有用。

在线服务系统在客户端和服务端都应该做监控。如果两遍有不同的行为,那么这个对调试是很有意义的。如果一个服务有很多客户端,也不可能让服务监控每个客户端,所以客户端肯定需要依赖自己的数据。

当你按照 query 开始或结束统计数量一定要使用一致的标准。推荐使用结束来作为标准,因为比较容易实现,而且能统计错误和延迟。

离线系统

对每一个 stage, 记录进入的 item 的数量,有多少在处理中,上次你处理某个东西的时间,多少 item 被发送出去。如果你采用的是批处理,也应该记录进出的批的数量。

更好的方法是通过系统发送一个心跳包:一些带着时间戳的 dummy item 通过整个系统。每个 stage 都输出他看到的最近的时间戳,这样你就知道一个 item 需要多长时间才能经过整个系统了。

批操作

关键指标是上次成功操作的时间。

This should generally be at least enough time for 2 full runs of the batch job. For a job that runs every 4 hours and takes an hour, 10 hours would be a reasonable threshold. If you cannot withstand a single run failing, run the job more frequently, as a single failure should not require human intervention.

对于其他的子系统而言,可以选择如下指标

第三方库

如果一个库会访问进程外的资源,比如网络硬盘等等,至少要记录下所有的访问次数,错误和延迟。

Depending on how heavy the library is, track internal errors and latency within the library itself, and any general statistics you think may be useful.

日志

As a general rule, for every line of logging code you should also have a counter that is incremented. If you find an interesting log message, you want to be able to see how often it has been happening and for how long. 一个比较通用的规则,对于每一条日志,应该有一个计数器。如果你发现了一条有有意思的信息,你肯定想知道这件事

错误

Failures should be handled similarly to logging. Every time there is a failure, a counter should be incremented. Unlike logging, the error may also bubble up to a more general error counter depending on how your code is structured.

线程池

对于所有的线程池来说,核心指标是排队的请求的数量,正在使用的线程的数量,总线程的数量, 已经处理的任务的数量和处理任务花费的时间,以及任务排队花费的时间。

缓存

缓存核心指标是总的查询数,命中数,总的延迟以及缓存所对应的线上系统的查询数量,错误率,延迟。

最后

监控的核心目标还是护航业务稳定,保障业务的快速迭代,永远不要忘记因何而来。不要为了监控而监控,盲目提高监控或者告警的数量。

参考

  1. Logs and Metrics and Graphs, Oh my!
  2. Prometheus 和 influxdb 对比
  3. 360 基于 Prometheus 的在线服务监控实践
  4. 虎牙基于时序数据库的直播业务监控实践
  5. 监控系统选型
  6. OpenTSDB/Bosun 报警语法介绍/学习笔记
  7. https://zhuanlan.zhihu.com/p/28127748
  8. Good and Bad Monitoring
  9. https://mp.weixin.qq.com/s/0bDwRtTQdcP7tKI1s76I5g

© 2016-2022 Yifei Kong. Powered by ynotes

All contents are under the CC-BY-NC-SA license, if not otherwise specified.

Opinions expressed here are solely my own and do not express the views or opinions of my employer.