乐观锁和悲观锁
在Redis中,锁机制主要用于处理并发操作,确保数据的一致性和完整性。Redis提供了两种常见的锁机制:乐观锁和悲观锁。
悲观锁
悲观锁是一种传统的锁机制,它假设在任何时候都可能发生冲突,因此在操作数据之前会先锁定数据,防止其他操作修改。在Redis中,悲观锁通常通过WATCH命令实现。
使用步骤:
使用WATCH命令监控一个或多个键。
执行事务(MULTI/EXEC),在事务中对监控的键进行修改。
如果在事务执行期间,监控的键被其他客户端修改,事务将失败,EXEC返回nil。
乐观锁
乐观锁假设在大多数情况下不会发生冲突,因此在操作数据时不加锁,而是在提交数据时检查数据是否被修改。在Redis中,乐观锁通常通过版本号或时间戳来实现。
使用步骤:
在数据中添加一个版本号或时间戳。
在更新数据时,先读取版本号或时间戳,然后在更新时检查版本号或时间戳是否一致。
如果版本号或时间戳一致,则更新数据并增加版本号或更新时间戳;如果不一致,则放弃更新。
总结
悲观锁:适用于写操作频繁的场景,通过WATCH命令实现。
乐观锁:适用于读操作频繁的场景,通过版本号或时间戳实现。
ROD和AOF
RDB是一种快照持久化方式,它会在指定的时间间隔内将Redis数据库的完整快照保存到磁盘上。RDB文件是一个紧凑的二进制文件,适用于备份和恢复。
优点:
高效:RDB文件是一个紧凑的二进制文件,适合大规模数据恢复。
性能:Redis在生成RDB文件时会fork出一个子进程,主进程不受影响,因此对性能影响较小。
缺点:
数据丢失:如果在两次快照之间发生崩溃,可能会丢失最后一次快照之后的数据。
配置复杂:需要配置多个保存点(save points),以确保数据的安全性。
AOF是一种日志持久化方式,它会将每个写操作追加到AOF文件中。AOF文件是一个文本文件,记录了所有写操作的命令,Redis重启时会重新执行这些命令以恢复数据。
优点:
数据完整性:AOF记录了每个写操作,因此数据丢失的风险较小。
可读性:AOF文件是文本文件,便于人类阅读和理解。
缺点:
性能:AOF文件通常比RDB文件大,且写操作频繁时对性能有一定影响。
恢复速度:AOF文件恢复速度通常比RDB文件慢,因为需要重新执行所有写操作。
选择合适的持久化方式
RDB:适用于对性能要求较高,且能容忍一定数据丢失的场景。
AOF:适用于对数据完整性要求较高,且能容忍一定性能损失的场景。
在实际应用中,可以同时使用RDB和AOF,以兼顾性能和数据完整性。Redis会优先使用AOF文件进行数据恢复,因为AOF文件记录了更完整的数据变化历史。
主从分离
Redis的主从复制(Master-Slave Replication)是一种常见的数据复制和高可用性解决方案。通过主从复制,可以将一个Redis实例(主节点)的数据复制到一个或多个其他Redis实例(从节点),从而实现数据的冗余备份和读写分离。
主从复制的原理
同步(Sync):当从节点启动时,会向主节点发送SYNC命令,请求全量复制数据。主节点会生成一个RDB文件,并将文件发送给从节点。
命令传播(Command Propagation):在全量复制完成后,主节点会将后续的写命令发送给从节点,以保持数据的一致性。
部分重同步(Partial Resynchronization):在主从节点断开重连后,Redis 2.8及以上版本支持部分重同步,即只同步断开期间缺失的数据,而不是全量复制。
注意:如果主机断开,从机也不会上位。
缓存击穿,穿透,雪崩
缓存穿透
定义:缓存穿透是指查询一个不存在的数据,由于数据不存在,缓存中也不会有该数据,因此每次查询都会直接访问数据库,导致数据库压力增大。
解决办法:
布隆过滤器:在缓存之前使用布隆过滤器来过滤掉不存在的数据请求。布隆过滤器是一种空间效率高的概率型数据结构,用于测试一个元素是否属于一个集合。
空值缓存:对于查询结果为空的数据,也进行缓存,并设置一个较短的过期时间
缓存雪崩
定义:缓存雪崩是指缓存中大量数据在同一时间失效,导致大量请求直接访问数据库,造成数据库压力骤增,甚至宕机。
解决办法:
随机过期时间:为缓存数据设置随机的过期时间,避免大量数据同时失效。
多级缓存:使用多级缓存架构,如本地缓存+分布式缓存,减少对单一缓存的依赖。
热点数据永不过期:对于热点数据,可以设置永不过期,通过后台线程定期更新。
缓存击穿
定义:缓存击穿是指一个热点数据在缓存中过期,此时大量请求同时访问该数据,导致所有请求都直接访问数据库,造成数据库压力骤增。
解决办法:
互斥锁:在查询数据库时使用互斥锁,保证只有一个请求去查询数据库并更新缓存,其他请求等待缓存更新完成。
热点数据永不过期:对于热点数据,可以设置永不过期,通过后台线程定期更新。
内存淘汰策略
- 不淘汰(noeviction)
策略描述:当内存达到上限时,Redis不再接受写操作,并返回错误。这是默认的淘汰策略。
适用场景:适用于对数据完整性要求极高的场景,确保不会因为内存不足而丢失数据。
- 随机淘汰(allkeys-random)
策略描述:从所有键中随机选择数据进行淘汰。
适用场景:适用于数据重要性不高,且希望均匀分布淘汰影响的场景。
- LRU淘汰(allkeys-lru)
策略描述:Least Recently Used(最近最少使用),从所有键中选择最近最少使用的数据进行淘汰。
适用场景:适用于数据访问模式较为均匀,且希望保留最近访问的数据的场景。
- LFU淘汰(allkeys-lfu)
策略描述:Least Frequently Used(最不经常使用),从所有键中选择访问频率最低的数据进行淘汰。
适用场景:适用于数据访问频率差异较大,且希望保留高频访问数据的场景。
- 过期键优先淘汰(volatile-ttl)
策略描述:从设置了过期时间的键中,选择剩余生存时间(TTL)最短的数据进行淘汰。
适用场景:适用于希望优先淘汰即将过期的数据的场景。
- 过期键LRU淘汰(volatile-lru)
策略描述:从设置了过期时间的键中,选择最近最少使用的数据进行淘汰。
适用场景:适用于希望优先淘汰过期键中的最近最少使用数据的场景。
- 过期键LFU淘汰(volatile-lfu)
策略描述:从设置了过期时间的键中,选择访问频率最低的数据进行淘汰。
适用场景:适用于希望优先淘汰过期键中的最不经常使用数据的场景。
配置方法
可以通过Redis的配置文件(redis.conf)或动态命令来设置淘汰策略。