这是 2017 年的 promcon 的分享,原文地址在这里,作者 Julius Volz,今天偶然看到,虽然已经过去 6 年,有些实践经验还是非常值得学习。做个意译,加入一些自己的理解,分享给大家。

埋点方面

1. 所有模块都要埋点

我印象中 Google 有个规范,所有的服务模块,都需要通过 HTTP /varz 接口暴露监控指标,即便是一个纯后端的 RPC 服务,也要暴露一个这样的 HTTP 接口。当然,实操的话,应该是通过框架来统一埋点,但是统一埋点只能埋入一些通用的指标,如果涉及一些自身业务逻辑相关的,还是需要自行埋点。

2. 借鉴 USE 方法论

USE 方法论,即 Utilization、Saturation、Errors 三个维度,即资源的使用率、饱和度、错误。这三个维度,可以用来衡量一个资源是否健康,如果有一个维度不健康,就需要考虑扩容或者优化。USE 方法论提出者是著名大神 Brendan Gregg,他的博客里有很多关于性能优化的文章,非常值得一读。

3. 借鉴 RED 方法论

RED 方法论,即 Request rate、Error rate、Duration,托生自 Google 的四个黄金指标,主要用来衡量微服务的健康度,RED 方法论的原文在 这里

4. 指标命名要有规范

Prometheus 的指标命名,其实是没有约束的,也没有单位的概念,但通常会有一些约定,要尽量遵守,比如:

5. 注意标签基数爆炸

在 Prometheus 生态里,一个时间线的唯一标识是一个 labelset,即多个标签的组合(指标名称其实也是一个特殊标签,标签 Key 是 __name__)。比如 disk_free{host="10.1.2.3", fstype="ext4", path="/data"} 唯一标识了一个时间线。其中 disk_free 是指标名称,实际底层处理的时候,会处理成:{__name__="disk_free", host="10.1.2.3", fstype="ext4", path="/data"},所以说标签集合是唯一标识一个时间线的。如果任一标签变化,就会当成一个新的时间线。一些高基数的信息,就不适合作为标签,比如:

  • 用户访问的来源 IP
  • 用户的 ID
  • 用户请求的 TraceID

6. 统计失败+总量而不要统计失败+成功量

考虑下面两个 counter 指标:

  • failures_total
  • successes_total

如果要计算失败率,可以这么写:

rate(failures_total[5m])
/
(rate(successes_total[5m]) + rate(failures_total[5m]))

写起来相对复杂一些,如果我们统计失败+总量:

  • failures_total
  • requests_total

失败率的计算就会变简单:

rate(failures_total[5m]) / rate(requests_total[5m])

7. 使用默认值提前初始化指标

假设有这么一个指标:ops_total{optype="<type>"},显然,这是想统计不同类型的操作的次数,但是如果某个类型的操作一次都没有发生,那么这个指标就不会出现在 Prometheus 的时间序列里,但你可能在 Grafana 图表和相关告警规则中用到了这样的语句:sum(rate(ops_total{optype="create"}[5m])),如果 create 一次都没有发生,那就没法工作了。一般我们建议,代码埋点的时候要做初始化,比如下面的 Go 语言例子,把已知的操作类型都初始化一下:

for _, val := range opLabelValues {
// Note: No ".Inc()" at the end.
ops.WithLabelValues(val)
}

当然,填充默认值的这种方式并非总能奏效。比如 http_requests_total{status="<status>"} 这样的指标,status=~"5.." 过滤器查不到数据时会破坏整个 promql,此时有个比较 tricky 的方法是使用 or 语法:

<expression> or up{job="myjob"} * 0

更多信息可参考这个文章

8. 避免使用无法识别的额外信息标签

比如机器的指标,disk_usage_bytes,如果某个机器部署了服务A,你可能会想这么打标签:disk_usage_bytes{service="a"},但是如果后面这个机器改变了用途,不再部署服务A,而是部署服务B,这个磁盘使用的指标就会变成 disk_usage_bytes{service="b"},而这,由于标签变化,就会导致 Prometheus 会认为这是一个新的时间线,而不是原来的时间线,导致时间线数据不连续。

那怎么办?可以使用 group_left 附加额外标签的方式,具体可以参考这个文章

关于告警

Rob Ewaschuk 有一篇广为流传的文章:My Philosophy on Alerting,推荐大家 Google 一下阅读一下。

9. 告警症状而非原因

