问题

Redis 7 新特性有哪些?

答案

1. 核心概念

Redis 7.0 于 2022 年 4 月发布,被誉为Redis历史上变化最大的版本。主要新特性聚焦在底层数据结构优化IO性能提升持久化机制改进功能增强四个方面,显著提升了Redis的性能、可靠性和易用性。


2. 核心新特性详解

2.1 ListPack:替代ZipList的紧凑结构

核心概念

ListPack(紧凑列表)是Redis 7.0引入的新数据结构,用于替代ZipList(压缩列表),解决了ZipList的级联更新问题,提升了小数据量场景下的性能。

原理与源码关键点

ZipList的问题

// ZipList结构(Redis 7.0前)
<zlbytes><zltail><zllen><entry1><entry2>...<entryN><zlend>

// 问题:每个entry存储了前一个entry的长度(prevlen)
// 当插入/删除元素时,可能导致后续所有entry的prevlen字段需要更新
// 最坏情况:O(N²)复杂度,级联更新

ListPack的改进

// ListPack结构(Redis 7.0+)
<total_bytes><size><entry1><entry2>...<entryN><end>

// 关键改进:
// 1. 每个entry只存储自己的长度,不存储前一个entry的长度
// 2. 从后往前遍历,通过end标记(0xFF)定位
// 3. 插入/删除只需修改局部,避免级联更新

ListPack Entry结构

<encoding-type><element-data><element-total-len>

element-total-len: 变长编码,存储整个entry的长度

编码切换条件

# Redis 7.0配置
hash-max-listpack-entries 512   # Hash使用ListPack的元素数量阈值
hash-max-listpack-value 64      # Hash单个值大小阈值(字节)
zset-max-listpack-entries 128   # ZSet使用ListPack的元素数量阈值
zset-max-listpack-value 64      # ZSet单个值大小阈值(字节)

查看编码

redis> HSET user:1001 name "Alice" age "25"
redis> OBJECT ENCODING user:1001
"listpack"  # Redis 7.0+ 使用ListPack

redis> HSET user:1001 bio "这是一个超过64字节的长文本..."
redis> OBJECT ENCODING user:1001
"hashtable"  # 超过阈值自动转换为HashTable

性能优化与场景考量

  • 内存优化:ListPack相比HashTable节省30-50%内存(小数据量场景)
  • 性能提升:插入/删除操作从O(N²)优化到O(N),避免级联更新
  • 适用场景:Hash、ZSet在元素数量少、值较小时自动使用ListPack
  • 注意事项:超过阈值会自动转换为HashTable,需合理控制数据规模

2.2 多线程IO(后台IO线程)

核心概念

Redis 7.0引入了多线程IO机制,将网络IO操作(读/写)从主线程中分离出来,由后台IO线程处理,提升高并发场景下的性能。注意:命令执行仍然是单线程的。

原理与源码关键点

Redis 6.0 vs Redis 7.0

Redis 6.0:
主线程: [接收连接] -> [读取请求] -> [解析命令] -> [执行命令] -> [写入响应] -> [发送响应]
         ↑________________________↑                    ↑________________________↑
             网络IO(阻塞)                                 网络IO(阻塞)

Redis 7.0:
主线程: [接收连接] -> [解析命令] -> [执行命令]
IO线程: [读取请求] -> [写入响应] -> [发送响应]

关键配置

# 开启多线程IO
io-threads 4              # IO线程数量(建议为CPU核心数)
io-threads-do-reads yes    # 是否启用读线程(Redis 7.0+新增)

源码关键点

// Redis 7.0 网络IO处理流程
// 1. 主线程接收连接,将socket加入队列
// 2. IO线程从队列读取socket,执行read操作
// 3. 主线程解析命令并执行(单线程)
// 4. IO线程执行write操作,发送响应

性能优化与场景考量

  • 性能提升:高并发场景下QPS提升20-40%(取决于网络延迟)
  • 适用场景
    • 网络延迟较高的场景(如跨机房)
    • 大value读写场景(减少主线程阻塞时间)
    • 高并发读多写少场景
  • 注意事项
    • 命令执行仍是单线程,CPU密集型操作不会加速
    • IO线程数建议设置为CPU核心数,过多反而降低性能
    • 低延迟场景(本地网络)提升不明显

示例

# 配置多线程IO
redis> CONFIG SET io-threads 4
redis> CONFIG SET io-threads-do-reads yes

# 查看IO线程状态
redis> INFO stats
# io_threaded_reads_processed: 1000000
# io_threaded_writes_processed: 1000000

2.3 Redis Functions(函数机制)

核心概念

Redis Functions是Redis 7.0引入的函数编程机制,允许将Lua脚本以函数库的形式加载到Redis中,支持持久化和主从复制,解决了EVAL命令的脚本管理问题。

原理与源码关键点

EVAL vs Functions

特性 EVAL命令 Redis Functions
持久化 不支持 支持(RDB/AOF)
主从复制 不确定 自动同步
管理 每次执行需传脚本 一次加载,多次调用
性能 每次解析 预编译,性能更好

函数库结构

#!lua name=mylib

