Redis 7.0在2022年4月正式发布,带来了很多新特性和性能优化。
我们公司的Redis一直用的是6.2版本,随着业务增长,Redis的压力越来越大,高峰期响应时间能到10ms以上,偶尔还会超时。老板让我研究一下Redis 7.0,看看能不能通过升级和优化提升性能。
我花了一周时间,研究了Redis 7.0的新特性,在测试环境验证后,把生产环境的Redis从6.2升级到了7.0,同时做了全面的性能优化。最终效果不错:平均响应时间从5ms降到了1ms,高峰期也能稳定在2ms以内。
本文分享Redis 7.0的新特性、升级过程、性能优化实战、踩坑记录,帮你用好Redis 7.0。
一、Redis 7.0的重要新特性
先说说Redis 7.0有哪些重要的新特性。
1. Redis Functions
Redis 7.0引入了Functions(函数),这是一个重要的新特性。
Functions和Lua脚本类似,但有几个优势:
- Functions是持久化的,存在数据库里,重启不丢失
- Functions有版本管理,可以升级
- Functions支持AOF和复制,更可靠
- Functions的执行效率更高
Lua脚本的问题是:每次都要传脚本内容,或者用EVALSHA但要管理脚本缓存,主从切换时脚本可能丢失。Functions解决了这些问题。
# 创建函数
redis-cli -x FUNCTION LOAD REPLACE <<EOF
#!lua name=mylib
redis.register_function('myincr', function(keys, args)
return redis.call('INCR', keys[1])
end)
EOF
# 调用函数
redis-cli FCALL myincr 1 mykey2. 多部分AOF(Multi-part AOF)
Redis 7.0改进了AOF(Append Only File)持久化机制。
以前的AOF是一个文件,重写的时候会创建一个临时文件,重写完成后替换。Redis 7.0把AOF分成了多个文件:
- 基础文件(base file):重写生成的快照
- 增量文件(incr file):重写之后的增量命令
- 清单文件(manifest file):记录文件列表和历史
这种方式的好处:
- AOF重写更快,不需要复制整个文件
- 崩溃恢复更快,只需要加载基础文件+增量文件
- 支持AOF的原子操作,更安全
3. ACL改进
Redis 7.0改进了ACL(访问控制列表):
- 支持按key前缀授权(
~prefix:*) - 支持按命令的子命令授权
- 支持select命令的权限控制
- ACL可以持久化到外部文件
这些改进,让Redis的权限管理更细粒度,更安全。
4. 客户端Eviction
Redis 7.0新增了客户端Eviction机制。
当内存不足时,Redis可以自动断开一些客户端连接,释放内存。可以配置:
- 最大客户端内存使用量
- 断开哪些类型的客户端(普通客户端、从节点、订阅客户端等)
这对防止客户端内存泄漏很有用。
5. 性能优化
Redis 7.0做了很多底层的性能优化:
- 列表(List)的底层实现优化,内存占用更少
- 哈希(Hash)的编码优化,小哈希更省内存
- 网络IO优化,高并发下性能更好
- 过期key的删除优化,减少阻塞
- RDB加载速度提升
根据官方测试,Redis 7.0比6.0性能提升了约20-30%。
6. 其他新特性
SHUTDOWN命令增加了NOW、FORCE选项CLIENT NO-EVICT命令,保护特定客户端不被evictCOMMAND DOCS命令,查看命令的文档- 支持
EXPIRETIME、PEXPIRETIME命令,查看过期时间戳 - 集群模式的改进,支持更灵活的槽位迁移
二、升级过程
说说我们从Redis 6.2升级到7.0的过程。
1. 升级前的准备
升级前,做了充分的准备:
- 阅读Redis 7.0的release notes,了解不兼容的变化
- 检查应用代码,确认没有使用被废弃的命令
- 备份数据,确保可以回滚
- 在测试环境验证,确认应用兼容
不兼容的变化:
- 一些旧的配置项被移除或改名
INFO命令的输出格式有变化- Lua脚本的一些行为有变化
- 一些旧的RDB格式不再支持
2. 升级步骤
我们用的是主从架构,升级步骤:
- 先升级从节点:停掉从节点,替换二进制文件,启动,等待同步完成
- 验证从节点:确认数据同步正常,应用能正常连接
- 主从切换:把主节点切换为从节点,原从节点变为主节点
- 升级原主节点:停掉原主节点,替换二进制文件,启动,作为从节点同步
- 验证:确认主从同步正常,应用无异常
整个过程,应用没有停机,只是在主从切换时有几秒钟的延迟。
3. 回滚方案
准备了回滚方案:
- 如果升级后出问题,立即切回6.2版本的主节点
- 数据用升级前的备份恢复
- 应用的连接配置改回原地址
因为Redis 7.0的RDB格式和6.2不完全兼容,回滚的时候要注意数据格式。
三、性能优化实战
升级之后,做了全面的性能优化。
1. 内存优化
Redis是内存数据库,内存优化是重点。
优化一:使用合适的数据结构
- 小数据量用压缩编码:Hash、List、ZSet在元素少的时候用压缩列表(ziplist/listpack),省内存
- 避免大key:单个key不要存太多数据,否则会阻塞Redis
- 用Bitmap、HyperLogLog等概率数据结构,省内存
我们有一个用户标签的场景,原来用Set存每个用户的标签,内存占用很大。改成用Bitmap后,内存占用减少了80%。
优化二:设置过期时间
很多key没有设置过期时间,一直存在内存里。
我们梳理了所有的key,给不需要永久存储的key都加了过期时间。比如:
- 缓存数据:1小时到1天
- 会话数据:7天
- 临时数据:1小时
加了过期时间后,内存占用减少了30%。
优化三:内存淘汰策略
配置了合理的内存淘汰策略:
maxmemory 10gb
maxmemory-policy allkeys-lruallkeys-lru表示所有key都按LRU淘汰。我们的场景是缓存为主,用这个策略比较合适。
如果是有持久化需求的场景,可以用volatile-lru(只淘汰设置了过期时间的key)。
优化四:Redis 7.0的listpack
Redis 7.0用listpack替代了ziplist,listpack更省内存,访问更快。
升级到7.0后,小Hash、小List、小ZSet自动用listpack编码,内存占用减少了约15%。
2. 网络优化
优化一:连接池
应用端用连接池,避免频繁创建和销毁连接。
我们的Java应用用的是Lettuce,配置了连接池:
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxTotal(50);
poolConfig.setMaxIdle(20);
poolConfig.setMinIdle(5);连接池的大小要合理,不是越大越好。一般来说,连接数 = CPU核心数 * 2 + 磁盘数。
优化二:Pipeline
对于批量操作,用Pipeline减少网络往返。
比如,一次更新100个key,不用循环执行100次命令,而是用Pipeline一次发送。
List<Object> results = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
for (String key : keys) {
connection.get(key.getBytes());
}
return null;
});用Pipeline后,批量操作的性能提升了5-10倍。
优化三:避免热key
热key是指访问量特别大的key,会导致单个Redis节点压力过大。
我们的解决方案:
- 本地缓存:热点数据在应用端做本地缓存(Caffeine),减少Redis访问
- key拆分:把一个热key拆成多个key,分散压力
- 读写分离:读请求走从节点,写请求走主节点
3. 持久化优化
优化一:AOF配置
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mbappendfsync everysec:每秒刷盘一次,性能和安全的平衡- 自动重写:AOF文件增长100%且超过64MB时自动重写
Redis 7.0的多部分AOF,重写速度更快,对性能影响更小。
优化二:RDB配置
save 900 1
save 300 10
save 60 10000RDB快照的频率要合理,太频繁会影响性能,太少会丢失更多数据。
我们的场景,用AOF为主,RDB为辅。RDB主要用于备份和快速重启。
优化三:禁用危险命令
在生产环境,禁用一些危险命令:
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command KEYS ""防止误操作导致数据丢失或性能问题。
4. 慢查询优化
用SLOWLOG命令查看慢查询:
SLOWLOG GET 10我们发现了几个慢查询:
KEYS *:全量遍历,禁用,改用SCAN- 大key的
HGETALL:拆分成多个小key,或者用HSCAN - 复杂的Lua脚本:优化脚本逻辑,或者拆分成多个命令
优化后,慢查询从每天几十条降到了几乎没有。
四、具体的优化案例
说说几个具体的优化案例。
案例一:排行榜优化
我们有一个排行榜功能,用ZSet实现。原来的实现是每次都全量计算排名,性能很差。
优化方案:
- 用ZSet的
ZREVRANK命令直接获取排名,O(log N)复杂度 - 用
ZINCRBY增量更新分数,不需要全量重算 - 排行榜前100名用缓存,减少Redis访问
优化后,排行榜接口的响应时间从50ms降到了2ms。
案例二:计数器优化
我们有一个文章阅读量计数器,每篇文章一个key,用INCR更新。
问题是,文章很多,key数量大,内存占用高。而且每次阅读都写Redis,压力大。
优化方案:
- 用Hash把多篇文章的计数存在一个key里,减少key数量
- 应用端先累加,每隔一段时间批量写入Redis
- 用Redis 7.0的Functions,把计数逻辑封装成函数,减少网络往返
优化后,内存占用减少了50%,写入QPS提升了3倍。
案例三:缓存穿透优化
我们遇到了缓存穿透的问题:大量请求查询不存在的key,直接打到数据库。
优化方案:
- 缓存空值:查询不存在的key,也缓存一个空值,过期时间短一些(比如5分钟)
- 布隆过滤器:用Redis的Bloom Filter(RedisBloom模块),过滤不存在的key
- 接口限流:对异常流量限流
优化后,数据库的压力减少了80%。
五、监控和运维
优化之后,监控和运维也很重要。
1. 关键监控指标
用Prometheus + Grafana监控Redis:
- 性能指标:QPS、响应时间、慢查询数
- 内存指标:内存使用率、内存碎片率、淘汰key数
- 网络指标:连接数、网络流量
- 持久化指标:AOF大小、RDB执行时间
- 主从指标:主从延迟、同步状态
2. 告警配置
配置了告警:
- 内存使用率超过80%告警
- 响应时间超过5ms告警
- 主从延迟超过1秒告警
- 慢查询超过10条/分钟告警
- 连接数超过最大值的80%告警
3. 定期运维
- 每天检查慢查询
- 每周检查内存使用情况,清理无用key
- 每月做一次主从切换演练
- 定期备份,验证备份可用性
六、踩坑记录
说说升级和优化过程中踩的坑。
坑一:Lua脚本不兼容
升级到7.0后,有一个Lua脚本报错了。
原因是Redis 7.0的Lua脚本中,redis.call的返回值类型有变化。原来返回的是number,现在返回的是string(取决于命令)。
解决方法:修改Lua脚本,用tonumber()做类型转换。或者用Redis 7.0的Functions替代Lua脚本。
坑二:AOF文件变大
升级后,AOF文件突然变大了。
原因是Redis 7.0的多部分AOF,基础文件和增量文件分开了。看起来文件多了,但总大小其实差不多。而且重写更快了。
解决方法:理解新的AOF机制,不需要担心。可以用INFO persistence查看详细信息。
坑三:客户端连接被断开
升级后,偶尔有客户端连接被断开。
原因是Redis 7.0的客户端Eviction机制,默认会在内存不足时断开客户端。我们的内存配置有点紧张,高峰期触发了Eviction。
解决方法:调大maxmemory,或者配置client-eviction no关闭这个功能。我们选择了调大内存。
坑四:CONFIG命令被禁用
我们的应用用了CONFIG GET命令获取配置,升级后发现报错了。
原因是我们在配置文件里rename了CONFIG命令,但应用代码里还在用。
解决方法:修改应用代码,不用CONFIG命令。或者在测试环境用,生产环境禁用。
七、优化效果
说说最终的优化效果。
1. 性能提升
- 平均响应时间:从5ms降到1ms
- P99响应时间:从20ms降到5ms
- QPS:从5万提升到15万
- 高峰期无超时
2. 内存优化
- 内存使用率:从85%降到55%
- 内存碎片率:从1.5降到1.1
- key数量:从2000万降到1200万(清理了无用key)
3. 稳定性提升
- 慢查询:从每天几十条降到几乎没有
- 主从延迟:从偶尔1秒以上降到稳定在10ms以内
- 故障次数:从每月2-3次降到0
八、写在最后
Redis 7.0是一个值得升级的版本。新特性(Functions、多部分AOF、ACL改进)很实用,性能也有明显提升。
但升级只是第一步,真正的性能提升,来自于全面的优化:内存优化、网络优化、持久化优化、慢查询优化、业务层面的优化。
Redis是一个简单但强大的工具。用好了,它能成为你系统的性能利器;用不好,它也可能成为系统的瓶颈。
2022年了,Redis已经成为很多系统的标配。但很多人只是把它当缓存用,没有发挥它的全部能力。了解新特性,做好性能优化,能让Redis更好地为业务服务。
最后,用一句话总结:"Redis 7.0的升级,不只是版本的升级,更是性能和架构的升级。理解新特性,做好优化,才能从慢到快。"
愿大家的Redis,都能又快又稳。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录