使用redis特性便捷解决业务问题

达芬奇密码2018-06-20 09:35

业务背景

在前台页面,当用户打开或下载视频时(含各种格式的视频文件),系统自动判断当前并发观看视频的帐号数量是否达到帐号并发上限, 若超过则提示“当前人数已满,请稍后再试”。

初步分析

用户观看的视频是从NOS直接加载到浏览器的,因为不是直播,所以只能通过客户端每隔10s上报一个维持活跃的请求到后端,由后端来统计和判断过期。 通过在缓存中维持用户和最后活跃时间的哈希表,再起一个定时器,短轮询主动过期最后活跃时间是10s前的用户, 这种方案功能上是满足,但是性能上会比较糟糕(不停的遍历整个哈希表进行比较)。

昨晚花了点时间想了两种该场景下的解决方案。

方案1 redis 双哈希表设计

哈希表1: {key:用户ID,value:最后活跃时间(时间戳秒)};过期时间10s
哈希表2: {key:活跃时间(时间戳秒),value:活跃数};过期时间10s
内存中只维护最近10秒的10个桶

 

时间推移每秒都会过期一个桶


获取当前活跃数

  • 构建当前时间之前10秒内的时间戳List
  • 根据redis获取这批key的值
  • 内存中累加每个桶的活跃数

维持在线状态
见下面的流程图,比较详细

 

本案思路来源于hystrix中用于判断断路器开闭,内存中维护请求统计的数据结构设计

方案2 redis sorted set

sorted set是redis提供的一种有序集合,具有set和hash的特点。
其中每个元素都关联一个score,并以这个score来排序。
其内部实现用到了两个数据结构:hash table和 skip list

哈希表: {key:用户ID,value:最后活跃时间(时间戳秒)};

熟悉几个命令

  • zadd 用于将给定分值的成员添加到有序集合里,如果成员存在,则更新这个分值。
  • zcount 用于返回分值区间内的成员数量
  • zremrangebyscore 用于移除有序集合中分值介于MIN与MAX之间的所有成员

获取当前活跃数

  1. zcount userIdLastActiveTimeHashTable 当前时间戳(秒)-10秒 10000000000

维持在线状态

  1. zadd userIdLastActiveTimeHashTable 当前时间戳(秒) 用户ID
  2. zremrangebyscore userIdLastActiveTimeHashTable 0 当前时间戳(秒)-10秒

本文来自网易实践者社区,经作者陈志良授权发布。