Prometheus & Grafana No Data 排查手册

经常有同事来问我为什么从 Grafana 面板上看不到数据,其实排查思路是基本固定的,按照查询的链路一步一步看每一个组件里面是否有这个数据。之前写了一个排查文档,但是发现没有人阅读,遇到问题还是直接找我。今天画了一个图片版本的,更加清晰一些。在这里也贴一下。点击图片可以查看大图。

 

去远航

之前觉得像泰坦尼克号这样的游轮旅行是距离普通人很遥远的一件事,甚至觉得这种东西不存在了,因为飞机快太多了,水上交通只有轮渡和货轮才有存在的必要。后来听说还有游轮这种东西,但是目的已经不是交通了,而是在船上游玩。

相比于其他旅行,邮轮之旅最好的地方就是几乎不用做攻略,不用做计划,反正一直都在船上,也不需要预定住宿,不需要交通。喜欢什么玩什么,喜欢什么吃什么。非常适合带父母旅行,或者带小朋友来玩。所有的项目都是现场排队,唯一要预定的是丝绸之路演出,但事实证明,不预定也 ok 的,无非入场晚一点而已,观看效果也不会太差。整个行程可以不像旅游一样有压力,当作放松之旅就可以啦。

邮轮的模式

就是你只需要支付住宿的钱,其他的都是免费的,包括:游玩项目,吃饭,观看演出,参加 party。简单来说,预定的时候支付了一笔住宿费,后面都不用花钱了。(我在船上就一分钱没花)。当然,上船之后都有收费项目,比如免费的饮料都不含酒精,酒水是要收费的。游玩项目免费的只是浅尝辄止,想要继续精进(比如冲浪,风洞跳伞)都是要额外付费的。餐厅也有付费餐厅,有的时候付费餐厅的人会去免费餐厅拉客。比较赞的一点是,所有的收费项目都是明码标价,绝对不对在不知不觉中被隐藏小费,体验非常好。

上船之后护照会被收走,发一张房卡,叫做 seapass。航程结束之后不回收,可以留作纪念。在船上很多项目都要刷这张卡,所有的消费也都是刷这张卡消费。有一点神奇的是,在滨城和普吉岛下船的话,也是刷这张卡?! 不需要护照,刷卡绑定照片核对,所以下船的话卡片千万不能丢了。

船上也可以用现金消费,不过用的是美金。(另外船上的紧急电话也是 911,这船就像是美国的飞地)

可以提前下载一个官方的 app,上船之后可以连接船上 wifi。如果购买上网套餐的话,就能上网,如果不购买上网套餐,相当于在一个局域网,只能使用 app:能够看每天的项目,可以在 app 内和船上的朋友聊天,可以看 shiptime (航程如果跨越时区,手机的自动调整在海上是不准确的),可以 reserve 一些项目,也可以看自己的消费账单。

预定方式和价格

官网直接预定即可,即使有其他做旅游的平台和公司,其实也都是在这里订的,然后收你一些手续费。有意向要去玩的话可以多刷一刷他们的网站,不定时会有折扣。房间有不同类型:无窗,有遮挡窗,阳台房,有遮挡阳台房等。我们定的阳台房,阳台房价格一晚1000人民币(每人)算是不错了的,刷到的话可以下手。

正常一间房间就是住两个人,如果是1人去玩的话,价格几乎跟2人一样。带小朋友的话,官网也经常能刷到免费带小朋友的活动。

我们这一次坐的船是海洋光谱号(Spectrum of the Seas)。皇家加勒比是一个比较大的邮轮公司,旗下的邮轮游很多,不同的城市有不同的船和航线,有的时候船也会调往其他地方。海洋光谱号去年和今年(2014年)三月前都是在东南亚的航线,但是3月份就会去上海了,所以官方上可以看到新加坡出发的,从3月开始就没有了。上海的朋友就可以订到海洋光谱号了。也会有一条(唯一一次)从新加坡到上海的单向航线。

