关于可观测性
记录所有事件的所有上下文,对调试或者了解当前系统的状况,于技术、于业务而言,都是非常有益的,但是需要处理和存储海量的数据,这是不现实的。
大概有四种方式来减少数据量,让处理和存储这些数据变得可实现:
-
Profiling(性能剖析)
特点:只采样短期内发生的事件,包含完整上下文
例子:tcpdump
-
Tracing(追踪)
特点:按比例采样所有事件的一部分(N%),关注调用链
例子:jaeger
-
Logging(日志)
特点:只记录特定事件,上下文丰富,大致分为:
- 事务日志(例如涉及钱,不能丢失)
- 请求日志(尽量不丢失,丢失了问题也不大)
- 应用日志(例如启动消息、后台任务,主要是给人阅读,不会有很多)
- 调试日志(量多,只应用在调试情景,可以随意丢失)
各种日志的处理方式不能一概而论
-
Metrics(监控指标)
特点:关注计数,上下文几乎没有
指标类型
Counter
累计值,只增不减。通常用来记录事件累计发生的次数,用于表现事件在时间轴上发生(次数):
例:rate(user_logins_total[1m])
Gauge
快照值。通常用来直接表现状态在时间轴上的变化:
例如:temperature
Summary
对应两个累计值,只增不减。一个记录事件累计发生的次数,一个记录事件属性的累计和,主要用于表现事件在时间轴上发生(与否),以及事件发生时的属性均值:
例如:rate(request_latency_seconds_sum)/rate(request_latency_seconds_count)
如果使用了 quantile,还会有若干个 Gauge 值对应事件属性百分位值的快照:
50%的请求延迟小于这个值:request_latency_seconds{le="0.5"}
75%的请求延迟小于这个值:request_latency_seconds{le="0.75"}
95%的请求延迟小于这个值:request_latency_seconds{le="0.9"}
注意:百分位值在客户端计算,需要消耗客户端资源。
Histogram
对应 2 + N 个累计值,只增不减。一个记录事件累计发生的次数,一个记录事件属性的累计和,其余N个记录事件在N个属性值区间上累计发生的次数:
前2个累计值的使用和 Summary 类似。
剩余N个累计值:
请求延迟值(秒)命中 [0, 0.1] 区间的累计次数:
request_latency_seconds_bucket{quantile="0.1"}
请求延迟值(秒)命中 [0, 0.5] 区间的累计次数:
request_latency_seconds_bucket{quantile="0.5"}
请求延迟值(秒)命中 [0, +Inf] 区间的累计次数 = 请求累计次数:
request_latency_seconds_bucket{quantile="+Inf"}
90%的请求延迟小于这个值(百分位值):
histogram_quantile(0.9, rate(request_latency_seconds_bucket[1m]))
注意:计算发生在服务端,计算结果的精度和 bucket 区间个数、每个区间的大小有关。
指标命名
- snake case
- 使用(无前缀)基本单位的复数作后缀,例如seconds、bytes,而不是 milliseconds、kilobytes
- counter 再带上 total 后缀
监测的对象
服务
-
在线服务
监测要点:request rate, latency, error rate
-
离线服务
监测要点:queued work, in-progress work, work process speed, error
可以类比为水池,需要关注水位、水位变化速度(水流入速度 - 水流出速度)
-
批处理作业
通常是定时作业,并非24小时运行
监测要点:和离线服务类似,但是需要 push gateway 辅助收集指标
库
关注报错以及打日志的地方
何时使用标签
指标使用了某标签K=V以后,如果无视标签K进行聚合,得到的结果还有意义,说明可以使用这个标签。
容量规划
可以简单地认为 prometheus 最多能处理 1000 万个时间序列
再预设最多有 1000 个被监控的实例,每个实例平均能占用 10000 个时间序列
1 个 Gauge/Counter 占用的时间序列数 = 1 x (标签1的的值个数) x (标签2的的值个数)x(标签3的的值个数)x ... x (标签N的的值个数)
注意:要排除 instance 标签,已经被当成 1000 个值计算过了
1 个 Summary 占用的时间序列数 = (同 Gauge/Counter) x (2 + quantile 数)
1 个 Histogram 占用的时间序列数 = (同 Gauge/Counter) x (2 + bucket 区间数)
大部分指标占用的时间序列应该少于10个
少部分指标占用的时间序允许在100个左右
如果把某个标签的值展开,变成多个指标(标签值移入到指标名),例如 http_requests_total => http_get_requests_total, http_post_requests_total, http_put_requests_total ... 占用的时间序总数并没有发生变化,还加大了聚合的难度