Redis 为什么快
- 纯内存操作,避免磁盘 IO
- 使用了 IO 多路复用机制,无须等待一个慢连接的操作,可以高效的处理多个网络连接
- 单线程模型,避免了频繁的上下文切换
Redis 持久性
- AOF
AOF 同步策略:- always: 每执行一条命令就同步到磁盘,数据安全性最高,但性能较差。
- everysec: 每秒同步一次,在性能和数据安全性之间取得平衡。
- no: 由操作系统决定何时写入磁盘.
- RDB
Redis 快照
特点:- 文件小,RDB 文件是压缩的二进制文件
- 恢复速度快,恢复数据时只需要加载一个文件
影响 Redis 性能的点
- 集合的全量查询和聚合操作(可考虑使用 scan 分批读取数据,在客户端操作)
- bigkey 删除,大量空间的释放会在内存重新分配时耗时
- 清空数据库,flushdb flushall 等,可考虑使用(flushdb async)来异步清空
- AOF 日志同步写
- 从库加载 RDB 文件
- 大量数据的写入会导致 hash 冲突,redis 使用的链式 hash 会导致操作变慢,为避免这个问题,使用了渐进式 hash
针对 big 可以问题的解决方案
如何避免
- 拆分 bigkey,将一个大的 key 拆分成多个小的 key
- 选择合理的数据结构
- 水平分片,将数据分配到多个 redis 实例
删除
- 使用 unlink 异步删除
- 渐进式删除,每次分批删除一部分,可以使用 scan,hscan,zscan 等
redis6.0 为什么引入多线程,不是已经有了 IO 多路复用吗
Redis 6.0 引入多线程的原因主要在于优化网络 IO 性能,而不是替代多路 IO 复用机制。简要来说:
1️. 多路 IO 复用(如 epoll)仍然承担着管理客户端连接和事件分发的核心工作,确保单线程模型带来的简单性和原子性;
2️. 多线程被引入后,用于并行处理网络数据的读写(如请求数据的读取与响应数据的发送),从而减少了数据在单线程处理时的瓶颈,尤其在处理大 value 或高并发大量数据传输时提升了吞吐量;
3️. 总体上:命令解析和执行依旧保持单线程来维护数据一致性,而多线程仅用于网络数据 IO 的辅助处理,二者协同工作,实现了性能和稳定性的平衡。
网络 I/O 并行化:
多个 I/O 线程: Redis 6.0 将网络请求的处理分配给多个 I/O 线程,每个线程负责处理一部分连接。
并行处理: 这样,多个客户端的请求可以并行处理,提高了网络 I/O 的吞吐量。
减少阻塞: 一个慢速的请求不会阻塞其他请求,提高了系统的整体响应速度。
Redis 循序渐进
为了防止单个实例宕机,引入主从。为了防止主库宕机无法提供服务,引入哨兵机制来实现主从切换。
为了防止哨兵宕机和误判,引入了哨兵集群。
为了在数据量过大时单机实例无法容纳或者性能下降的问题,引入切片集群,将数据分散到多个实例上。
Redis 变慢问题排查
- 是否阻塞性操作,
key *
命令,或同步删除 bigkey - 是否开启了 AOF 日志并同步写
- 查看是否发生内存 swap,是否数据量太大导致了 swap,可以考虑增加物理内存
https://freegeektime.com/100056701/287819/
缓存淘汰策略
Redis7.0 的默认缓存淘汰策略是noeviction
, 这意味着当 Redis 的内存使用量达到设置的最大值时,新的写入操作将会失败,而不是去主动淘汰旧的数据。
可通过命令设置其他的淘汰策略,如 LRU
config set maxmemory-policy volatile-lru
缓存更新策略
- Cache-Aside: 先更新数据库再删除缓存
- Read Through: 应用先查询缓存,如果缓存中没有数据,就查询数据库并写入缓存。如果缓存有数据就直接返回。
- Write Through: 应用先更新数据库,再更新缓存。缺点:缓存更新失败会导致数据一致性问题。可加入重试机制。
- Write Behind: 异步写回。应用先更新缓存,异步将更新操作写入消息队列,消费者从消息队列取更新操作写入数据库
- Write Around: 写绕过。写操作直接更新数据库。读操作先从缓存取,如果没有查询数据库并更新缓存。缺点:缓存更新滞后,导致数据一致性问题。