选择房间

船头和船尾会晃动的厉害一些,怕晕船尽量选低楼层,船中间的房间。但其实船两头正常人也能接受,船很大,很难晕船的。99% 的时间都是跟陆地一样。

6层和13层会比较吵,因为餐厅,剧院,Party 在4、5层,13层以上是活动区。

房间会有一张沙发,沙发拉出来下面一层也可以是一张床,所以一个房间可以住下四个人。有需要的话可以让客房服务铺好这张“床”。4个人的话也可以订两个房间,然后阳台可以打通(都是组合的钢板,可以拆),也比较舒适。

我感觉船晚上会加速,晃动的厉害一些。有一个小插曲,有一天晚上我总觉得有一些噪音随机出现,找了半天没找到是在哪里发出来的。最后实在受不了,就去前台问了一下。前台说是衣橱里面的衣架,刚刚来了一个人问一样的问题,最后发现是衣架晃动的声音。我回去看了一下,果然是。

吃饭

船上餐厅有收费餐厅和付费。付费的我都没去过,所以不写了。

免费餐厅主要有两种:Main Dining Room 和帆船餐厅。

  • Main Dinning Room 是西餐,仪式感非常强,整套的西餐刀叉,每次进去服务员都会帮女士拉出座椅,菜单也是西式的前菜+主菜+甜品的风格,会吃到一些自助餐厅吃不到的东西。缺点是上菜速度有些慢,如果赶时间看演出的话最好不要去。
  • 帆船餐厅就是自助了,品质相当于景区 Resort 酒店的自助水平,还是不错的,虽然是算不上惊艳,但是很干净,进去之前每个人都要洗手,餐厅很注意卫生,比如,禁止用使用过的杯子二次接水。缺点是有些游客素质差,不排队,没礼貌。

其他还有一些小餐厅,泳池附近有戏水餐厅,有冰激凌站,热狗车,都是免费的。早餐也可以叫 Room Service,在阳台上看着大海吃早餐,也是免费的。

所有的服务员都非常友好,简直是海底捞级别的服务。最后一天每一个餐厅的服务员和厨师都出来跳舞,气氛很赞。

演出

每晚都有演出,这些演出超出我的预期了,非常精彩,有歌舞,杂技,魔术,二人滑稽戏等等。建议观看!一般每个演出在同一天有两场,可以安排下吃饭时间,不要错过。

Party

晚上有各种 party,青少年 party,单身 party,虚拟烟花 Party 等等。

我觉得最有意思的是一个 Silence Party。现场有dj,但是没音响,大家都戴耳机,耳机有一圈 LED 颜色,表示当前的频道的颜色:有蓝绿两个音乐频道,可以自己切换,耳机颜色不同的人可能跳不到一块去,而且自己看不到自己耳机的颜色。有的时候会觉得自己格格不入。关掉耳机,感觉大家都和僵尸一样。

除了 Party,可以留意 app 上提示的当晚服装建议,有正装夜之类的。但是我们的船每天都是 casual.

上网

前面提到过如果买了上网套餐就可以上网了。使用的网络是 starlink,速度测试大约 2MiB/s,但是非常稳定,体验很好,视频通话,看 youtube,Netflix 都是足够的。

上网认证的步骤做的体验很好,首次登陆需要创建一个 wifi 账号,然后后续用这个账号登陆。我们买的是每人1个设备套餐,登陆第二个设备,前一个设备会提示你要不要 logout,wifi 认证成功率 100%,一次都不掉链子。

有一种作弊手段是,用一个路由器连接 wifi,然后将其共享给所有的人用。安卓手机就可以做到这种效果。不过我没用过,看网上这样说可以。

The Key

