在高流量、源源不断的请求接口中,一个用户可能会发送多个请求,因此如何在这种情况下抽样并记录不重复用户的信息是一个重要的设计问题。本设计考虑多种方案,旨在通过有效的抽样策略来减少存储负担,同时确保数据的代表性。
确定性哈希抽样
对于用户ID进行确定性抽样。
比如用户A哈希值为103,那么在抽样率为5%的情况下,由于 103 m o d 100 < 5 103 \bmod 100 < 5 103mod100<5,所以就会被抽样
这种方法的特性是
- 相同用户的结果一致
- 计算开销小
- 也不需要存储状态
缺陷在于在多接口抽样时抽到到的都是同样的用户
为了防止这样的缺陷其实还是可以将接口与用户ID进行hash,然后再确定性哈希抽样
本方案非常适用于对简单场景中低资源占用的快速抽样
布隆过滤器+概率抽样
布隆过滤器(Bloom Filter)是一种空间效率非常高的概率数据结构,用于测试某个元素是否在一个集合中。结合布隆过滤器与概率抽样,可以达到以下效果:
- 布隆过滤器判断:首先通过布隆过滤器检查该用户是否已经被抽样过。若未抽样过,则继续进行下一步。
- 概率抽样:对通过布隆过滤器判断的用户进行概率抽样。例如,通过生成随机数判断该用户是否符合抽样条件。
优点
- 内存占用小:布隆过滤器通过位数组压缩存储大规模数据,内存消耗低
- 动态调整采样率:可以根据业务需求调整抽样率。
- 适合单机部署:无需依赖分布式存储,布隆过滤器可在单机环境下高效运行。
缺点
- 误判:布隆过滤器存在误判的概率,可能导致某些未采样的用户被认为已采样。
- 无法删除元素:布隆过滤器一旦记录某元素,无法删除,因此需要定期重置以避免过期信息。
大流量接口的用户信息采样,尤其适合实时性要求不高,且可以容忍一定误判的场景,如统计和分析
Redis HyperLogLog+Hash
hyperLogLog是一种用于估算基数的概率数据结构,在Redis中被用于估算不重复元素的数量,特别是在数据量非常大时,能够提供高效的近似计数
Hash则用于储存已经采用用户的详细信息
优点
- 分布式支持:Redis天然支持分布式部署,适用于分布式系统。
- 性能高,内存占用固定:HyperLogLog的空间复杂度固定,无论数据量多大,内存占用几乎不变。
- 支持并行合并:可以在多个节点间合并HyperLogLog的结果,适合分布式环境。
缺点
- 网络开销大:HyperLogLog和Hash操作需要通过网络与Redis交互,可能带来一定的延迟。
- 近似结果:HyperLogLog只提供基数的估算值,不会返回精确结果。
- 无法撤回数据:一旦用户信息被采样并写入Redis,无法删除或撤回。
适合大规模分布式系统,尤其在估算用户基数、进行去重统计时非常有效
分层采样
分层采样是一种将抽样过程分为多个步骤的方法,以提高性能并减少数据处理
- 概率预筛选:首先进行一个概率筛选,确定是否进入下一步抽样过程
- 本地bloom filter过滤:对于通过预筛选的用户,使用布隆过滤器进一步判断是否已被抽样
- 异步写入redis:符合条件的用户信息通过异步方式写入Redis,以便高效记录
- 定期持久化到数据库:为了保证数据持久性,定期将Redis中的数据同步到数据库中
优点
- 系统负载小,高性能
- 可靠性好
- 支持横向拓展
缺点
- 实现复杂
适合需要高性能、高可靠性和可扩展性的分布式系统,尤其在需要大规模用户信息采样时
时间窗口+一致性哈希
在某些场景下,可以根据时间窗口来控制用户的采样。具体步骤如下:
- 确定当前用户访问所在的时间窗口。比如在10:03访问的位于10:00-10:05的窗口期内
- 根据窗口值和用户ID生成哈希值
- 使用一致性哈希进行判断是否在采样的节点中
优点
- 采样均匀:由于时间窗口的限制,可以保证采样分布较为均匀
- 资源消耗可控:通过一致性哈希,可以在一定程度上控制内存和计算资源的消耗
- 支持动态调整:可以动态调整时间窗口或哈希范围,适应不同的流量和业务需求
缺点
- 窗口切换开销:时间窗口的切换可能会带来一定的开销,影响系统性能
- 存在边界问题:在时间窗口的边界上,可能会出现采样不均匀的问题
- 内存占用大:由于需要存储用户在每个窗口的采样信息,内存消耗较高
适合需要时间维度的分析场景,如用户活跃度分析、时段流量分析等
总结
根据不同的应用场景和需求,可以选择不同的流式抽样方案。
如果需要高效且简单的实现,可以考虑确定性哈希抽样或布隆过滤器方案;如果对数据量和性能有更高要求,Redis HyperLogLog和分层采样则是更合适的选择;对于需要时间维度分析的场景,可以使用时间窗口 + 一致性哈希方案。