原因类指标可以放到仪表盘上用于后续问题根因排查,症状类指标,通常反映的是上层用户的感受,啥是症状类指标?比如:

  • 某个关键服务延迟高,或错误率高
  • 某个磁盘即将在未来 4h 内写满

10. 注意 target 缺失告警

比如下面这个告警规则:

ALERT HighErrorRate
IF rate(errors_total{job="myjob"}[5m]) > 10
FOR 5m

看起来挺好的,但是如果你的 target down 掉了或者压根没有被 Prometheus 发现,上面的表达式查不到数据,自然就不会告警。建议,对于关键指标,要一并配置 up 和 absent:

ALERT MyJobInstanceDown
IF up{job="myjob"} == 0
FOR 5m ALERT MyJobAbsent
IF absent(up{job="myjob"})
FOR 5m

11. 告警规则通常要配置持续时长

比如下面的告警规则,没有配置持续时长:

ALERT InstanceDown
IF up == 0

如果有一次抓取失败,就会告警,但实际上可能是网络抖动,实际的 target 是健康的,所以建议配置持续时长:

ALERT InstanceDown
IF up == 0
FOR 5m

12. 注意保留关键标签

举例:

Don't:

ALERT HighErrorRate
IF sum(rate(...)) > x Do (at least): ALERT HighErrorRate
IF sum by(job) (rate(...)) > x

读者可以在即时查询里体验一下,sum 之后,如果不加 by 的逻辑,所有便签就都没了,告警事件发出来信息太少,所以一般建议把关键标签放到 by 后面分组统计。

关于查询

13. 查询表达式通常要过滤到job颗粒度

不同的 job 可能有相同的指标名字,为了避免冲突,尽量把 job 作为过滤条件:

Don't: rate(http_request_errors_total[5m])
Do: rate(http_request_errors_total{job="api"}[5m])

14. 注意 rate() 和 sum() 的顺序

对于 counter 类型的指标,如果服务重启,指标会被重置,从 0 开始重新上报,rate() 函数可以修正这种情况,比如:

正常来讲,应该先求 rate(),再求 sum(),如果弄反了,就麻烦了,比如下面的例子:

译者注:要想玩转 Prometheus,其实还是有门槛的,但是大部分公司首先会把人力投入到自己的赚钱业务上,监控或者可观测性系统,这种偏辅助类的基础设施,没有精力搞,巧了,我们创业就是提供可观测性平台和服务,如果您对我们放心,欢迎联系我们,我们会提供一流的服务。

译者:秦晓辉,Open-Falcon、Nightingale、Categraf 等开源项目创始研发人员,极客时间专栏《运维监控系统实战笔记》作者,目前在创业,提供可观测性产品,微信 picobyte,欢迎加好友交流,加好友请备注公司。

微信公众号不好贴外部链接,更好的阅读体验可以访问:https://flashcat.cloud/blog/prometheus-best-practices-and-beastly-pitfalls/