类似于特权卡吧,买了的话,Seapass 会带有一个 key 的标志。包括的权益主要有:

  • 上网套餐(1设备);
  • 快速登船和下船,包括在目的地下船,比较实用;
  • 上船当天额外一顿午餐;
  • 餐厅固定座位;
  • 演出专属位置:演出前 key 会员先进入,演出前 15min 所有人都可以进入。不顾实际体验是都不管,所以这条几乎没用。

核心卖点就是上网套餐了。在约定游轮之后,邮箱会经常收到折扣信息,我是刷到 35% 入手的,只比购买上网套餐贵了一点点。需要注意的是如果购买的话,必须整个房间一起购买,所以有人认为单纯需要上网的话,The key 比作弊共享的方式贵太多了。

在目的地下船

前面提到过下船不需要护照,只需要 seapass 卡就可以了。不在高峰时间下船,速度非常快,几乎10-20分钟就能到目的地。

下船方式分成两种:

  • Dock: 船会停在码头上,直接出船的 Gateway 就可以从码头出去,没有海关检查,速度很快;
  • Tender: 船不会靠近码头,会有小船从游轮将游客接送到码头。

我们的行程是包括滨城和普吉岛,滨城是 Dock,靠近 George Town,普吉岛是 Tiner,靠近巴东海滩。都是在景区,所以出去转一圈非常方便。

下船的话要注意船上的规定,回来要过安检的,比如酒水就可能不让带上船,买了的话会收走,行程结束归还。

另外,如果去过了目的地,不下船也是一个很好的选择,一个是时间短,这么短也玩不了多少内容。另一个是在下船时间,船上人比较少,可以少排队体验一些项目。

游玩项目

  • 模拟跳伞:就是在风洞里面飞行,第一次体验,挺好玩的。免费体验是 1分钟的课程。
  • 甲板冲浪:分成两种,趴着到跪起来的,和站的的,因为用的不一样的板子,很刺激。但是排队的地方太晒了,注意防晒。
  • 碰碰车:很好玩,有时候很少人排队,可以经常去看看,人少就上。
  • 射箭:个人也比较喜欢。后面人少,也可以尽情玩。
  • 乒乓球:公司就有,所以没啥兴趣。
  • 篮球:也没啥兴趣;
  • 体感游戏机:小朋友很喜欢,我玩的时候有个小孩在指导我,我每次路过都看到这小孩在玩这个,感觉可能是一个 NPC。
  • 儿童游戏厅:不是投币的,是直接刷房卡。
  • 露天泳池
  • 室内日光浴场
  • 泡泡浴
  • 北极星(可以看作是只有一个舱的魔天伦):我们想定的时候系统坏了,可惜了,没体验过。
  • 南极球(我们去的时候关闭了)
  • 高层透明玻璃的走道:惊险又刺激。
  • 以及到处都有的躺椅:躺一躺也是不错的,中间还有露天电影,晚上放电影,白天放可爱猫咪的视频。
  • 赌场:建议出海不要涉赌,我们去剧院的路上要穿过赌场,拍了一些照片。有很多中年人大叔大妈在里面玩。机器的玩法居然也是刷 seapass 卡就可以下注,我觉得这可太恐怖了,没有花钱的感觉,说不定不知不觉就输了一大笔。

~~贴图时间~~

碰碰车欢乐多
甲板冲浪
整整齐齐的餐厅
学习的叠餐巾,跌的是蜡烛
学习叠毛巾,叠的是北极熊
主餐厅的牛排
船头的日光浴场
晚上的船上泳池
演出
从滨城码头看海洋光谱号
滨城,著名的自行车
房间墙壁都是钢铁的,门也是,所以可以用各种磁铁。
演出
Silence party,每个人都戴着耳机
从船上看滨城码头
模拟跳伞
帆船自助餐厅
在阳台上吃早餐,这天到了普吉岛
Costa Serena 号,这艘游轮和我们一起停在了滨城和普吉岛。看起来比海洋光谱号小很多。这是他们的官网
普吉岛的海滩,上次来普吉岛正好是一年前了,可惜这篇游记躺在草稿箱一年还没有写完
从普吉岛的 tender 看海洋光谱号
船的顶楼景色
船上的日落
晚上的船
船上顶层的跑道
回到了新加坡