-- 函数定义
redis.register_function('set_key', function(keys, args)
    return redis.call('SET', keys[1], args[1])
end)

redis.register_function('get_key', function(keys, args)
    return redis.call('GET', keys[1])
end)

加载和使用

# 加载函数库
redis> FUNCTION LOAD "#!lua name=mylib\nredis.register_function('set_key', ...)"

# 调用函数
redis> FCALL set_key 1 mykey "myvalue"
"OK"

# 查看函数库
redis> FUNCTION LIST
1) "mylib"

# 删除函数库
redis> FUNCTION DELETE mylib

性能优化与场景考量

  • 性能提升:函数预编译,执行速度比EVAL快10-20%
  • 适用场景
    • 复杂业务逻辑封装(如分布式锁、限流)
    • 原子性操作组合(如扣减库存+记录日志)
    • 需要持久化的脚本逻辑
  • 注意事项
    • 函数库会占用内存,需合理管理
    • 函数修改需重新加载,可能影响正在执行的请求
    • 主从复制时函数库会自动同步

Java示例

// 使用Jedis加载函数
String functionCode = "#!lua name=mylib\n" +
    "redis.register_function('increment_with_log', function(keys, args)\n" +
    "    local value = redis.call('INCR', keys[1])\n" +
    "    redis.call('LPUSH', 'log:increment', value)\n" +
    "    return value\n" +
    "end)";

jedis.functionLoad(functionCode);

// 调用函数
Object result = jedis.fcall("increment_with_log", 
    Collections.singletonList("counter:1001"), 
    Collections.emptyList());

2.4 Multi-part AOF(多部分AOF)

核心概念

Multi-part AOF是Redis 7.0对AOF持久化机制的改进,将单一AOF文件拆分为基础文件(base)增量文件(incr),提升数据恢复效率和可靠性。

原理与源码关键点

传统AOF vs Multi-part AOF

传统AOF(Redis 7.0前):
appendonly.aof (单一文件,可能很大)
  -> 重写时创建临时文件
  -> 替换原文件(原子操作)

Multi-part AOF(Redis 7.0+):
appendonly.aof.manifest (清单文件)
appendonly.aof.1.base.rdb (基础文件,RDB格式)
appendonly.aof.1.incr.aof (增量文件1)
appendonly.aof.2.incr.aof (增量文件2)
  -> 重写时只需重写base文件
  -> 增量文件自动合并

工作流程

1. 启动时:读取manifest文件,按顺序加载base和incr文件
2. 写入时:追加到当前incr文件
3. 重写时:
   - 创建新的base文件(RDB格式快照)
   - 创建新的incr文件
   - 更新manifest文件
   - 异步删除旧的base和incr文件

配置

# 开启AOF
appendonly yes

# AOF文件命名(Redis 7.0+自动使用multi-part)
# appendfilename "appendonly.aof"  # 实际会生成多个文件

# 查看AOF文件
ls appendonly.aof.*
# appendonly.aof.manifest
# appendonly.aof.1.base.rdb
# appendonly.aof.1.incr.aof

性能优化与场景考量

  • 恢复速度:基础文件使用RDB格式,恢复速度提升2-5倍
  • 可靠性:增量文件机制,减少数据丢失风险
  • 磁盘IO:重写时只需处理base文件,减少IO压力
  • 适用场景:所有需要AOF持久化的场景
  • 注意事项
    • 文件数量增加,需合理配置磁盘空间
    • 主从复制时需同步所有文件

2.5 Sharded Pub/Sub(分片发布订阅)

核心概念

Sharded Pub/Sub是Redis 7.0引入的集群模式下的发布订阅机制,允许消息在不同分片(shard)之间传递,扩展了Pub/Sub在集群模式下的应用场景。

原理与源码关键点

传统Pub/Sub vs Sharded Pub/Sub

传统Pub/Sub(Redis 7.0前):
- 只能在单个节点内工作
- 集群模式下,发布者和订阅者必须在同一分片
- 限制:无法跨分片通信

Sharded Pub/Sub(Redis 7.0+):
- 支持跨分片通信
- 使用特殊的前缀:S{shard_key}
- 消息路由到指定分片

使用方式

# 传统Pub/Sub(单节点或集群单分片)
PUBLISH mychannel "Hello"
SUBSCRIBE mychannel

# Sharded Pub/Sub(集群跨分片)
# 发布:消息会路由到shard_key对应的分片
SPUBLISH mychannel{user:1001} "Hello"  # 路由到user:1001所在分片

# 订阅:订阅指定分片的频道
SSUBSCRIBE mychannel{user:1001}  # 订阅user:1001所在分片的频道

路由机制

// Sharded Pub/Sub使用CRC16计算分片
int slot = CRC16.calculate("mychannel{user:1001}") % 16384;
// 消息路由到对应slot所在的节点

性能优化与场景考量

  • 扩展性:支持集群模式下的发布订阅,突破单节点限制
  • 适用场景
    • 集群模式下的消息通知
    • 基于用户ID的消息路由(如私信、通知)
    • 分布式系统中的事件发布
  • 注意事项
    • 跨分片通信可能带来延迟
    • 需合理设计shard_key,确保消息路由正确
    • 与传统Pub/Sub不兼容,需使用新的命令(SPUBLISH/SSUBSCRIBE)

