HyperLogLog 算法在监控场景中的运用

HyperLogLog 算法在监控场景中的运用

背景介绍

OpsMind 低代码开发平台监控模块,为了支撑B站众多监控数据的管理场景,研发人员在分布式层做了众多优化工作。为了更好的掌握每个 metric 自身的空间占用以及各个存储节点的时序分布情况,需要对每个指标的时序数目(基数)有一个大致的预估(允许存在误差),以便于 OpsMind 系统能更加合理的均衡各个存储节点的负载。

为何选用 HyperLogLog

OpsMind 系统指标的形式与 prometheus 完全兼容(在此 prometheus 基础上做了一些拓展),一个监控指标(metric)的时序数,可以看做是该指标所有 labels 的组合(对 labels 求 fingerprint)数目。在对每个指标时序集合进行统计的过程中,如何去重是一个关键。当指标时序不多时,只需要简单通过 HashMap(比如 Golang 中,直接通过map进行去重)来实现。可是在监控的大部分场景中,随着监控对象的增加,labels的组合数将会变得越来越多,甚至达到百万级别。如果采用 HashMap 的方式进行统计,对服务端的内存占用将会越来越高。例如以 Golang map 为例,labels 的 fingerprint(uint64) 作为key,当 key 的数目达到100w级别时,内存占用大概为 7.6M 左右,当 metric 数目达到 1w 左右时,整体占用的内存空间是 74GB 左右。而B站目前管理的 metric 数目远不止 1w,显然不能使用 Golang map 来进行去重统计时序数目。

type Fingerprint uint64
type MetricLablesSet map[Fingerprint]struct{}

此时,尽量减少内存的占用(降低空间复杂度),成为主要要解决的问题。为了达到这个目的,另一种是通过 Bit-map 的方式进行基数的统计。Bit-map 的实现原理比较简单,即:使用 bit 位来标记某些元素是否存在。比如,在指标基数统计场景中,我们可以通过标记 labels fingerprint hash值在 bit 数组中的位置(与 bit 数组长度取模后得到),来进行去重。所以如果要存储 100w 个 fingerprint 是否存在的信息,至少需要占用 122KB 内存空间。1w个metric 至少占用 1GB 的空间。虽然相较于 HashMap,Bit-map 的方式极大的减少了内存空间的占用, 但是 1GB 的空间大小(实际情况下,会大很多),仍然不能满足需求。另外,实际场景中,一般会给每个 metric 预留一个较大长度的 bit 数组,当 metric 时序数较少的情况下,资源利用率会很低。即便存在其他能很好的提升资源利用率的算法(比如:Roaring Bit-map),在B站那么大数据量的场景下,依然没法很好的解决资源占用高的问题。

在满足效率的同时,内存占用能否继续降低?空间利用率能否持续提升?答案是肯定的,就是本文要介绍的算法:HyperLogLog(另一种方式是采用 Bloom Filter,不过不在本文讨论范围)。

HyperLogLog 算法介绍

HyperLogLog 利用了概览算法,存在一定的统计误差,不过这个误差在 metric 基数统计场景中是可以接受的。关于原理,读着可以带入到日常生活中常见的伯努利实验,例如:抛硬币, 出现正反面的概率都是1/2,一直抛硬币直到出现正面,记录下投掷次数 K,将这种抛硬币多次直到出现正面的过程记为一次伯努利过程,对于n次伯努利过程,可以得到n个出现正面的投掷次数值 K_1, K_2 ... K_n,其中最大值记为 K_{max}

可以得出以下结论:

  1. n 次伯努利实验,投掷次数不大于 K_{max}
  2. n 次伯努利过程,至少有一次投掷次数为 K_{max}

对于结论1,n 次伯努利过程投掷次数都不大于 K_max 的概率为:

P_n(X≤K_{max}) = (1 - 1/2^{K_{max}})^n

对于结论2,至少有一次抛了K_{max}次的概率为:

P_n(X≥K_{max}) = 1 - (1 - 1/2^{K_{max}-1})^n

继而可以得到:

  • 当 n 远小于 2^{K_{max}} 时,P_n(X≥K_{max})≈0,结论1不成立;
  • 当 n 远大于 2^{K_{max}} 时,P_n(X≤K_{max})≈0,结论2不成立;

最后可以通过 2^{K_{max}} 来估计 n 的值:

n = 2^{K_{max}}

image

这相当于知道某回合的最大投掷次数,可以估算出总共进行了几回合。而 HyperLogLog 算法的基本核心正基于此。通过统计存储元素 hash 值二进制表示中的第一个 1 的最大位置来估算元素数量,来预估存储单元基数的大小。这里,第一个 1 的位置可以类比为抛硬币场景中出现正面时的投掷次数,存储单元基数则相当于投掷了多少回合。

不过在抛硬币场景中,假如第一回合,第 3 次出现正面朝上,带入到公式中则预估出总共进行了 2^3 = 8回合;显然存在较大误差。HyperLogLog 为了改善这种较大误差的情况,引入了分桶平均以及偏差修正的方式。将存储的hash值分到m个桶中,分别统计 n,最后求得 m 个桶的调和平均数。公式如下:

image

m 为桶的数目, alpha为修正常数。

其中 alpha 的取值为:

switch (m) {
   case 16:
       alpha = 0.673;
   case 32:
       alpha = 0.697;
   case 64:
       alpha = 0.709;
   default:
       alpha = 0.7213 / (1 + 1.079 / m);
}

带入到 metric 基数统计场景,选取 m 的数目为 16384 (类似Redis),每个桶的大小为 6 bit 长度;通过对 metric 的 fingerprint hash 得到一个 uint64 的数字,通过该数字前14位确定桶的位置,其余位用来做伯努利过程。则所有桶占用的内存空间为 16384*8bit = 12KB

为了更少的资源占用,有些 hll 的实现又引入了“稀疏存储结构”和“密集存储结构”的概念,当稀疏存储的容量达到一定规模后,会合并成密集存储结构,感兴趣的读着,可以自行搜索相关实现。

总结

在 metric 基数统计场景中,使用 HLL 对时序进行预估,可以保证较低且稳定的内存占用,又可以保证误差率在一个较低的可接受范围内。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容