其他网友写的:

 

站立提醒软件推荐:stretchly

之前在这篇博客《沉浸式工作》推荐过一个站立办公的软件,定时提醒。它好的地方是可以在锁定屏幕的时候认为你正在休息,但是有一个很让我苦恼的问题:就是它的提醒依赖通知,容易被忽略。

尝试了其他几款软件之后,我现在觉得用的 stretchly 非常好,推荐一下。从名字可以看出来,它的本意不是提醒站立,而是定时提醒你休息,伸伸懒腰,眼睛离开屏幕。但是意思差不多。

它工作的方式是用一个页面盖住当前的屏幕,告诉你该休息了。一些细节处理的非常好。

  • 如果有外接屏幕,两个屏幕都会盖住。
  • 当前在使用的 app 也不会失去焦点,降低了误操作的概率,也不会造成意外的错误。

弹出框也是可以暂时跳过的,也可以设置强制模式让它永远不能跳过。

Stretchly 提醒弹出的界面

Mac 安装方法:

也支持 Windows 和 Linux,更多安装方式见这里官方网站

 

2023 年总结

其实也没有什么好总结的。我若是说说自己今年的流水账,那肯定很无聊。要说技术问题的话,就更无聊的,值得说的事情在博客里应该已经说过了。

那就随便写一写吧,主要记录一下想法,将来回头看看自己每一年的想法,应该也挺有趣的。

感觉最近心境上有了一些变化,比如以前写博客,就是想收获一些名气,运营上会花不少功夫:交换友情链接,要挑选好时间发布,写完了发到很多地方做宣传之类的。现在几乎不会这样做了。现在写博客的目的是什么?我自己都已经想不明白了,可能是单纯想记录一下自己的想法,写完之后也会有一些满足感。

以前也想可以营造某种形象,写出自己漫不经心地解决天大难题的故事,对行业案例、术语侃侃而谈。发现自己到底写不出来这样的文章(倒是读过不少)。有些博客我不喜欢读,是因为字里行间作者不是想分享什么,而是想说明自己有多厉害,知道这么多,或是想说明公司多厉害,这种文章通常知识也不多。比如他们会说:当然对于这个问题我们可以用 XX 解决,但是 XX 是什么?他要假设读者已经知道了,要解释的话就显得水平太低了。

以前会焦虑,现在不会了。以前喜欢强迫自己去学会某一些自己不喜欢的东西,研究一些不感兴趣的技术,细想一下原因,应该是想得到别人的认可,比较在乎别人的想法。现在倒不是很在意了,不懂什么就研究什么。有些对工作和仕途没有什么用的技术,今年也花了很多时间在这上面,比如终端应用啥的。

去年写过:

假如喜欢编程这件事情并且想长久地坚持下去的话,比如 30 年,就会发现有些事情是不重要的,有些事情是重要的。

眼光放长远的话,也就无需焦虑了。慢慢积累,坚持 30 年,很难不成为一个厉害的人吧?

生活上

也是平凡的一年,好像没有什么特别值得说的。

旅行倒是去了不少地方:普吉岛,巴厘岛,去爬了一座火山,去了澳大利亚。算是比较精彩的一年。最后假期居然还剩个 8 天。对了,还完成了新加坡环岛骑行,这可太牛逼了。

工作上

今年的工作大部分是去年工作的延续,每一个季度的 OKR 都没有完成(好像在大公司定制的 OKR 从来没有完成过),感觉 OKR 挺扯淡的,定制 OKR 和实际工作严重脱节:临时插进来的工作又不能不做,SRE 的一部分工作时间也不能自己安排,得看项目的紧急程度。

今年大部分工作都是对已有的项目优化,支持一些公司决定做的事情。

