如何用Redis的Sorted Set做排行榜?
Sorted Set(有序集合):可以自动保持元素有序,并且支持快速的排名查询
- 它和Set一样,都是存储不重复的元素,但 Sorted Set 中的元素是有序的
- 每个元素都会关联一个 double 类型的分数(score),元素就是通过这个分数来排序的
Redis命令:
# 添加元素
zadd key score1 member1 [score2] [member2] ...
# 获取指定元素的排名
zrank key member (返回值从0开始计数)
zrevrank key member (返回的是元素在有序集合中逆序排名)
# 更新分数
zadd key score member
# 删除元素
zrem key member
性能和优化:
-
SortedSet 的操作时间复杂度一般是比较低的
- 例如:
ZADD
、ZREM
等单个元素操作的时间复杂度通常是 O(logN),这使得它能够高效地处理大量数据
- 例如:
-
如果需要对排行榜进行分页展示,可以利用 Sorted Set 的分页功能
- 通过合理设置 start 和 end 参数来获取不同页面的数据
-
还可以结合 Redis 的持久化功能,将排行榜数据持久化到磁盘,防止数据丢失
Redis做分布式锁如何实现?
分布式锁:是用于分布式环境下并发控制的一种机制,用于控制某个资源在同一时刻只能被一个应用所使用
Redis 本身可以被多个客户端共享访问,正好就是一个共享存储系统,可以用来保存分布式锁, 而且 Redis 的读写性能高,可以应对高并发的锁操作场景
Redis 的 SET 命令有个 NX 参数可以实现「key不存在才插入」,所以可以用它来实现分布式锁:
- 如果 key 不存在,则显示插入成功,可以用来表示加锁成功
- 如果 key 存在,则会显示插入失败,可以用来表示加锁失败
基于 Redis 节点,实现分布式锁时,对于加锁操作,我们需要满足三个条件:
- 加锁包括了读取锁变量、检查锁变量值和设置锁变量值三个操作,但需要以原子操作的方式完成,所以,我们使用 SET 命令带上 NX 选项来实现加锁
- 锁变量需要设置过期时间,以免客户端拿到锁后发生异常,导致锁一直无法释放,所以,我们在 SET 命令执行时加上 EX/PX 选项,设置其过期时间
- 锁变量的值需要能区分来自不同客户端的加锁操作,以免在释放锁时,出现误释放操作,所以,我们使用 SET 命令设置锁变量值时,每个客户端设置的值是一个唯一值,用于标识客户端
满足这三个条件的分布式命令:
SET lock_key unique_value NX PX 10000
- lock_key 就是 key 键
- unique_value 是客户端生成的唯一的标识,区分来自不同客户端的锁操作
- NX 代表只在 lock_key 不存在时,才对 lock_key 进行设置操作
- PX 10000 表示设置 lock_key 的过期时间为 10s,这是为了避免客户端发生异常而无法释放锁
解锁的过程:del lock_key
但不能乱删,要保证执行操作的客户端就是加锁的客户端
所以,解锁的时候,我们要先判断锁的 unique_value 是否为加锁客户端,是的话,才将 lock_key 键删除
解锁是有两个操作,这时就需要 Lua 脚本来保证解锁的原子性,因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,保证了锁释放操作的原子性
// 释放锁时,先比较 unique_value 是否相等,避免锁的误释放
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
这样一来,就通过使用 SET 命令和 Lua 脚本在 Redis 单节点上完成了分布式锁的加锁和解锁