黑马程序员Redis教程学习笔记(第7部分):Redis集群优化与原理篇入门
课程概述
本篇笔记涵盖黑马程序员Redis教程中关于Redis集群优化和原理篇入门的重要内容,主要包括Redis内存划分、集群优化策略以及Redis底层数据结构等内容。
1. Redis内存划分与配置
内存划分概述
Redis内存主要分为三大类:
- 数据内存:Redis最主要的部分,用于存储键值信息
- 常见问题是Big Key问题
- 由业务设计不当导致,需合理选择数据结构
- 内存碎片:内存分配过程中产生
- Redis底层采用jemalloc内存分配策略
- 提前预定义多个不同内存大小区间(如8,16,32,48字节等)
- 当申请内存时,按最接近的区间分配,多余部分成为碎片
- 进程内存:Redis主进程运行时需要分配的内存
- 包括运行代码、变量等
- 大小相对固定,一般为几MB
- 缓冲区内存:包括客户端缓冲区、AOF缓冲区和复制缓冲区等
- 受客户端操作影响
- 波动较大
内存监控命令
INFO Memory命令
INFO Memory查看Redis服务端内存相关信息,包括不同模块的内存占用情况。
MEMORY命令
MEMORY USAGE key_name # 查看特定Key内存占用
MEMORY STATS # 查看内存统计信息
MEMORY DOCTOR # 内存诊断内存碎片优化
内存碎片可以通过以下方式解决: - 定期重启Redis服务(碎片会被回收) - 分批重启避免服务中断 - 确保Redis可用性的情况下进行重启
2. 缓冲区优化
复制缓冲区
- 作用:在主从复制时,记录增量复制的数据
- 配置:通过
repl-backlog-size设置,默认1MB - 问题:如果设置过小,可能导致频繁全量复制
AOF缓冲区
- 作用:AOF持久化时的缓冲区域
- 特点:没有固定上限
- 影响:AOF重写时会占用大量CPU和磁盘IO
客户端缓冲区
客户端缓冲区分为输入缓冲区和输出缓冲区:
- 输入缓冲区:
- 最大值1GB,固定不可配置
- 存储客户端发送的命令
- 当Redis主线程阻塞时,可能导致输入缓冲区积压
- 输出缓冲区:
- 可以配置大小限制
- 存储Redis处理结果,准备返回给客户端
输出缓冲区限制配置
# 配置格式
client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
# 示例配置
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60参数说明: - <class>:客户端类型(normal/slave/pubsub) - <hard limit>:硬限制,超出立即断开连接 - <soft limit>:软限制,配合soft seconds使用 - <soft seconds>:达到软限制后持续时间
3. 集群模式下的批处理优化
集群批处理问题
在集群模式下,MSET、Pipeline等批处理命令要求多个Key必须落在同一个槽中,否则会导致执行失败。
解决方案
1. 串行命令
逐个执行命令,性能最差,但实现简单。
2. 串行Slot
- 计算每个Key的槽值
- 将槽值相同的命令归为一组
- 逐组执行批处理
- 减少了网络往返次数,但仍是串行执行
3. 并行Slot
- 同样按槽值分组
- 但使用多线程并行执行各组命令
- 性能优于串行Slot,但需注意线程安全
4. Hash Tag
- 在Key中使用大括号{}包含相同内容
- 确保相关Key落在同一槽中
- 可直接使用MSET或Pipeline
- 性能最佳,但可能导致数据倾斜
Spring Boot中的自动优化
Spring Boot的RedisTemplate会自动处理集群下的批处理: - 自动计算Key的槽值 - 按槽值分组 - 使用异步方式执行各组命令 - 实现了并行Slot方案
4. 集群最佳实践
集群完整性问题
- 问题:默认
cluster-require-full-coverage yes,任意槽不可用时整个集群不可用 - 解决方案:设置为
no,允许部分槽不可用时集群继续工作
带宽问题
- 问题:集群节点间通过ping交换信息,节点越多信息量越大
- 解决方案:
- 避免大集群,节点数控制在1000以内
- 单机节点数适中,避免过多
- 合理配置
cluster-node-timeout参数
其他集群问题
- 数据倾斜:使用相同Hash Tag或Big Key导致
- 客户端性能:需要处理节点选择、读写分离等
- 兼容性问题:MSET、Pipeline等命令受限制
- LOA和事务:跨槽时无法执行
集群使用建议
在满足业务需求情况下,能不用集群就不用集群: - 单体Redis可达到万级QPS - 主从模式也能提供高可用性 - 集群复杂度高,维护成本大 - 仅在确实需要分片时使用集群
5. Redis底层数据结构原理
动态字符串(SDS)
Redis中的字符串并非C语言的字符串,而是自定义的SDS(Simple Dynamic String)结构: - 包含长度信息,获取长度O(1)时间复杂度 - 预分配冗余空间,避免频繁内存重分配 - 惰性释放,减少内存重分配次数
IntSet(整数集合)
- 当集合中元素都是整数且数量较少时使用
- 底层采用数组存储,内存紧凑
- 有类型升级机制,根据数据范围选择合适的存储类型
Dict(字典)
- Redis中存储键值对的数据结构
- 采用哈希表实现
- 支持渐进式rehash,避免一次性rehash造成的阻塞
ZipList(压缩列表)
- 为节约内存而设计的数据结构
- 连续内存存储,无额外指针开销
- 适合存储小数据量的列表或哈希
QuickList(快速列表)
- 结合ZipList和链表的优点
- 用双向链表组织多个ZipList
- 既节约内存又保证操作效率
SkipList(跳跃表)
- 用于实现有序集合(ZSet)
- 时间复杂度O(logN),空间换时间
- 实现简单,支持范围查询
6. RedisObject
Redis中所有值都用RedisObject包装: - 包含类型信息 - 支持对象共享和引用计数 - 实现了内存回收机制
总结
Redis的优化不仅涉及配置层面,还包括数据结构选择、集群架构设计等方面。在实际应用中,应根据业务特点选择合适的优化策略:
- 合理设计Key,避免Big Key
- 选择合适的数据结构
- 在集群和主从之间做出合适选择
- 优化内存使用和缓冲区配置
- 理解底层数据结构,有助于更好使用Redis
掌握这些优化策略和底层原理,能够帮助我们在实际项目中更好地使用Redis,充分发挥其性能优势。