这里面值得一提的是监控系统存储 metrics 随着时间越来越长,索引越来越大了。TSDB 存储时序数据很擅长,但是 metrics 横向的数量过多,就有问题了。集群的索引已经到了 20TiB 级别,查询也还好,可以限制查询范围,没想到出问题的居然是写入链路。写入新 metrics 的时候要在存储节点上先查询要写入的 metrics 是否存在,这些写入前的查询在一些情况下会造成很大的索引查询压力,导致集群雪崩:比如一个存储节点坏掉,所有向这个存储节点在写入的来源都要重新路由到其他的节点进行写入,这时候大家一起进行写入前查询,就足以将其他所有的存储节点都查的干不了任何其他事情,loadavg 升到 500多。写入被停止了,写入来源这时候会将写不下去的监控数据暂时存到本地,等知道 metrics 应该往哪里写了,再将存量 metrics 写回去。可惜的是,一旦存储节点哼哧哼哧把查询完成了,又被大量写入弄崩溃了。这个问题之前没有遇到,跑的好好的,(其他集群和其他公司一般的用法应该遇不到),是因为索引不大问题就不大,20TiB 的索引怎么出来的呢?我们存了1年多的时序数据,历史上的 metrics 都在这个索引里面,就膨胀了。而一般的需求,时序顺序存储1个月就够了。

解决思路略微奇葩,写入前的查询会造成压力,我就拆分了两个存储集群,一个 hot 一个 cold。实时数据写入 hot,只保存 7天数据,每天晚上在低峰期将当前数据移动到 cold,查询的时候两个集群一起查。这样就完美了:

  • hot 集群的索引只有 10G,怎么查都不会出问题,快的很;
  • hot 集群的查询能力也很强了,因为大部分时序数据查询的都是当前数据,hot 集群配置高,实例少,缓存命中率高;
  • cold 集群磁盘大,HDD 盘,成本低,性能低,但是应对 QPS 不到 1 完全够了;
  • 每天的迁移只有在迁移开始的时候会大查询 cold 集群,而且限制并发,不是一起查的,查询结束之后顺序写入性能也贼高;

感觉解决的很完美。

新项目倒是也有一个,做了一个Alert 自动诊断系统,可惜利用率不是很高。

历史长河

经常会忘了哪一年是哪一年,哪一年发生了什么。我印象最深的是 2002 年附近,好像小时候的时间过的很慢,2002 年之后是 2003 年,然后是 2004 年,一直到 2008 年,但是好像 2008 年之后时间变快了,还没熟悉过来新的年份就马上进入到了下一年。有一种 2023 年和 2003 年之间只隔了10年的错觉。

不过我之前发现维基百科有页面记录每一年的大事年表,2023年的简中版本见此

2024,新的一年

先看看去年我写的今年计划:

  • 锻炼身体:上半年还可以,下半年就懒回去了;2024年要继续锻炼身体;
  • 打字训练:算是颇有成果,至少正确的指法了,一年都在刻意用正确的指法打字了,可以盲打所有按键包括符号和数字,甚至连右 Shift 键都能用起来了;
  • 学习:没按照计划学,但是也学了不少东西;

去年的时候感觉自己太活跃了,希望能不写新的项目,下半年还是写了一些,主要是用 textual 这个库做了很多终端工具:

  • flameshow: 一个终端展示火焰图的工具,已经完成;
  • vcron:一个终端计算 crontab 的工具,已经完成;
  • mactop:一个 mac 的类似 htop 的工具,基本完成,但是对 M1 的 macbook 兼容性还有一些问题,没有 M1 的电脑,不方便测试。

新的一年的话,我要认真再学习一下编译原理,最好能实现一个简单直观的、可以定义规则的 DSL。

我的梦想

自从小时候有一次全班同学都要写一下自己的梦想,我就开始思考我的梦想应该是什么。有的看起来就不可能完成,甚至没有努力一下的必要,因为实现的几率太小;有的又太微不足道感觉不值得作为一生的梦想。于是提及这个问题的时候,总是草草找一个比较合适作为答案的来交差。

