dubbo-go icon indicating copy to clipboard operation
dubbo-go copied to clipboard

observability design

Open XiaoWeiKIN opened this issue 4 years ago • 2 comments

本文详细阐述了 dubbo-go 可观测性的设计思路

1. 指标采集

监控系统的四个黄金指标

  • 延迟(latency)
  • 流量(qps)
  • 错误率

​ gRpc 以错误码代表一次调用的返回类型,实际上是和 HTTP/2 对齐的。但是dubbo 协议没有返回码,所以在这里不增加err_status的 label, 希望由 tripe 协议的监控进行采集。

  • 饱和度

    服务容量有多“满”。通常是系统中目前最为受限的某种资源的某个具体指标的度量。(在内存受限的系统中,即为内存;在I/O受限的系统中,即为I/O)。这里要注意,很多系统在达到100% 利用率之前性能会严重下降,增加一个利用率目标也是很重要的。

    在 dubbo-go 这种以RPC调用为主的服务治理框架中,饱和度反映多为协程数量。

2. 长尾问题

下面引用自 《Googel SRE 运维解密》

构建监控系统时,很多人都倾向于采用某种量化指标的平均值:延迟平均值,节点的平均CPU使用率,数据库容量的平均值等。后两个例子中存在的问题是很明显的:CPU和数据库的利用率可能波动很大,但是同样的道理也适用于延迟。如果某个Web服务每秒处理1000个请求,平均请求延迟为100ms。那么1%的请求可能会占用5s时间。[10]如果用户依赖几个这样的服务来渲染页面,那么某个后端请求的延迟的99%可能就会成为前端延迟的中位数。区分平均值的“慢”和长尾值的“慢”的一个最简单办法是将请求按延迟分组计数(可以用来制作直方图):延迟为0~10ms之间的请求数量有多少,30~100ms之间,100~300ms之间等。将直方图的边界定义为指数型增长(这个例子中倍数约为3)是直观展现请求分布的最好方式。

所以采用 Prometheus Histogram 是非常好的方式,这里简单的阐述下为什么不使用Summary :

在Prometheus中,Histogram 会预先划分若干个bucket,Histogram 不会保存数据采样点值,每个bucket只记录落在本区间样本数的counter,即histogram存储的是区间的样本数统计值,在服务端(prometheus)我们可以通过 histogram_quantile() 函数来计算分位数,因此比较适合高并发的数据收集。而 Summary 则在客户端 直接存储了 quantile 数据,它计算的数据比较精确,但是有全局锁,不适合高并发的场景。

3. Histogram 采集数据最佳实践

使用 Histogram 重要的是 bucket 的划分,bucket 太多了或者太少了都不行,而 dubbo-go 提供的划分比较简单。这里 参考 micromete histograms_and_percentiles PercentileHistogramBuckets的划分算法,这个算法是Netfix根据经验值而划分的,预先生成了 1ms-60s 的72个桶。

4. 上报方式

支持使用 push 模式进行数据上报,因为 pull 模式需要 prometheus 支持服务发现,而一些主流的注册中心,比如naocs 还不支持 prometheus。额外暴露一个 port,端口的安全策略也需要保证。若同一个 IP 部署了多个应用,则会导致 port 难以获取,实现起来比较复杂。

5. 指标计算示例

  • 客户端 某个服务 1分钟 TP 99
histogram_quantile(0.99, sum(rate(consumer_service_histogram_bucket{application="$consumer",service=~"$service",instance=~"$consumer_instance"}[1m])) by (le))
  • 服务端 某个服务 1 分钟 成功 qps
 sum(rate(provider_service_histogram_count{application="$provider",service=~"$service",instance=~"$provider_instance",category="successful"}[1m]))
  • 服务端 某个服务 1 分钟 失败 qps
sum(rate(provider_service_histogram_count{application="$provider",service=~"$service",instance=~"$provider_instance",category="failure"}[1m]))
  • 查看 1分钟内 服务端负载是否均衡
sum by (instance) (
  rate(provider_service_histogram_count{application="$provider",service=~"$service"}[1m])
)

XiaoWeiKIN avatar Nov 03 '21 10:11 XiaoWeiKIN

顺路参考了下 grpc go-grpc-prometheus

XiaoWeiKIN avatar Nov 03 '21 10:11 XiaoWeiKIN

另外 协议自身也需要一定的监控,比如协议出入口的流量。但是 filter 做不到这一点,因为他是在通信层之上的,不能获取到出入口流量信息。

XiaoWeiKIN avatar Nov 03 '21 10:11 XiaoWeiKIN