6

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

 2 years ago
source link: https://www.cnblogs.com/welan/p/16516052.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

一、主要功能

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

二、简单方案:

最简单的方案就是通过所有在线人数判断与主播是否构成粉丝关系,每个人进入直播间会产生记录,根据用户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" <user_id>

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

SISMEMBER "online-fans:live_id" <user_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" <user_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" <user_id>
EXPIRE "online-fans:live_id"  6*60*60 
  • 3,4场景用户离开直播间与server检测超时断开连接,可以直接执行SREM从粉丝集合删除,由于redis集合移除元素操作的时候,如果元素在集合内则直接移除,不在忽略,因此不需要再判断粉丝关系。
SREM  "online-fans:live_id" <user_id>
  • 5场景中,主播主动关闭直播间,则本场直播的实时在线粉丝人数需要清空。删除对应的直播场次的缓存
DEL "online-fans:live_id" <user_id>
UNLINK  "online-fans:live_id" <user_id>

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

  • 6场景开播情况下,不需要主动创建一个空的集合,因为在添加操作的时候如果集合不存在,则会创建。还有点延迟初始化的效果。
  • 7,8 直播间内用户转变为粉丝的情况可以不考虑,心跳本身也有几秒一次的短暂定时机制,心跳到达server会更新状态,数据上的短暂延迟可以接受。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK