• 场景之在线人数或者粉丝查询实现


    直播间在线人数或者粉丝查询

    一、主要功能

    通常对于一些实时在线业务中,比如直播业务中的主播,希望让主播看到直播间实时在线粉丝数等数据,从而从数据方面提升主播的整体直播体验。

    二、简单方案:

    最简单的方案就是通过所有在线人数判断与主播是否构成粉丝关系,每个人进入直播间会产生记录,根据用户ID去遍历主播与用户的关系表,判断记录中is_follow关系是否为1,为1用户则为主播粉丝,记录下来,遍历整张表结束则可以统计出在线粉丝人数。
    缺点:对于在线粉丝查询这一功能而言,是相对实时更新并且主播端请求频率比较高的操作,如果每次查询根据每个在线的用户再去扫描表,即使是扫描从库也是很耗时,因此是不可取的。而对于主播而言短暂的粉丝数量误差延迟是可以接受的,所以考虑引入redis进行缓存记录。

    三、涉及场景

    也就是记录在线粉丝功能中涉及到的主要接口

    • 1、用户进入直播间:用户进入直播间之后判断是否粉丝,如果是粉丝并可以添加记录
    • 2、用户心跳:一般用户和server,server和主播都会维持等间隔几秒发送一次心跳,心跳的主要作用包括获取直播间的一些基础人数,商品,礼物等信息以及维持连接正常等功能,同样基础数据中也包括在线粉丝数据。而对于用户端而言,可以在用户发起心跳的时候,判断是否是主播粉丝,如果是则添加记录。
    • 3、用户离开房间:用户离开直播间触发判断是否粉丝,如果是粉丝并从记录删除的操作。
    • 4、超时断开连接:一般可能由于一些异常原因,比如网络等问题,用户和server的连接可能会被判超时,而server的策略则多数是,定期会清理一些超时连接,在清理超时连接的时候,根据连接的用户是否主播构成粉丝关系,需要从在线粉丝记录中删除。
    • 5、主播关闭直播间:清除粉丝在线记录
    • 6、主播开播:开启在线粉丝记录
    • 7、开播过程中添加关注:粉丝在直播间添加关注,这里根据情况不太需要更新记录,因为有用户心跳更新粉丝关注,用户心跳稳定且频繁,新增关注带来的在线粉丝数量上的短暂延迟可以接受。
    • 8、开播过程中取消关注:同添加关注
      等等......

    四、可选方案

    利用redis的不同数据结构记录在线粉丝。

    1、采用有序集合

    用户上线时候,判断构成粉丝关系,则采用ZADD,将用户以及在线时间添加集合中,其中live_id是直播间id,用主播id或者直播id区分不同的在线粉丝集合。current_timestamp是进入直播间时间戳。

    ZADD "online-fans:live_id"  <user_id> <current_timestamp>
    

    通过ZCARD命令查看集合中的数量,也就是在线粉丝个数

    ZCARD “online-fans:live_id”
    

    通过ZCOUNT 查看某一时段进入直播间的粉丝。

    COUNT "online-fans:live_id" <start_timestamp> <end_timestamp>
    

    2、采用集合

    使用有序集合能够同时储存粉丝的id以及上线时间戳, 但如果只想要记录在线的id, 而不想要储存上线时间, 那么也可以使用集合来代替有序集合进行记录。

    当进入直播间,判断是否是粉丝, 执行 SADD 命令将它添加到在线记录中当中:

    SADD "online-fans:live_id" 
    

    通过使用 SISMEMBER 命令, 可以检查粉丝是否在直播间:

    SISMEMBER "online-fans:live_id" 
    

    统计在线粉丝数则可以通过执行 SCARD 命令来完成:

    SCARD "online-fans:live_id"
    

    与有序集合相同的是,都是集合类型,可以进行一些交集和并集的聚合操作,比如交集判断连续一周都在直播间的粉丝,并集可以查看一周之内出现在直播间的粉丝等数据。

    3、采用Bitmap

    使用有序集合或者集合能够储存具体的在线用户名单, 但是却在粉丝量在线大的时候需要消耗比较多的内存;
    bitmap相对来说既能够获得在线用户名单, 又可以尽量减少内存消耗。Redis 的位图就是一个由二进制位组成的数组, 通过将数组中的每个二进制位与用户 ID 进行一一对应, 使用位图可以去记录每个粉丝是否在线。

    当一个用户进入直播间时,判如果是粉丝,使用 SETBIT 命令, 将这个用户对应的二进制位设置为 1

    SETBIT "online-fans:live_id <user_id> 1
    

    通过使用 GETBIT 命令去检查一个二进制位的值是否为 1 , 判断粉丝是否在线:

    GETBIT "online-fans:live_id" 
    

    通过 BITCOUNT 命令, 统计出位图中有多少个二进制位被设置成了1,也即是有多少个粉丝直播间在线:

    BITCOUNT "online-fans:live_id"
    

    同样由于,bitmap是用0,1表示对应的粉丝是否在线,也可以多个记录的bitmap形成与或非运算,计算多个时段或者多个直播间在线的粉丝数。

    五、实际方案

    综合实际的情况和要求,采用集合记录在线粉丝人数。

    1、定义redis集合

    设置一个集合,具体如下

    key = "online-fans:live_id"
    value = {user_id1, user_id2, user_id3....}
    

    其中live_id是直播间或者直播场次id,也用主播id定义,集合中记录用户的user_id即可

    2、修改对应场景下的操作

    具体操作包括

    • 1,2进入直播间和用户心跳场景中,通过获取到用户的用户Id,判断是否与主播构成粉丝关系,如果是,则执行SADD添加集合操作。一般认为主播开播不会超过6h,因此集合有效期设置为为每当有新粉丝进入,则更新缓存有效期6h。
    SADD "online-fans:live_id" 
    EXPIRE "online-fans:live_id"  6*60*60 
    
    • 3,4场景用户离开直播间与server检测超时断开连接,可以直接执行SREM从粉丝集合删除,由于redis集合移除元素操作的时候,如果元素在集合内则直接移除,不在忽略,因此不需要再判断粉丝关系。
    SREM  "online-fans:live_id" 
    
    • 5场景中,主播主动关闭直播间,则本场直播的实时在线粉丝人数需要清空。删除对应的直播场次的缓存
    DEL "online-fans:live_id" 
    UNLINK  "online-fans:live_id" 
    

    具体的redis删除集合的命令有两个,一个是del,一个是unlink,具体的是由于redis在执行命令操作的时候是一般是单线程的,因此如果是当在线粉丝人数过多导致集合很大的时候,业务流程中执行del操作,会有延迟。因此可以采用单开一个协程或者线程去异步非阻塞执行del操作或者直接使用unlink命令直接返回删除结果,让redis单开一个额外的线程去执行删除操作,不阻塞后端流程。

    • 6场景开播情况下,不需要主动创建一个空的集合,因为在添加操作的时候如果集合不存在,则会创建。还有点延迟初始化的效果。
    • 7,8 直播间内用户转变为粉丝的情况可以不考虑,心跳本身也有几秒一次的短暂定时机制,心跳到达server会更新状态,数据上的短暂延迟可以接受。
  • 相关阅读:
    十三、DataFrame表格型数据结构
    Go 锁扩展
    I/O性能与可靠性
    非关系型数据库MongoDB:(二)副本集部署说明、数据迁移、限制内存、启用mongo认证
    创建自己的工具包(python)
    极简试用期转正述职报告PPT模板
    使用快解析搭建自己的minecraft服务器
    轴承故障分类方法之CNN+SVM和ELM
    总结:2022-9-11 动态规划最优子结构特征 多进程图像总结
    Nignx部署前端页面
  • 原文地址:https://www.cnblogs.com/welan/p/16516052.html