Hi,欢迎来到 卡瓦邦噶!这里是一个 SRE 的博客,讨论的内容有:Linux, Vim, Tmux, NixOS, Python, Java, TCP/IP, Container, Docker, Ansible, Git, Graphviz, Redis, Prometheus, SSH, Shell, Bash, GNU, Github, C, C++, Unix, Nginx, Lua, Django, React 以及运维的方法论,编程的思考,工作的感悟。除了技术上的内容之外,这个博客还会分享一些读书感悟,电影和音乐等。欢迎留下你的评论。

声明:本博客内容仅代表本人观点,和我的雇主无关。本站所有内容未加说明均为原创,一经发布自动进入公有领域,本人放弃所有权利。转载无需本人同意。但是依然建议在转载的时候留下本博客的链接,因为这里的很多内容在发布之后会还会不断地继续更新和追加内容。

PromCon 2022 演讲:Alerting with Confidence

我从 2018 年就在做和监控告警相关的工作,到现在已经有差不多5年了。之前几年集中在报警的自动化处理上,后来发现这样做效果太少,治标不治本,后面在 Shopee 主要关注提高 Alert 的设置准确性和处理流程上面,我认为这样可以从根本上解决问题。

今年在 PromCon 上做了一个演讲,介绍了从 Alert 的配置,到触发,最后 Review 的一些经验。

演讲是英文的(虽然我的口语也不太好),视频已经上传到了 Youtube:https://www.youtube.com/watch?v=OWZU3S44ss0

Slides 地址:https://github.com/laixintao/alerting-with-confidence

 

没来的请举手

我们需要在一个 VPC 网络环境中采集一些服务的 metrics,TSDB 存储在中心机房中,存储节点、中心节点和采集端的网络是不通的,要访问的话必须开通防火墙配置。网络架构大体如下:

直接从 central 去访问应用的 metrics 暴露端口采集数据,肯定不显示,这样的话要开通的防火墙太多了,也就失去了防火墙的意义。

怎么才能尽可能少的开通防火墙,又保证数据采集呢?

最直观的方法是,直接用 vmagent 部署在 VPC 本地采集数据,采集之后将数据发送到 central 机房。

那么又有了一个问题:监控的监控。我们怎么去监控采集端 vmagent 的健康呢?简单的方法是,直接开一个双向的防火墙白名单,我们从 central 直接去监控 vmagent。但是我想到一个方法,可以免掉这个防火墙。

第一步,我们将 vmagent 的采集 target 加入到它自己的采集列表中,即,让它自己收集它自己的 metrics,然后发送到 central。

然后我们再配置 alert,难点就在这里。

Prometheus 触发 alert 的规则是:

  • 如果表达式的 evaluate 结果是 null,说明不满足条件,不 fire
  • 如果表达式的 evaluate 结果有值,说明满足设定的条件,fire

我们用如上的模式采集 vmagent 的 metrics,就会有这个问题:假如 vmagent 挂了,那么不会有人把 metrics 发回来,也就不会有 prometheus 的 up metric, 如果我们设置一个 alert rule: up < 1 , 也就不会 fire。就遇到了这个问题:没来的请举手。

解决方法是,既然已经确定这个 target 必然会存在,可以将默认值设置为 0,如果有值的话,会被 overwrite 成1.

PromQL 原生的表达式:

MetricsQL:

这样,只有确定采集端 vmagent 是 up 的时候,才不会触发 alert。

这个查询表达式对 Push 到 Prometheus 的模式也同样适用。

另外还有一个方法可以解决这个问题,就是在 VPC 中搭建两个 vmagent,互相采集对方的 metrics,发送回来。这样有一个缺点,就是如果中间的网络有问题,那么两个 vmagent 就会一起挂掉了,不会有 metrics,也就不会触发 alerts。

参考:

  1. https://nklya.medium.com/promql-how-to-return-0-instead-of-no-data-9e49f7ccb80d
 

婚礼回顾和一些经验分享

我在国庆完成了和老婆的婚礼,这件人生大事从计划到完成花费了至少1年的时间,牵扯了上百人的精力,值得记录一下自己的感受。

一场婚礼是非常耗费精力的事情,涉及到两大家族长时间的准备。一个家族内部之间的矛盾可能在这个过程被激发出来,鸡毛蒜皮的事情可能会导致出来一些纷争,牵扯出很久时间之前的恩怨;两个家族之间的价值观也会受到考验。事后来看,有些人之间的感情会更好,因为一起经历过了这件大事,有些人的感情可能会变差——由于有些地方事情办得不好。

家庭和亲戚们不是人能选择的,所以协调这样一个团队去完成一个大项目,本身就是一件很复杂的事情。