今年看了很多电影,于是想,看电影真是一件令人快乐的电影,这一辈子要是能看很多电影就好了。那一生能够看多少电影呢?如果一年看 100 部,已经算是比较多的了。那么 50 年也才能看 5000 部!如果真能看 5000 部电影,也算是一件了不起的事情吧。

这样一想,一生看 5000 部电影也是一件不简单的事情:要活 50 年,要身体健康,至少眼睛和耳朵要没问题,智力也要没问题,还得经常有足够的空闲时间……

这也不是一件痛苦的事情。我们谈起梦想,仿佛默认要像苦行僧一样努力很久才能实现。但是何必要这样呢?梦想不能就像一部一部看电影一样呢?看完一部看下一部,每一部都有每一部的乐趣。

实现梦想之后呢?可能有些梦想被实现了之后会让人感到空虚。但是看电影也不会,看完 5000 部电影之后,也不会想:梦想终于实现了,我再也不用看电影了吧。而是找时间去看 5001 部电影。

所以“一生看完 5000 部电影”这个事情作为一个梦想还真是不错。说起来也不至于让人家笑话。

不知道为什么说这个,胡思乱想就写了这么多。其实我是有一个梦想的,只是写出来读者会笑话,就不写了。

说到这里了,就继续说说人生的意义吧。

今年看了一本书叫做 Ask a Philosopher, 有一个问题就是问 The meaning of life.

作者说,他也不知道,但是这不重要。

大意是,假设有一天你意外地发现地球是一个外星人的农场,外星人在地球上放养了很多人,人类的意义就是快速繁殖,吃的白白胖胖,将来有一天给外星人吃掉。这就是人生的意义。

但是知道人生的意义会让我们的生活变好吗?会让我们的精神变好吗?我们应该为了人生的意义——努力地吃和繁殖,然后被外星人吃掉——而去努力吗?显然不是。即使我们的命运就是被外星人吃掉,也不意味着我们应该朝这个方向努力。

我们思考人生的意义,大部分都是低潮的时候。无论人生的意义是什么,它应该指导我们更积极地生活。

既然这样的话,我们应该勇敢地追寻自己热爱的东西吧!而不是寻求人生的意义的真相。

其他的年终总结列表:

  1. 2013年
  2. 2014年
  3. 2015年
  4. 2016年
  5. 2017年
  6. 2018年
  7. 2019年
  8. 2020年
  9. 2021年
  10. 2022年
 

程序的 Metrics 优化——Prometheus 文档缺失的一章

Prometheus 设计的 Pull 模式监控非常优雅:程序开发者只需要做一件事情,暴露出来一个 HTTP 服务,/metrics 返回当前程序的 metrics,就可以了。然后 Prometheus 会定时过来请求 metrics 数据,存储到 TSDB 中。程序只需要关注一件事:暴露 (export) metrics。

如果一开始接触的监控就是 Prometheus,可能觉得这种模式非常自然,符合直觉(就像第一次接触 SCM 就是 Git 会觉得 Git 也很符合直觉一样?)。但是 Prometheus 出现之前,很多公司的做法,是运维人员清洗日志,按照日志特定位置的关键字聚合成 metrics,然后画图,非常麻烦。最大的问题是运维人员会看不懂日志——为了节省空间,很多日志都没有 key,只有分隔符和 value。依稀记得,我的上一家公司为了解决这个问题,还启动了一个项目,叫做“监控代码化”。这和 Prometheus 的想法如出一辙:让开发者来暴露 metrics,因为开发者是最懂程序的。

但问题是,开发者却不是最懂监控的。

我们的监控系统经历过很多次 overload,一般都是伴随着应用发布。开发者不清楚修改 metrics 会对监控系统本身带来多大的压力。我发现就连 Prometheus 的文档也没有专门说明这部分内容。所以这篇博客就尝试介绍一下 metrics 采集量计算的逻辑和优化的方法。

