Kaito
2020-09-02
使用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的风险,建议把这些统计数据与在线业务数据拆分开,实例单独部署,防止在做统计操作时影响到在线业务。
展开
共 37 条评论
512
注定非凡
2020-09-14
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可以在从库使用
展开
66
Anthony
2020-09-02
感觉第一个聚合统计这种场景一般频率不会太高,一般都是用在运营统计上,可以直接在mysql的从库上去统计,而不需要在redis上维护复杂的数据结构
共 2 条评论
35
波哥威武
2020-09-02
现在大数据情况下都是通过实时流方式统计pvuv,不太会基于redis,基于存在即合理,老师能分析下相关优劣吗,我个人的想法,一个是在大量pvuv对redis的后端读写压力,还有复杂的统计结果redis也需要复杂的数据结构设计去实现,最后是业务和分析任务解耦。
24
土豆哪里挖
2020-09-02
在集群的情况下,聚合统计就没法用了吧,毕竟不是同一个实例了
共 1 条评论
21
Geek_960d5b
2020-11-02
老师只是提供了一种使用思路, 但做统计业界主流还是上数仓用hive等做报表
13
范闲
2020-10-20
1.redis里不建议用聚合统计。原因有几点: 单实例会阻塞。cluster的时候key可能分布在不同的节点,需要调用方做聚合。 2.带排序的统计可以使用sorted set。cluster的时候可能一样需要做聚合 3.hyperlog是带误差的统计,可以用来统计总量。
共 3 条评论
12
悟空聊架构
2021-05-18
对于这个问题:假设越新的评论权重越大,目前最新评论的权重是 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。
共 4 条评论
11
阿基米德
2021-05-14
这里一亿个数据返回给客户端处理,这个场景是不是就会有大key问题
共 2 条评论
9
Darren
2020-09-02
老师说的大部分场景都没用到过。。。。。 我们有这么一种场景: 在多实例下,定时任务就不能使用@Schedule使用,必须使用分布式定时调度,我们自研的分布式调度系统支持MQ和Http两种模式,同时支持一次性的调用和Cron表达是式形式的多次调用。 在MQ模式下(暂时不支持Cron的调用),分布式调度系统作为MQ的消费者消费需要调度的任务,同时消息中会有所使用的资源,调度系统有对应的资源上线,也可以做资源限制,没有可用资源时,消息不调度(不投递)等待之前任务资源的释放,不投递时消息就在Zset中保存着,当然不同的类型在不同的Zset中,当有对用的资源类型释放后,会有专门的MQ确认消息,告诉任务调度系统,某种类型的资源已经释放,然后从对应type的Zset中获取排队中优先级最高的消息,进行资源匹配,如果可以匹配,则进行消息发送。 当然http也是类似的,只是http不做资源管理,业务方自己掌控资源及调用频次,http请求的调用时调度系统自己发起的,引入quartz,在时间到达后,通过Http发送调用。
共 4 条评论
9