面试题答案
一键面试保证操作一致性和幂等性的方案
- 使用分布式锁:
- 可以利用Redis的SETNX(SET if Not eXists)命令来实现分布式锁。在执行订阅或退订脚本前,每个节点尝试获取锁。例如,使用命令
SET lock_key value NX EX expire_time
,其中lock_key
是锁的键,value
是唯一标识该节点的值(如UUID),expire_time
是锁的过期时间,防止死锁。只有获取到锁的节点才能执行脚本,执行完毕后释放锁(使用DEL lock_key
)。 - 优点是简单直接,利用Redis自身特性实现。缺点是存在锁过期导致的并发问题,需要合理设置过期时间。
- 可以利用Redis的SETNX(SET if Not eXists)命令来实现分布式锁。在执行订阅或退订脚本前,每个节点尝试获取锁。例如,使用命令
- 基于Redis的事务:
- 将订阅或退订操作封装在Redis事务中。通过
MULTI
开启事务,将订阅或退订相关命令(如SUBSCRIBE
、UNSUBSCRIBE
)加入事务队列,最后使用EXEC
执行事务。Redis事务能保证队列中的命令按顺序执行,不会被其他客户端打断,从而确保操作的一致性。 - 优点是Redis原生支持,简单易用。缺点是不支持跨多个键的复杂事务,如果涉及多个频道的操作可能不太适用。
- 将订阅或退订操作封装在Redis事务中。通过
- 幂等性设计:
- 在脚本中,对于订阅操作,可以先检查是否已经订阅该频道。例如,使用
PUBSUB NUMSUB
命令获取当前节点对各频道的订阅数量,若已订阅则不再重复订阅。对于退订操作,同样先检查是否订阅,若未订阅则不执行退订操作。这样无论执行多少次脚本,结果都是一致的。
- 在脚本中,对于订阅操作,可以先检查是否已经订阅该频道。例如,使用
记录历史操作及结合持久化机制的设计思路和技术方案
- 使用Redis的List数据结构记录操作:
- 为每个节点或整个系统创建一个List来记录订阅和退订的历史操作。每次执行订阅或退订操作时,将操作信息(如操作类型:订阅/退订,频道名称,操作时间等)以JSON字符串或特定格式的字符串形式,使用
RPUSH
命令添加到List的尾部。例如,RPUSH history_list "subscribe,channel_name,2023 - 10 - 01 12:00:00"
。 - 优点是List结构适合按时间顺序记录操作,且Redis对List的操作性能较好。缺点是如果历史记录过多,读取和分析可能会比较耗时。
- 为每个节点或整个系统创建一个List来记录订阅和退订的历史操作。每次执行订阅或退订操作时,将操作信息(如操作类型:订阅/退订,频道名称,操作时间等)以JSON字符串或特定格式的字符串形式,使用
- 结合Redis持久化机制:
- RDB持久化:RDB会在指定的时间间隔内将内存中的数据集快照写入磁盘。对于记录操作的List,RDB可以保证在系统故障恢复时,能够恢复到最近一次快照时的历史记录状态。但由于RDB是定期快照,可能会丢失一些最新的操作记录。
- AOF持久化:AOF是以日志的形式记录服务器所处理的每一个写操作。开启AOF后,每次向记录操作的List中添加新记录,都会立即记录到AOF文件中。这样在系统恢复时,可以通过重放AOF文件中的操作来恢复到故障前的完整历史记录状态。但AOF文件可能会不断增大,需要定期进行重写。
- 综合考虑,可以同时开启RDB和AOF持久化。RDB用于快速恢复数据集,AOF用于保证历史操作记录的完整性。同时,定期对AOF文件进行重写,以减少文件大小,提高恢复效率。