这是小米开源监控系统OpenFalcon应对高并发7种手段之一的:一致性哈希分片提高吞吐容量。
一致性哈希分片
这么多数据上来不可能由一台机器处理,因此做了一个数据分片,即一个机器只处理一部分数据,报警数据是由 Judge 做分片,绘图数据由 Graph 做分片,这两个都是使用一致性哈希。
一致性哈希分片有一个问题,就是扩缩容比较麻烦,数据打到某个 judge 之后,就会一直打到这个 judge。
当列表发生变化时候,由于一致性哈希算法,原来打到一台 judge 实例的数据就会打到另外一个 Judge 实例,所以 Judge 一定要保证没有状态,这样才能方便扩缩容。
状态标记
其实说它没有状态也不太合适,judge 内存里也存了几个点。比如某一台机器 cpu.idle 数据上来之后,连续 3 ~ 5 次达到一个特定阀值才去报警,而不是达到阀值立马报警。像 CPU,是一直都忙碌状态才去报警,Judge 判断的时候它是判断多个点。
产生报警之后,还有一些后续处理,比如对这个报警事件做一个判断,上次产生事件是什么状态,他是第几次报警,是不是达到了最大报警次数不能再报了,避免重复报警给处理人员造成干扰。一般大家都设置报警 3 次。
因此报警事件需要记录一个状态,标记是否健康,如果有问题,记录当前是第几次。Judge 状态存在数据库,虽然 1 亿条数据上来,实际上报警数据不多,可能只有 10 万条数据级别,因此可以存入数据库,这样 Judge 就剥离了报警事件状态。
虽然 Judge 内存当中还存一些前面所说数据状态,但也不是一个大问题。因为监控数据是源源不断上来,即使丢掉一些状态,新的 Judge 实例很快就会又填充数据。
扩容
一致性哈希对扩容不是很友好,比如 20 台 Graph 的机器如果变成 40 台,势必有老的 Graph 实例的一部分数据打到新的 Graph 上,因此我们做了一个自动数据迁移。
这个自动迁移是由于一致性哈希造成的问题,如果用映射表做分片,在映射表这统一维护数据和 graph 实例对应关系,扩容就简单很多。