首先,在代码中暴露 metrics 的时候,每一个新的 label value 意味着新的 metrics,比如,下面这三个是三个不同的 metrics。

即使它们的 metric name 相同,也并不意味着什么,这只是给人类看的语法糖。它实际存储起来像下面这样:

代码中(SDK, 比如 golang SDK)一个 metric实例 可能产生多于一条 metrics,比如 Histogram 会产生 10 个 _bucket,加上一个 _sum 和 一个 _count

添加 Label 的情况

如果添加一个新的 label,新的 label 会和原来的 metrics 做笛卡尔积。比如,新添加的 label 是 HTTP 的 status code,添加之后可能会变成下面这样:

这里要格外注意,一个新的 label 不意味着成倍的 metrics,而是笛卡尔积。或者这么想,添加的 每一个 label 都可能将原来的 metrics 拆成多个 metrics。

例子1: 假设原来有 10 条 metrics,新添加了一个 label 叫做机器的 IP,那么新的 metrics 还是 10 条,因为每一个 metrics 在采集的时候就会带有 instance label;

例子2: 假设原来有 10 条 metrics,metrics 原来有 pathquery_params (HTTP协议的),然后新添加一个 label 叫做 full_url 含有 path 和 query_params, 那么新的 metrics 还是 10 条,因为每一个原有的 metric 和新的 metric 都是一一对应的;

例子3: 假设原来有 10 条 metrics,新添加的一个 label 叫做 client port,那么新的 metrics 可能会是 10 * 65535 条(先不考虑 reserve port). 因为 port 有 65535 个不同的的值,并且于原来的 label 都没有关系,所以每一个 label 都被拆成了 65535 个。

这就告诉我们:那些无法枚举,程序不能控制的 lebels,千万不能加入到 metrics 中。

Label 必须是可以枚举的

不可枚举的 metrics 比如,url,IP,等等。或者客户端传递过来的参数。即使参数可能是一个有限集,但是 client 如果有办法不按照这个集合来传,换句话说,你控制不了,那就不能放到 label 中去。否则,会导致 TSDB 的索引快速膨胀,让查询速度急剧下降。

TSDB 是专门存储时序数据的数据库,一条 metrics 在历史时间的数据,它能很快找出来。但是如果要找 100万条 metrics,查询就比较慢了。我们要尽量减少一次查询涉及的 metrics 数量。

优化 Metrics 输出

有了上面的背景, 我们在添加 metrics 的时候,就可以考虑怎么即能够满足监控需求,又可以添加最少量的 metrics 完成需求。

比如我们在统计延迟的时候,Histogram 一下子就是 12 条 metrics。假设我们想在像看到 cluster 维度(有10个)的延迟,也想监控 API 维度(有20个)的延迟,但是我们不需要监控每一个 API 在每一个 cluster 的延迟。

很多人会这么写:request_duration_bucket{cluster='A', API='user', le='10'},这样的话,总数就是 cluster * API * 10 (bucket) = 10 * 20 * 10 = 2000 个 metrics。

但是如果我们暴露两个 metrics:

  • request_duration_cluster_bucket{cluster='A', le='10'}
  • request_duration_api_bucket{api='user', le='10'}

那么总数就是 cluster * 10 bucket + user * 10 bucket = 200 + 100 = 300 个 metrics,少了一个数量级。

另一种情况是,比如在七层网关上的 metrics,我们需要:nginx_instance, status_code, upstream_ip, path, 数据可能达到千万级别,所有的这些 label 都是需要的,用来定位问题。

我们有两个面板:

  1. 一个是汇总查询,只查询所有的实例上面的 status_code,用于发现问题;
  2. 一个是详情查询,需要查询 instance, upstream, path 等等,用于在发现问题之后定位问题;

