第10章用户关系服务——10.2 基于Redis中ZSET的设计

基于Redis ZSET的设计

一开始我们很容易想到使用Redis的ZSET对象来实现用户关系服务,ZSET高效支持数据的插入与查询功能,且很容易实现按照关注时间排序。

对于每个用户来说,都使用两个ZSET对象分别维护其关注列表和粉丝列表。

  • 关注列表的Key为following_{用户ID},Member为被关注的用户ID,对应的Score为关注行为发生的时间。
  • 粉丝列表的Key为follower_{用户ID},Member为粉丝用户ID,对应的Score为用户被关注行为发生的时间。

查询某用户的关注列表 ,就是获取following_{用户ID}集合的数据,使用ZREVRANGE命令即可实现按照关注时间从近到远排序的要求:

1
ZREVRANGE following_{用户ID} 100 199

获取用户的粉丝列表也是同理,只不过读取的Key为follower_{用户ID}

获取用户的关注数和粉丝数即获取这两个ZSET的长度,对应的Redis命令为ZCARD。

当用户1关注用户2时,就是在用户1的关注列表ZSET和用户2的粉丝列表ZSET中新增一条记录,Score为当前时间戳:

1
2
ZADD following_用户1 时间戳 用户2
ZADD follower_用户2 时间戳 用户1

取消关注亦是同理,只不过是在用户1的关注列表ZSET和用户2的粉丝列表ZSET中删除一条记录:

1
2
ZREM following_用户1 用户2
ZREM follower_用户2 用户1

当查询用户1是否关注用户2时,既可以查询在用户1的关注列表ZSET中是否包含用户2 ,也可以查询在用户2的粉丝列表ZSET中是否包含用户1:

1
2
ZRANK following_用户1 用户2
ZRANK follower_用户2 用户1

当批量查询用户1与若干指定用户的关注关系时,可以先使用ZRANGE命令获取用户1的关注列表:

1
ZRANGE following_用户1 0 -1

然后在结果中查找这些指定的用户是否存在即可。当批量查询若干指定用户是否是用户1的粉丝时,也是同理。

使用Redis ZSET实现用户关系服务比较简单,不过,它毕竟使用了昂贵稀缺的内存资源,此方案本身有一定的局限性。对于国民级社交应用来说,拥有几百万粉丝的网红、大V数不胜数,更不要说其中的大网红动辄粉丝数上亿了,这就意味着需要存储很多超长的 ZSET对象,而这对于Redis来说是一笔昂贵的开销。所以,Redis ZSET方案仅适合社交属性不强,或者用户量级不大的小型应用,并不适合拥有海量用户、社交属性强的应用