五种数据类型:
String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)
性能优化:
使用批量操作来减少网络传输,减少RTT [往返时间](网络传输时间)
- 原生批量操作命令 MGET、HMGET等、
- 如 批量获取多个字符串键的值
- 减少RTT时间
- 原生实现、效率最高
- 命令支持有限、Key数量有限
- 如 批量获取多个字符串键的值
- pipeline(流水线):将一批redis命令封装成一组然后一次性提交给服务器。
- 十分通用,可以打包各种命令
- 非原子性
- 需要控制包(元素)的大小
- Lua脚本:将多个命令写在一个 Lua 脚本中,然后将整个脚本作为一个字符串发送给 Redis 服务器。Redis 会单线程、原子性地执行整个脚本。
- 原子性,但无法回滚,若程序异常中断,中断前的内容也会生效
- 灵活性高,也可以实现较为复杂的逻辑
- 有性能风险,编写的垃圾脚本可能导致堵塞线程
- 主从复制Lua脚本可能会有压力
关于HotKey
- 发现方法:
- 用自带的 –hotkeys参数查找
- 使用Monitor命令
- 根据业务情况提前预估
- 解决方法:
- 拆分Key:
- 一个 Key 的 Value 是一个包含 10000 个字段的 Hash,每次读取都传输整个 Value,则进行Key的拆分,将其拆分成 10 个 Hash,每个 Hash 包含 1000 个字段。
- 读写分离:
- 使用主从架构,将读请K求分散到多个从节点上。让应用程序将写请求发往主节点,而将大量的读请求发往一个或多个从节点。
- 二级缓存:
- 若热点Key:12345,则在L1本地缓存中缓存一份key:12345的数据。若未命中则查询L2(Redis)缓存 [ 这包含了本地缓存策略 ]
- 拆分Key:
基于Redis实现延时任务
- Redis过期事件监听:
- 时效性差:
- Redis采用的定时删除+惰性删除原则 会导致指定的过期时间到了但是Key还未被删除,进而没有发布过期事件的情况
- 还有丢消息和消息重复的问题,都是Redis 的pub/sub模式固有的弊端
- 时效性差:
- Redisson内置的延时队列
3种常用的缓存读写策略详解
- Cache Aside Pattern (旁路缓存模式)
- 适合读比较多的场景
- 服务端需要同时维系db和cache
- 写:先更新db,再更新cache
- 读:从cache中读取数据,读取到就直接返回。
- 读不到就从db读取。再把数据存入cache
- 为什么是先更新数据库,再删除cache?
- 若先删除cache,则在数据库更新前有请求访问cache,未命中,则直达数据库将旧数据写进缓存导致数据不一致
- 若先更新缓存,如果数据库更新失败,则会导致缓存中的数据变成脏数据
- 若先更新数据库,再更新缓存,则会导致在并发写的情况下,可能会出现线程A更新数据库后,线程B更新数据库,然后线程B更新缓存,最后线程A更新缓存的情况,导致缓存中是线程A的旧数据。
- 为什么是先更新数据库,再删除cache?
- 读不到就从db读取。再把数据存入cache
- Read/Write Through Pattern (读写穿透)
- 有性能问题,而且Redis没有提供将cache写入数据库的功能
- Write Behind Pattern (异步缓存写入)
- 有较强的数据不一致性问题
AOF持久化
1. 命令执行
- 当 Redis 客户端执行一个写命令时(例如
SET,HSET,SADD,DEL等),服务器会在执行完该命令、将数据更新到内存中之后。 - 将这个命令按照 Redis 序列化协议(RESP)的格式追加到服务器内存中的一个缓冲区(aof_buf)。
关键点:先执行命令,再记录日志。这样做可以避免记录错误的命令,并且不会阻塞当前的写操作。但潜在风险是,如果命令执行成功但日志记录失败,可能会在宕机时丢失数据。
2. 日志追加AOF
- 上一步中的
aof_buf缓冲区存在于内存中,目的是为了将多次写命令集中起来,避免每次写命令都直接进行磁盘 I/O 操作,从而提升性能。
3. 文件同步/写入
- Redis根据预先配置的策略,来决定何时将
aof_buf缓冲区中的内容真正写入并同步到磁盘上的 AOF 文件中- AOF 缓冲区根据对应的持久化方式(
fsync策略)向硬盘做同步操作。这一步需要调用fsync函数(系统调用),fsync针对单个文件操作,对其进行强制硬盘同步,fsync将阻塞直到写入磁盘完成后返回,保证了数据持久化。
- AOF 缓冲区根据对应的持久化方式(
4. 数据恢复 (Data Recovery)
- 当 Redis 服务器重启时,如果需要使用 AOF 文件进行数据恢复,它会自动执行以下操作:
- 启动一个伪客户端。
- 从头到尾读取 AOF 文件中的所有命令。
- 按顺序逐一重新执行这些命令,从而在内存中重建整个数据集。
Redis常见堵塞原因
- O(n)命令:时间复杂度过大的命令可能导致堵塞,比如一些特定的KEYS *
- 手动使用SAVE命令生成RDB快照文件
- AOF日志记录阻塞(AOF日志记录是在主线程中进行的):
- AOF日志记录是在当前命令组执行完毕后开始记录
- 可以省略语法检查
- 不会阻碍当前命令组的执行
- 但是可能会阻止其他命令组的执行
- AOF日志记录是在当前命令组执行完毕后开始记录
- AOF刷盘阻塞:当后台线程调用
fsync函数同步 AOF 文件时,需要等待,直到写入完成。当磁盘压力太大的时候,会导致fsync操作发生阻塞 - AOF重写阻塞:将缓冲区中新数据写到新文件的过程中可能会产生阻塞。
Redis事务特性
- 原子性:不具备原子性,因为不支持回滚因为开发者觉得没必要,命令错误应该在开发层面被发现
- 持久性:支持,但是性能很差
- 可以用Lua脚本保证原子性,但是Lua脚本要求代码命令不能有错,因为错误行前的代码都会被写入且执行
