Redis 核心技术与实战
蒋德钧
中科院计算所副研究员
81696 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 53 讲
开篇词 (1讲)
实践篇 (28讲)
Redis 核心技术与实战
15
15
1.0x
00:00/00:00
登录|注册

12 | 有一亿个keys要统计,应该用哪种集合?

基数统计
二值状态统计
排序统计
基数统计
排序统计
聚合统计
基数统计
差集计算
聚合统计
HyperLogLog
Bitmap
List
Hash
Sorted Set
Set
集合类型

该思维导图由 AI 生成,仅供参考

你好,我是蒋德钧。
在 Web 和移动应用的业务场景中,我们经常需要保存这样一种信息:一个 key 对应了一个数据集合。我举几个例子。
手机 App 中的每天的用户登录信息:一天对应一系列用户 ID 或移动设备 ID;
电商网站上商品的用户评论列表:一个商品对应了一系列的评论;
用户在手机 App 上的签到打卡信息:一天对应一系列用户的签到记录;
应用网站上的网页访问信息:一个网页对应一系列的访问点击。
我们知道,Redis 集合类型的特点就是一个键对应一系列的数据,所以非常适合用来存取这些数据。但是,在这些场景中,除了记录信息,我们往往还需要对集合中的数据进行统计,例如:
在移动应用中,需要统计每天的新增用户数和第二天的留存用户数;
在电商网站的商品评论中,需要统计评论列表中的最新评论;
在签到打卡中,需要统计一个月内连续打卡的用户数;
在网页访问记录中,需要统计独立访客(Unique Visitor,UV)量。
通常情况下,我们面临的用户数量以及访问量都是巨大的,比如百万、千万级别的用户数量,或者千万级别、甚至亿级别的访问信息。所以,我们必须要选择能够非常高效地统计大量数据(例如亿级)的集合类型。
要想选择合适的集合,我们就得了解常用的集合统计模式。这节课,我就给你介绍集合类型常见的四种统计模式,包括聚合统计、排序统计、二值状态统计和基数统计。我会以刚刚提到的这四个场景为例,和你聊聊在这些统计模式下,什么集合类型能够更快速地完成统计,而且还节省内存空间。掌握了今天的内容,之后再遇到集合元素统计问题时,你就能很快地选出合适的集合类型了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Redis集合类型在Web和移动应用的业务场景中有着广泛的应用,特别是在需要保存key对应数据集合并进行统计的情况下。本文详细讨论了四种常见的集合统计模式:聚合统计、排序统计、二值状态统计和基数统计。 在聚合统计方面,文章以移动应用中的用户登录信息为例,说明了使用Set类型来记录累计用户和每日用户,并通过差集、并集和交集操作来完成新增用户和留存用户的统计。同时,提出了在数据量较大时,应避免直接在主库实例进行聚合计算,而是选择从库或客户端进行操作,以规避阻塞风险。 在排序统计方面,文章比较了List和Sorted Set两种有序集合类型的适用情况。通过具体的示例,阐述了List在分页操作中可能出现的问题,而Sorted Set则能准确获取按序排列的数据,适用于需要频繁数据更新或分页显示的场景。 此外,文章还介绍了Bitmap和HyperLogLog两种特殊的集合类型,分别适用于二值状态统计和基数统计。Bitmap通过位操作实现了对二值状态的高效统计,而HyperLogLog则能在节省内存空间的前提下完成基数统计,适用于需要统计不重复元素个数的场景。 总的来说,本文通过实际场景的案例分析,深入浅出地介绍了Redis集合类型在统计模式下的应用,为读者提供了选择合适集合类型的指导建议。读者可以根据具体业务需求和数据规模,选择合适的集合类型来完成统计任务。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Redis 核心技术与实战》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(61)

  • 最新
  • 精选
  • Kaito
    使用Sorted Set可以实现统计一段时间内的在线用户数:用户上线时使用zadd online_users $timestamp $user_id把用户添加到Sorted Set中,使用zcount online_users $start_timestamp $end_timestamp就可以得出指定时间段内的在线用户数。 如果key是以天划分的,还可以执行zinterstore online_users_tmp 2 online_users_{date1} online_users_{date2} aggregate max,把结果存储到online_users_tmp中,然后通过zrange online_users_tmp 0 -1 withscores就可以得到这2天都在线过的用户,并且score就是这些用户最近一次的上线时间。 还有一个有意思的方式,使用Set记录数据,再使用zunionstore命令求并集。例如sadd user1 apple orange banana、sadd user2 apple banana peach记录2个用户喜欢的水果,使用zunionstore fruits_union 2 user1 user2把结果存储到fruits_union这个key中,zrange fruits_union 0 -1 withscores可以得出每种水果被喜欢的次数。 使用HyperLogLog计算UV时,补充一点,还可以使用pfcount page1:uv page2:uv page3:uv或pfmerge page_union:uv page1:uv page2:uv page3:uv得出3个页面的UV总和。 另外,需要指出老师文章描述不严谨的地方:“Set数据类型,使用SUNIONSTORE、SDIFFSTORE、SINTERSTORE做并集、差集、交集时,选择一个从库进行聚合计算”。这3个命令都会在Redis中生成一个新key,而从库默认是readonly不可写的,所以这些命令只能在主库使用。想在从库上操作,可以使用SUNION、SDIFF、SINTER,这些命令可以计算出结果,但不会生成新key。 最后需要提醒一下: 1、如果是在集群模式使用多个key聚合计算的命令,一定要注意,因为这些key可能分布在不同的实例上,多个实例之间是无法做聚合运算的,这样操作可能会直接报错或者得到的结果是错误的! 2、当数据量非常大时,使用这些统计命令,因为复杂度较高,可能会有阻塞Redis的风险,建议把这些统计数据与在线业务数据拆分开,实例单独部署,防止在做统计操作时影响到在线业务。
    2020-09-02
    39
    534
  • 注定非凡
    1,作者讲了什么? 1,Redis有那些数据结构适合做统计 2,作者是怎么把这事给讲明白的? 1,列举了常见的数据统计需求。从实际需求出发,推荐适合的数据类型,讲解了怎么用,并解答这种数据结构为什么可以 2,将数据统计需求,分了四类,分类分别讲解 3,为了讲明白,作者讲了哪些要点,有哪些亮点? 1,亮点1:BITMAP的特性和使用场景,方式 2,亮点2:HyperLogLog的特性和使用场景,方式 3,要点1:日常的统计需求可以分为四类:聚合,排序,二值状态,基数,选用适合的数据类型可以实现即快速又节省内存 4,要点2:聚合统计,可以选用Set类型完成,但Set的差,并,交集操作复杂度高,在数据量大的时候会阻塞主进程 5,要点3:排序统计,可以选用List和Sorted Set 6,要点4:二值状态统计:Bitmap本身是用String类型作为底层数据结构实现,String类型会保存为二进制字节数组,所以可以看作是一个bit数组 7,要点5:基数统计:HyperLogLog ,计算基数所需空间总是固定的,而且很小。但要注意,HyperLogLog是统计规则是基于概率完成的,不是非常准确 4,对于作者所讲,我有那些发散性思考? 1,对于统计用户的打卡情况,我们项目组也做了这个需求,但遗憾的是我们没有采用bitmap这种方案,而是使用了 sortSet 2,HyperLogLog可以考虑使用到,我们项目中的统计视频播放次数,现在这块,我们的方案是,每天产生一个key,单调递增。在通过定时任务,将缓存中的结果,每天一条数据记录,存入数据库 5,在将来的那些场景中,我能够使用它? 6,留言区的收获 1,主从库模式使用Set数据类型聚合命令(来自 @kaito 大神) ①:使用SUNIONSTORE,SDIFFSTORE,SINTERSTOR做并集,差集,交集时,这三个命令都会在Redis中生成一个新key,而从库默认是readOnly。所以这些命令只能在主库上使用 ②:SUNION,SDIFF,SINTER,这些命令可以计算出结果,不产生新的key可以在从库使用
    2020-09-14
    67
  • Anthony
    感觉第一个聚合统计这种场景一般频率不会太高,一般都是用在运营统计上,可以直接在mysql的从库上去统计,而不需要在redis上维护复杂的数据结构
    2020-09-02
    2
    35
  • 波哥威武
    现在大数据情况下都是通过实时流方式统计pvuv,不太会基于redis,基于存在即合理,老师能分析下相关优劣吗,我个人的想法,一个是在大量pvuv对redis的后端读写压力,还有复杂的统计结果redis也需要复杂的数据结构设计去实现,最后是业务和分析任务解耦。
    2020-09-02
    24
  • 土豆哪里挖
    在集群的情况下,聚合统计就没法用了吧,毕竟不是同一个实例了
    2020-09-02
    2
    21
  • Geek_960d5b
    老师只是提供了一种使用思路, 但做统计业界主流还是上数仓用hive等做报表
    2020-11-02
    13
  • 范闲
    1.redis里不建议用聚合统计。原因有几点: 单实例会阻塞。cluster的时候key可能分布在不同的节点,需要调用方做聚合。 2.带排序的统计可以使用sorted set。cluster的时候可能一样需要做聚合 3.hyperlog是带误差的统计,可以用来统计总量。
    2020-10-20
    3
    12
  • 悟空聊架构
    对于这个问题:假设越新的评论权重越大,目前最新评论的权重是 N,我们执行下面的命令时,就可以获得最新的 10 条评论。 理解如下: 假设当前的评论 List 是{A, B, C, D, E, F}(其中,A 是最新的评论,以此类推,F 是最早的评论,权重分别为 10,9,8,7,6,5)。 在展示第一页的 3 个评论时,按照权重排序,查出 ABC。 展示第二页的 3 个评论时,按照权重排序,查出 DEF。 如果在展示第二页前,又产生了一个新评论 G,权重为 11,排序为 {G, A, B, C, D, E, F}。 再次查询第二页数据时,权重还是会以 10 为准,逻辑上,第一页的权重还是 10,9,8。 查询第二页数据时,可以查询出权重等于 7,6,5 的数据,返回评论 DEF。 当想查询出最新评论时,需要以权重 11 为准,第一页数据的权重就是 11,10,9,返回评论 GAB。 再次查询第二页数据时,以权重 11 为准,查询出评论 CDE。
    2021-05-18
    4
    11
  • 阿基米德
    这里一亿个数据返回给客户端处理,这个场景是不是就会有大key问题
    2021-05-14
    2
    9
  • Darren
    老师说的大部分场景都没用到过。。。。。 我们有这么一种场景: 在多实例下,定时任务就不能使用@Schedule使用,必须使用分布式定时调度,我们自研的分布式调度系统支持MQ和Http两种模式,同时支持一次性的调用和Cron表达是式形式的多次调用。 在MQ模式下(暂时不支持Cron的调用),分布式调度系统作为MQ的消费者消费需要调度的任务,同时消息中会有所使用的资源,调度系统有对应的资源上线,也可以做资源限制,没有可用资源时,消息不调度(不投递)等待之前任务资源的释放,不投递时消息就在Zset中保存着,当然不同的类型在不同的Zset中,当有对用的资源类型释放后,会有专门的MQ确认消息,告诉任务调度系统,某种类型的资源已经释放,然后从对应type的Zset中获取排队中优先级最高的消息,进行资源匹配,如果可以匹配,则进行消息发送。 当然http也是类似的,只是http不做资源管理,业务方自己掌控资源及调用频次,http请求的调用时调度系统自己发起的,引入quartz,在时间到达后,通过Http发送调用。
    2020-09-02
    4
    9
收起评论
显示
设置
留言
61
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部