首先趁着记忆总结一下办一场尽量完美的婚礼的一些经验:

  1. 所有能提前做的事情都从确定结婚时间开始就准备,至少需要3个月的时间。包括:
    1. 拍婚纱照(需要预约档期)
    2. 定制西装(一般需要一个月)
    3. 租用婚纱(或者购买,也需要提前)
    4. 预定酒店(良辰吉日需要提前至少半年)
    5. 确定摄影跟拍、录像、司仪、跟妆的档期
    6. 找一个靠谱的婚庆
    7. 等等,只要现在具备了开始做的条件,就立即开始动手去做,不要说“这件事等提前一个月准备”就够了,能现在完成的事情就现在完成
  2. 确定整体的流程,要有一个在线的文档,跟所有的参与人员同步信息,就像项目管理一样。比如每一个时间该做什么事情,需要什么物件/物料,主要负责人是谁,联系电话等。
  3. 婚礼流程事无巨细落实,比如改口茶在哪里做,谁在场,杯子准备好了没,茶准备好了没,要说什么,要做什么,这个环节的负责人是谁,等等。
  4. 每一件事必须安排给一个负责人,不能是多个。比如签到处,可以安排3个人,包括引导员(入座),负责收红包记录礼金(很重要,千万不能收到无名红包),替班(不能只安排一个人让签到处没时间上厕所)等等。但是必须有一个签到处负责人,有事情打负责人电话,安排给负责人。告诉他他的职责。如果没有一个明确的负责人,很多任务无法落实。现场团队也必须有一个负责人,现场任何问题都直接找他,比如有客人临时参加没有位置,要现场负责人来解决。负责人一定要找靠谱、办事认真的人,否则一定会乱套。同步给所有准备婚礼的人,哪一个环节出了问题要找谁。
  5. 座位问题:邀请人参加婚礼,一旦确定客人要参加,一定问清楚是会来多少人,如果带小孩,小孩几岁。(酒店一般免费加宝宝椅但是不能加座位)。极力避免有客人来了没有找到自己的座位,或者到了之后发现自己的座位被占用的尴尬情况。(很尴尬我们就遇到了有客人没有位置吃饭的尴尬情况)
  6. 婚礼执行过程遇到任务不要抱怨,遇到问题只去想怎么能够解决。遇到一些有任务的人丢了东西,忘了流程,很正常,发火、抱怨没有用。我知道这些事之后从没有埋怨人,马上开始重新做补救措施。
  7. 预留充足的时间,因为整个流程完全按照计划发展几乎不可能(我们就取消了外景拍摄环节才让其他环节都顺畅)
  8. 摆正心态,这场婚礼最重要的是谁,是给谁办的,想明白这个问题,然后其他的问题都以这些人会不会高兴为准。
  9. 七大姑八大姨的“风俗”都去掉。这个博客的读者肯定不会认为“新娘的脚一旦落地”会让新人不幸福吧?按照我帮忙别人准备婚礼和我自己的婚礼的经验,每一次婚礼都会有 N 多人中间调出来说“哎呀你们没按规矩办啊!新娘不能xxx,新娘不能xxx” “发车时间得是几点几分”,“婚房外人不能进啊,摄影师拍摄也不能进!”。这些人就和恐怖分子一样来破坏婚礼,我在我们村随便拉一个大妈她都能我们全家说出来一些谁都没见过听过的习俗,这些习俗不知道也就罢了,知道了你不按照这些人说的办还心里膈应。所以,我的建议是,回到8,不是给这些亲戚或者外人办的,是给双方父母和我老婆(对我来说)办的,这些习俗对他们重要吗?重要,那就严格遵守;如果不重要,这些人爱咋说咋说。要和家人沟通好,任何中间跳出来的风俗习惯,就当听不见。
  10. 来帮忙的人不是越多越好,多给靠谱的人安排工作,不要不好意思,事后谢礼到位就行,记着人家的人情。不靠谱的人不如不来。
  11. 作为东道主,远道而来的客人需要好好招待。
  12. 婚庆的质量决定了整场婚礼的质量。一定要好好找,但是这个行业我觉得水很深,好在我的叔叔是做这一行的,我的婚礼是他操办的,非常成功。
  13. 敢于下判断,很多问题是能用钱解决的,不要过于纠结和花费过多精力。比如有临时客人来参加婚宴,现在看来位置不够直接加一桌要比重排座位要好。

其实无论是谁,第8个问题的答案一定是自己的爱人。这个很重要。

婚礼涉及的事情太多了,双方家庭一定会有在某些事情上不一致的地方,这对两个家庭的结合来说就是考验,对小夫妻也是考验,看能否协调好双方家庭。刚办完婚礼的我觉得如果婚礼能和谐地办好,那么以后幸福过日子不成问题。

婚礼看似费神费力,我的心态是,抱着享受过程的心态去准备每一件事,去体验。是一个和自己的兄弟们加深感情的机会(得请大家帮忙,团队合作),是一个双发家庭融合的机会,是一个考验小夫妻和双方父母三观的机会,也是你去认识对方家庭成员的机会,更是一个和自己的妻子加深感情的机会。

无论婚礼办成什么样子,只要第8个问题的答案这些人满意,那就是成功的。

我对自己的婚礼还是很满意的,虽然很累,但是办下来让我觉得很满足,这场婚礼也提醒了我有那么多关心我的人,让我知道这一切是多么来之不易。还认识了很多办事靠谱的人。比如我们的化妆师,从凌晨2点开始几乎没吃过东西,在最后婚礼上敬酒环节(最后一个环节,马上就结束了)依然一丝不苟的化妆,最后一次化妆间就和第一次化妆的细致程度一样,让我顿时觉得我也得成为这样对工作一丝不苟的人)。