Java示例

// 使用Jedis Cluster
JedisCluster cluster = new JedisCluster(nodes);

// 发布消息到指定分片
cluster.spublish("notifications{user:1001}", "You have a new message");

// 订阅(需使用JedisPubSub)
JedisPubSub subscriber = new JedisPubSub() {
    @Override
    public void onMessage(String channel, String message) {
        System.out.println("Received: " + message);
    }
};
cluster.ssubscribe(subscriber, "notifications{user:1001}");

2.6 ACL改进(访问控制列表增强)

核心概念

Redis 7.0对ACL(Access Control List)进行了增强,提供了更细粒度的权限控制命令类别支持动态用户管理,提升了Redis的安全性。

核心改进

  1. 命令类别(Command Categories): ```bash

    Redis 7.0新增命令类别

    +@read # 只读命令 +@write # 写命令 +@admin # 管理命令 +@dangerous # 危险命令 +@fast # 快速命令 +@slow # 慢命令

示例:授予只读权限

ACL SETUSER readonly on >password ~* +@read -@all


2. **键模式匹配增强**:
```bash
# 支持更灵活的键模式
ACL SETUSER appuser on >password ~user:* ~order:* +@all -FLUSHDB
  1. 选择器(Selectors)
    # 为不同键设置不同权限
    ACL SETUSER appuser on >password 
     ~user:* +@read +@write 
     ~order:* +@read 
     ~admin:* -@all
    

性能优化与场景考量

  • 安全性:细粒度权限控制,减少误操作风险
  • 适用场景
    • 多租户系统(不同用户不同权限)
    • 生产环境权限隔离
    • 第三方服务接入(限制命令和键访问)
  • 注意事项
    • ACL配置复杂,需仔细设计权限策略
    • 性能影响:每次命令执行需检查ACL,但开销很小(<1%)

2.7 其他重要改进

命令增强

  1. SORT命令优化:支持更多排序选项,性能提升
  2. EXPIRE命令改进:支持更精确的过期时间控制
  3. STRALGO命令:字符串算法命令(最长公共子序列等)

性能优化

  1. 内存优化:ListPack减少内存占用
  2. 网络优化:多线程IO提升网络吞吐
  3. 持久化优化:Multi-part AOF提升恢复速度

监控与诊断

  1. LATENCY命令增强:更详细的延迟分析
  2. MEMORY命令改进:更精确的内存分析
  3. INFO命令扩展:更多监控指标

3. 性能优化与分布式场景考量

3.1 性能对比总结

特性 性能提升 适用场景
ListPack 插入/删除O(N²)→O(N) 小数据量Hash/ZSet
多线程IO QPS提升20-40% 高并发、网络延迟高
Redis Functions 执行速度提升10-20% 复杂业务逻辑封装
Multi-part AOF 恢复速度提升2-5倍 所有AOF场景

3.2 分布式场景考量

集群模式

  • Sharded Pub/Sub支持跨分片通信
  • Functions自动同步到从节点
  • Multi-part AOF在集群模式下正常工作

主从复制

  • Functions自动复制到从节点
  • Multi-part AOF文件同步
  • 多线程IO不影响复制性能

高可用

  • Multi-part AOF提升数据可靠性
  • Functions持久化确保脚本不丢失
  • ACL增强安全性

4. 面试答题总结

标准回答模板

Redis 7.0的主要新特性包括:

  1. ListPack:替代ZipList,解决级联更新问题,插入/删除从O(N²)优化到O(N)
  2. 多线程IO:网络IO多线程化,高并发场景QPS提升20-40%,但命令执行仍是单线程
  3. Redis Functions:函数编程机制,支持持久化和主从复制,性能比EVAL提升10-20%
  4. Multi-part AOF:AOF文件拆分,恢复速度提升2-5倍,可靠性增强
  5. Sharded Pub/Sub:集群模式下的发布订阅,支持跨分片通信
  6. ACL改进:更细粒度的权限控制,提升安全性

这些改进显著提升了Redis的性能、可靠性和易用性,特别适合高并发、分布式场景。

常见追问

  • ListPack为什么能解决级联更新? → 每个entry只存储自己的长度,不存储前一个entry的长度,插入/删除只需修改局部
  • 多线程IO会影响Redis的单线程模型吗? → 不会,命令执行仍是单线程,只是网络IO多线程化
  • Functions和EVAL的区别? → Functions支持持久化和主从复制,性能更好,管理更方便
  • Multi-part AOF的优势? → 基础文件用RDB格式,恢复速度快;增量文件机制,可靠性高
  • Sharded Pub/Sub的使用场景? → 集群模式下的消息通知,基于用户ID的消息路由

升级建议

  • 生产环境升级:建议先在测试环境验证,特别注意Functions和Multi-part AOF的兼容性
  • 性能调优:根据实际场景调整io-threads和ListPack相关配置
  • 监控指标:关注IO线程处理量、Functions内存占用、AOF文件大小等