上一篇呢主要是讲了对于judge模块的内存优化,并且由于涉及到了judge与hbs之间的接口修改,因此在hbs这边也要进行少量的修改来进行优化,下面就直接简单介绍下优化思路。
优化思路
在judge哪边每次同步都是根据key来进行同步的,在最初的版本中hbs是把自己的全部数据使用list的方式全部推送给judge,当然啦,judge可以选择自己build成list然后筛选出来自己需要的数据,但是build是个很耗时的过程,同时拿全量数据对于带宽是个很大的消耗,并且judge对于增量更新是强需求,所以hbs这边必须支持依据key来进行同步的功能。
在这种情况下就必须要把原来的关键数据结构(list)改为map了,key是host+metric,在修改完成之后呢,发现hbs的内存上升了3-4G,这个很好理解哈,因为原本的结构只有list没有那个key这占用了很大一部分内存,之后通过比对数据结构意识到,其实呢,对于hbs来说即便是原本的list那种结构其实也是浪费了极大地内存的。为什么呢?
原因就在于,hbs当中存储的模板+策略其实毕竟是少数,但是在应用到节点上的时候就会导致每一个策略对象都会复制一遍。假设我们本来仅仅是一个模板然后里面有100台机器。那么这种情况下在hbs当中这一个模板+十条规则占用的内存就变成了原来的100倍!所以这种情况下其实就应该用指针啦,改用指针之后内存就会极大地减少,这里我贴一下关键数据结构,然后就接着说往下说(因为这是第一版)
1 | type StrategyTpl struct { |
修改到这里内存就从12G减小到了比原来最初的8G还要稍微少一丢丢的内存占用,这种情况下judge从hbs同步数据的时间也从最初的3分钟左右变成了几十秒。
下图内存明显分位三段,第一段是使用list时hbs的内存占用,第二段是修改为map之后的内存占用,第三段是修改为指针后的内存占用。
还没完
随着日常的使用呢,经过8个月发现hbs的内存占用会出现极大地波动,最多的时候内存占用会翻倍,发现这个情况之后找了很久都没有找到原因,因为数据结构的优化已经基本达到了极限,这时候突然想起来,将list改为map的时候内存出现了大量的增长,这个巨大的内存波动,很有可能是hbs这个大字典的key导致的,于是进行了验证,将字符串的key经过一层hash变为int64,之后发现内存占用果然下降了,不进内存占用比8个月前list的还小,并且内存波动也从原来的翻倍变成了1G之内的波动。这里注意一下,本质上是使用时间换空间,因此对于cpu的需求会上升。
最初是一个大字典然后使用了一个全局锁,这个其实很浪费性能在judge同步hbs数据的时候是会很影响时间的,因此这次优化主要包括以下几点:
- 将host+metric的字符串key经过一层hash映射为唯一的int64
- 将大map修改为支持并发锁的字典
- 在计算告警规则的时候使用协程并行计算规则,组建字典
下面直接贴代码了
1 | import ( |
下图是修改完的hbs实例和未修改实例的内存比对图,可以看到,不管是内存占用还是内存波动优化效果都十分明显
PS
以上对于hbs的优化方法不管是string转int还是使用并发锁对于graph同样适用,有需求的同学可以实践一下
转载请注明来源链接 http://just4fun.im/2020/03/01/falcon-optimize-hbs/ 尊重知识,谢谢:)