最后,结婚旅行也是一个不错的选择。祝各位读者幸福!

 

沉浸式工作

我发现屏幕上会动的东西都会吸引注意力,现在每天又收到很多消息,只要一个小时不看肯定会上百条。这样的工作状态很糟糕,一开始我强迫自己不要去关注未读消息数量,但是尝试了一段时间之后还是发现会不集中注意力。

最好的方法还是全部屏蔽掉实时的消息,在工作中用 IM 是一个很糟糕的主意,很多同事请 SRE 帮助的时候描述不清楚自己的问题,就导致发过去一条消息还要等他的回复。

也尝试过屏蔽一些消息,但是发现屏蔽不过来,总是有新的群拉起来,默认消息就是推送的,也会有新的陌生人过来问一些问题。

如果 IM 工具有“加急”的功能,那么总有一天,人们发送的所有消息都是“加急”的。

既然用户不喜欢使用提交 ticket,那么我们可以把 IM 用成 ticket。

我发现 Dozer网友推荐的一个非常好用的工具,它可以将 Mac 的 Toolbar 上面的活动图标给隐藏掉。

专心工作的时候,只需要留两个图标,一个是时间,另一个是每 30 分钟提醒站立的程序。

而且这个软件的 UI 设计的非常天才,只用两个点就可以完成全部操作。正好满足我的需求:隐藏掉 Toolbar 上面可以动的东西。

这样,只需要在工作的间隙定时去检查 IM 消息就好了。将全部 IM 回复一遍,如果无法一次性将问题描述清楚,就只要等待下一次沟通了。

另外一个烦人的地方是,别人 @我的时候,App 的图标会在 Dock 上跳一下。禁止所有的 App 跳动,可以用下面这两个命令:

  1. defaults write com.apple.dock no-bouncing -bool TRUE
  2. 然后让 Dock 重启一下:killall Dock

 

这样,专心工作的时候,屏幕上就没有会动的东西了。

 

用 PromQL 计算 SLI 和 SLO

用 PromQL 查询出来过去一个月中用掉的 Error budget,然后展示当前的 SLI。效果如下图所示:

这个查询的难点在于,PromQL 查询出来的内容都是时序的值,比如 memory > 0.6 这个查询,查到的所有满足条件的时序的时间和值的对应。让查询的结果是时间,就需要一些技巧。

实现的思路是:

  1. 首先定义分钟级的 up 标准,即 SLO 的定义:1min中如何算是 up 的,如何算是 down 的;
  2. 然后写一个查询,可以查到在一个时间区间内,有多少个分钟是满足条件,up 的,有多少分钟是 down 的;
  3. 最后就可以得到实时的 SLI 结果;

想到有两个思路能实现。

第一个是利用 recording rules. 首先要定义一个 rule 叫做 job:sla_minute_up,这个 rule evaluation 的结果是当前的这一分钟是否满足 up 的所有条件。所以可能是一个很多 and 连起来的复杂表达式。

然后我们只要将所有 up 的分钟数加起来即可,即 sum_over_time(job:sla_minute_up[30d])。最后除以一个月中所有的分钟数:sum_over_time(job:sla_minute_up[30d]) / 30 * 24 * 60,就是最后得到的 SLI。

但是这里面有一个特别重要的地方,就是 sum_over_time 计算的是这段时间内所有出现过的点。比如,假设采集间隔是 15s,那么 up 这个 metric 在每分钟内会有 4 个点,sum_over_time(up[1m]) 正常情况的结果应该是 4. 所以说,使用这种方法的话,recording rules 的 evaluation internal 必须设置为 60s,来做到每分钟只有一个点。

这种方式实际的结果和计算过程绑定了, 所以并不是很好,下面这种方法更巧妙一些。

我们可以换一个思路,直接计算这段时间内满足条件的百分比,然后百分比乘以时间段,就是最终的 up time。

得到这个百分比,首先依然是需要分钟级的 up 定义。不过我们关心的并不是具体的 value,而是是否满足条件,即非是即否。使用 >bool 这个运算,可以将结果转化成 bool,如果满足条件,结果就是1,不满足,结果就是0. 这样,我们只需要计算这段时间内的平均值,就可以得到 SLI 的百分比了。比如说,如果全部是 up,那么结果全部都是1,那么所有时间内的平均是100%。如果出现了不是 up 的点,那么按照占用所有的点的百分比,也是对的。

这个方法就和 interval 无关了。interval 越小,数据点就多,精度会提高。interval 大,那么精度会损失。从客观来讲,表示的真实 SLI 在去掉精度后都是正确的。

如果要表示一天内的 SLI,假设 SLO 只有错误率的话,就可以用下面的查询:

也可以和 Grafana 配合,使用 Grafana 选中的时间区间:

 

参考资料:

  1. https://stackoverflow.com/questions/54292803/calculate-the-duration-in-which-a-prometheus-metric-had-a-certain-value
  2. https://docs.bitnami.com/tutorials/implementing-slos-using-prometheus