推送设备高效检索方案
目前主流厂商的推送系统都支持别名推送、用户分群推送、标签推送。其中有个难点是如何从亿级设备中检索出特殊标签的用户实现高效的推送,如何实现每分钟千万推送消息,全推秒级到达,亿级大规模推送任务分钟级别推送完成将是一个很大的挑战,最简单的做法就是使用mysql 的 where 字句的检索方案,但是这种方法对 mysql 的压力非常大,而且查询速度非常慢,这里介绍在实践过程中使用到的分布式的标签检索方案。
在介绍这个分布式标签检索方案之前,我们先来看下会用到的相关数据结构:
Raoring Bigmap
RBM 的主要思想并不复杂,简单来讲,有如下三条:
- 我们将 32-bit 的范围 ([0, n)) 划分为 2^16 个桶,每一个桶有一个 Container 来存放一个数值的低16位;
- 在存储和查询数值的时候,我们将一个数值 k 划分为高 16 位(k % 2^16)和低 16 位(k mod 2^16),取高 16 位找到对应的桶,然后在低 16 位存放在相应的 Container 中;
- RBM 使用两种容器结构: Array Container 和 Bitmap Container。Array Container 存放稀疏的数据,
Bitmap Container 存放稠密的数据。即,若一个 Container 里面的 Integer 数量小于 4096,就用 Short 类型的有序数组来存储值。
若大于 4096,就用 Bitmap 来存储值。
![7bf3e202545e08b7d7cf8115f279a1f3.png](https://i-blog.csdnimg.cn/blog_migrate/d62af6c066025f088d452770a3790a8c.jpeg)
一致性 hash 算法
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简 单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。 一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义:
- 平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。
- 单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。
- 分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。
- 负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。
具体算法实现,这里就不再赘叙。
标签检索系统
接下来分为三步来介绍基于标签的检索系统
Tag Bitmap 系统设计
首先做一个映射
- DeviceId -> guid<uint32>
- Tag -> set<guid>
- Tag -> bitmap [0101….]
DeviceId 为设备 ID,唯一标识一台设备,在系统中唯一映射为一个uint32 guid
Tag 为标签,每个用户会被打上不同的标签,比如杭州、男性等,一个 Tag 对应 guid 的一个集合
同时每个 Tag 对应一个 raoring bitmap,记录 guid 信息
构建总长度为 2^32 的 bitmap,分成 2^16 个分区,每个分区长度 2^16,支持设备数量 40亿+
![d545745f4b3961ca4ae6254260ad2a53.png](https://i-blog.csdnimg.cn/blog_migrate/52f64522f8a3abb86e7ccc1bd5c54cd6.png)
Guid 高 16 位确认分区,低 16 保存为 roaring bitmap
Tag 标签,可以分为平台、版本、通道、地域、性别等,比如 android/ios/xiaomi/east 等
Tag Bitmap 分发设计
![c2f6855fcd6fbe106dc0b9459ebba517.png](https://i-blog.csdnimg.cn/blog_migrate/364d275dcc9c1884f1414a20af05b6ff.jpeg)
如果需要推送 Android 和小米通道的用户,只需要对 Android Tag 和 小米 Tag 的 roaring bitmap 做与操作,就可以检索出来对应的 guid 的集合。
Tag Bitmap 系统性能
![c1aa89b9ab37e5c0ccc556b6e987edd9.png](https://i-blog.csdnimg.cn/blog_migrate/c35631d79786026c9cdfb3d3e2cd7529.jpeg)
从上面的数据可以看出,即使 10亿的设备,占用的空间也就不到 1G
![d462eec9a22e285de54e72a2bb63c816.png](https://i-blog.csdnimg.cn/blog_migrate/c9fc93b65859713ba2a3f65f98a245ac.jpeg)
Roaring bitmap 检索性能非常高
Tag Bitmap 系统实现
上面几点介绍了 Tag Bitmap 系统检索系统的高效性,接下来介绍一下如何实现高效的分布式分发
- roaring bitmap 可以使用 redis roaring bitmap module
- roaring bitmap 分区及一致性 hash cache
![156d4c2fd0bd1da04c8e4f76dc730a25.png](https://i-blog.csdnimg.cn/blog_migrate/4bc0ccf78203100d0531d65aa3de75c2.jpeg)
GUID 高 16 位做一致性 hash,缓存到对应 的push-logic 节点
Tag bitmap 下发时,Bitmap 分区做一致性 hash,下发到对应的push-logic 节点
Bitmap 分布式 CACHE 到 push-logic节点
设备在注册时,根据 guid 做一致性 hash,更新 push-logic 里面的缓存
总结
通过 Tag Bitmap 系统,可以实现高效的基于标签的检索系统,实现秒级千万推送消息,亿级大规模推送任务分钟级别推送。