Redis(每天两道面试题)

19 阅读3分钟

如何用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 的操作时间复杂度一般是比较低的

    • 例如:ZADDZREM 等单个元素操作的时间复杂度通常是 O(logN),这使得它能够高效地处理大量数据
  • 如果需要对排行榜进行分页展示,可以利用 Sorted Set 的分页功能

    • 通过合理设置 start 和 end 参数来获取不同页面的数据
  • 还可以结合 Redis 的持久化功能,将排行榜数据持久化到磁盘,防止数据丢失

Redis做分布式锁如何实现?

分布式锁:是用于分布式环境下并发控制的一种机制,用于控制某个资源在同一时刻只能被一个应用所使用

Redis 本身可以被多个客户端共享访问,正好就是一个共享存储系统,可以用来保存分布式锁, 而且 Redis 的读写性能高,可以应对高并发的锁操作场景

Redis 的 SET 命令有个 NX 参数可以实现「key不存在才插入」,所以可以用它来实现分布式锁:

  • 如果 key 不存在,则显示插入成功,可以用来表示加锁成功
  • 如果 key 存在,则会显示插入失败,可以用来表示加锁失败

基于 Redis 节点,实现分布式锁时,对于加锁操作,我们需要满足三个条件:

  1. 加锁包括了读取锁变量、检查锁变量值和设置锁变量值三个操作,但需要以原子操作的方式完成,所以,我们使用 SET 命令带上 NX 选项来实现加锁
  2. 锁变量需要设置过期时间,以免客户端拿到锁后发生异常,导致锁一直无法释放,所以,我们在 SET 命令执行时加上 EX/PX 选项,设置其过期时间
  3. 锁变量的值需要能区分来自不同客户端的加锁操作,以免在释放锁时,出现误释放操作,所以,我们使用 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[1then  
  return redis.call("del",KEYS[1])  
else  
  return 0  
end

这样一来,就通过使用 SET 命令和 Lua 脚本在 Redis 单节点上完成了分布式锁的加锁和解锁