将这些 label 全都暴露出来,就可以满足两个需求了。但是现在出来一个问题,就是在做需求 1 的时候,由于 metrics 的总量太大了,监控上将他们聚合起来的成本很高,查询速度很慢。

这时候,添加一个新的 metrics 就可以解决问题:requests_by_code_total{status_code="200"}。它只有一个 label,所以 metrics 的量很少,查询速度很快。

这样也可以节省成本,虽然有些反直觉:添加 metrics 也可以减少成本。因为成本不仅仅是存储成本,还有查询计算的成本。查询成本也很可观,因为这个 metrics 通常可能要每 10s 就查询一次,用来做 alerting,判断系统是否正常。

我觉得如果 metrics 经过精心的设计,可以解决大部分的规模问题。但是有时候程序的代码不是我们能控制的,下面还有一些方法可以对付一下。如果代码改不了,可以考虑下下面的方法。

Recording rules 和多级 Recording rules

对于 metrics 太多导致查询起来太慢,可以用 Prometheus 的 recording rules 的方案。核心思想是,既然用户查询的太慢了,那么我就让一个聚合程序每 10s 查询一次,然后将查询结果写入到 TSDB 中,这样,用户在使用这个 metrics 的时候,查询结果已经存在了,必然很快。

Prometheus recording rules 工作原理

有时候 metrics 太多以至于查询根本就查不出来(recording rules 本质上也是一个查询)。还有一种方法是多级聚合。比如第一级分成 5份,每一份保存好聚合结果之后,第二级再跑一次 L2 聚合。

Prometheus recording rules 多级工作原理

这样做的缺点,一个是时效性低,数据有延迟。另一个就是查询造成的压力不减反增——每次查询成本都很高,以前是查询慢,现在查询快了,但是每分钟即使没有人用也要跑查询。

这个方案直觉上就有一个缺点:数据的流向,是首先抓回来存到存储,然后从存储查询出来,计算,然后再写到存储。数据多了一次出来再进去。那我们能够抓到 metrics,计算聚合,然后存储吗?

Streaming Aggregation

我觉得这个想法是合理的,这样数据只进入到了存储一次。

但是 Prometheus 没有这样的功能。我发现 Uber 的 m3db 有,他在聚合 metrics 方面就是在采集的时候计算的。这样开发者暴露再垃圾的 metrics 我们都可以得到想要的聚合了。

m3db 的问题是,它的文档是在太乱了,文档组织毫无逻辑,光运行起来就废了好大的功夫。跑起来之后发现性能也很差,原来的一个 vmagent 可以抓取的 targets,用上 m3db 之后连 1/6 都处理不了。这文档也没有让人想要贡献的欲望,索性作罢。

VictoraMetrics 去年支持了 stream aggregation。支持让 vmagent (VictoriaMetrics 系统中负责采集 metrics 的组件)在采集 metrics 的时候进行聚合。我们在一些场景下用了这个功能,资源使用很少,效果不错。

VictoriaMetrics 的 stream aggregation

它有一些缺点:只支持有限的聚合函数,不可以叠加。比如,用了 increase 之后就不可以再用 sum 了。但是 increase 又不算是聚合,原来有多少用了 increase 就还有多少。这样的话,这个功能就很鸡肋了。我发 issue 咨询了下,意外地得知,VictoriaMetrics 里面的 sum 居然是处理了处理了 counter reset 的,所以说,可以直接用 sum 聚合,sum then rate 也是没有问题!他们提的另一个方案是部署多个 vmagent,每一个都跑一个 stream aggregation:vmagent1 -> vmagent2 -> … -> vmagentN

另一个缺点是,每一个 vmagent 都会得到一份聚合之后的数据,但是问题不大,已经将 metrics 减少很多倍了。在配置的时候,要给每一个 vmagent 的 stream aggregation 规则都加上一个 vmagent 编号的 label,否则的话,多个 vmagent 可能得到完全相同的 metrics 名字,这样数据就不对了。