Prometheus 14 点实践经验分享的更多相关文章

  1. 领域驱动设计(DDD)的实践经验分享之ORM的思考

    原文:领域驱动设计(DDD)的实践经验分享之ORM的思考 最近一直对DDD(Domain Driven Design)很感兴趣,于是去网上找了一些文章来看看,发现它确实是个好东西.于是我去买了两本关于 ...

  2. 领域驱动设计(DDD)的实践经验分享之持久化透明

    原文:领域驱动设计(DDD)的实践经验分享之持久化透明 前一篇文章中,我谈到了领域驱动设计中,关于ORM工具该如何使用的问题.谈了很多我心里的想法,大家也对我的观点做了一些回复,或多或少让我深深感觉到 ...

  3. 关于Flask使用Celery的实践经验分享

      最近大Boss反馈Celery经常出现问题,几经实践终于把问题解决了!于是乎有了这篇博客的诞生,算是一个实践经验的分享吧! 软件版本如下: Celery () Flask () RabbitMQ( ...

  4. 我的devops实践经验分享一二

    前言 随着系统越来越大,开发人员.站点.服务器越来越多,微服务化推进,......等等原因,实现自动化的devops越来越有必要. 当然,真实的原因是,在团队组建之初就预见到了这些问题,所以从一开始就 ...

  5. 还原火山引擎 A/B 测试产品——DataTester 私有化部署实践经验

      作为一款面向ToB市场的产品--火山引擎A/B测试(DataTester)为了满足客户对数据安全.合规问题等需求,探索私有化部署是产品无法绕开的一条路.   在面向ToB客户私有化的实际落地中,火 ...

  6. CI Weekly #6 | 再谈 Docker / CI / CD 实践经验

    CI Weekly 围绕『 软件工程效率提升』 进行一系列技术内容分享,包括国内外持续集成.持续交付,持续部署.自动化测试. DevOps 等实践教程.工具与资源,以及一些工程师文化相关的程序员 Ti ...

  7. (转)CMOS Sensor的调试经验分享

    CMOS Sensor的调试经验分享 我这里要介绍的就是CMOS摄像头的一些调试经验. 首先,要认识CMOS摄像头的结构.我们通常拿到的是集成封装好的模组,一般由三个部分组成:镜头.感应器和图像信号处 ...

  8. 关于启用 HTTPS 的一些经验分享(二)

    转载: 关于启用 HTTPS 的一些经验分享(二) 几天前,一位朋友问我:都说推荐用 Qualys SSL Labs 这个工具测试 SSL 安全性,为什么有些安全实力很强的大厂家评分也很低?我认为这个 ...

  9. Expression Blend4经验分享:自适应布局浅析

    今天分享一下Blend制作自适应分辨率布局的经验,大家先看下效果图: 这是一个标准的三分天下的布局,两侧的红色区域是背景区域,是用来干吗的呢,下面简单的分析一下,大家就明白了. 1.拿到一个项目,进行 ...

  10. Expression Blend4经验分享:制作一个简单的图片按钮样式

    这次分享如何做一个简单的图片按钮经验 在我的个人Silverlight网页上,有个Iphone手机的效果,其中用到大量的图片按钮 http://raimon.6.gwidc.com/Iphone/de ...

随机推荐

  1. Kruise Rollout:灵活可插拔的渐进式发布框架

    简介: Kruise Rollout 是 OpenKruise 社区开源的渐进式交付框架.Kruise Rollout 支持配合流量和实例灰度的金丝雀发布.蓝绿发布.A/B Testing 发布,以及 ...

  2. Flink 源码 | 自定义 Format 消费 Maxwell CDC 数据

    Flink 1.11 最重要的 Feature -- Hive Streaming 之前已经和大家分享过了,今天就和大家来聊一聊另一个特别重要的功能 -- CDC. CDC概述 何为CDC?Chang ...

  3. 供应链商品域DDD实践

    简介: DDD是一套方法论,实践能否成功,不仅仅是个技术问题,更是执行贯彻实施的问题.本文将就DDD的基本概念和DDD的实施进行分享. 作者 | 侧帽来源 | 阿里技术公众号 前言 供应链商品域DDD ...

  4. 云原生 DevOps,模型化应用交付能力很重要!

    ​简介: DevOps 文化及其支撑其落地实践的自动化工具与平台能力在云原生架构渐为普及的背后,发挥了关键的价值. 撰稿:溪洋 云原生正在成为企业业务创新和解决规模化挑战的加速器. 云原生带来的变革绝 ...

  5. 阿里云重磅发布业务中台产品 BizWorks,中台发展进入下一个阶段

    ​简介: 业务中台产品BizWorks重磅发布,这可以看作是阿里云在 "做厚中台" 战略上继 "云钉一体"之后的又一个新动作! 10 月 19 日,2021 云 ...

  6. [Go] Colly 使用 POST 提交 application/x-www-form-urlencoded 示范

    Colly 提供了 Post 和 PostRaw 方法,它们的参数类型不一样,需要注意. 目标地址接受指定的 Content-Type,可以通过设置 request Header. 局部代码: // ...

  7. WPF 笔迹触摸点收集工具

    本文来安利大家一个工具,可以用来收集笔迹的触摸点,这个工具完全开源 在开始之前先看一下工具的界面 实现方式其实就在触摸的时候收集触摸点信息,上面的工具有很多功能都没有实现的.笔迹绘制的功能使用 WPF ...

  8. SQL 多表关联更新语句

    A表WHERE条件来自B表查询结果集 UPDATE a SET a.is_sync = 0 FROM A表 a LEFT JOIN B表 b ON a.order_id = b.order_id AN ...

  9. Mac安装mysql5.7

    1.下载文件(访问就直接下载了) http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.10-osx10.10-x86_64.dmg 2.打开下 ...

  10. 【web安全】隐藏nginx头文件信息

    摘要 Nginx作为开源web中间件,被广泛应用.因此源编译或者yum安装,都会带有其原有的nginx版本.很容易被针对,因此,通过修改nginx的源码.隐藏nginx版本和头部信息,保障nginx的 ...