redis集群、慢查询及内存优化

# 简介

作为缓存数据库,肯定要考虑缓存服务稳定性相关的保障机制。

持久化机制就是一种保障方式。持久化机制保证了 Redis 服务器重启的情况下也不会损失(或少量损失)数据,因为持久化会把内存中数据保存到硬盘上,重启会从硬盘上加载数据。

随着 Redis 使用场景越来越多,技术发展越来越完善,在 Redis 整体服务上的容错、扩容、稳定各个方面都需要不断优化。 因此在 Redis 的集群模式上也有不同的搭建方式来应对各种需求

总结来说,Redis 集群模式有三种

  • 主从模式
  • 哨兵模式
  • Cluster 集群模式

集群最大节点个数是16384 个

# 架构模式分类:有1+3种

  1. Redis 单节点单机器部署
  2. Redis 主从节点部署
  3. Redis Sentinel(哨兵)模式部署
  4. Redis 集群模式

# 主从(replication )模式

为了 Redis 服务避免单点故障,通常的做法是将 Redis 数据复制多个副本以部署在不同的服务器上。这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务。为此,Redis 提供了复制( replication )功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。

Redis 服务器分为两类:一类是主数据库(Master),另一类是从数据库(Slave)

主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。

从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。

如图所示: 优点

  1. 一个主,可以有多个从,并以非阻塞的方式完成数据同步

  2. 从服务器提供读服务,分散主服务的压力,实现读写分离;

  3. 从服务器之前可以彼此连接和同步请求,减少主服务同步压力。

缺点

  1. 不具备容错和恢复功能,主服务存在单点风险;

  2. Redis 的主从复制采用全量复制,需要服务器有足够的空余内存;

  3. 主从模式较难支持在线扩容。

# 哨兵(Sentinel)模式

Redis 提供的 sentinel(哨兵)机制,通过 sentinel 模式启动redis后,自动监控 Master/Slave 的运行状态,基本原理是:心跳机制 + 投票裁决。哨兵模式本身是基于主从为基础,所以写并发比较多的情况下,主压力肯定是有的

简单来说,哨兵的作用就是监控 Redis 系统的运行状况。它的功能包括以下两个:

  1. 监控主数据库和从数据库是否正常运行;
  2. 主数据库出现故障时自动将从数据库转换为主数据库。

哨兵模式主要有下面几个内容:

  • 监控( Monitoring ):Sentinel 会定期检查主从服务器是否处于正常工作状态。

  • 提醒( Notification ):当被监控的某个 Redis 服务器出现异常时,Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

  • 自动故障迁移(Automatic failover):当一个主服务器不能正常工作时,Sentinel 会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时,集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

Redis Sentinel 是一个分布式系统,你可以在一个架构中运行多个 Sentinel 进程( progress )。

如图所示:

优点

  1. 哨兵模式主从可以切换,具备基本的故障转移能力;保证高可用; 监控各个节点; 自动故障迁移;
  2. 哨兵模式具备主从模式的所有优点。

缺点

​ 1: 哨兵模式也很难支持在线扩容操作;

​ 2: 集群的配置信息管理比较复杂

主从模式,切换需要时间丢数据,没有解决 master 写的压力

# Cluster集群模式

Redis Cluster 是一种服务器 Sharding 技术,3.0 版本开始正式提供采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接

如图所示: Cluster 集群结构特点:

  1. Redis Cluster 所有的物理节点都映射到 [ 0-16383 ] slot 上(不一定均匀分布),Cluster 负责维护节点、桶、值之间的关系;
  2. 在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384 的值,从之前划分的 16384 个桶中选择一个;
  3. 所有的 Redis 节点彼此互联(PING-PONG 机制)内部使用二进制协议优化传输效率
  4. 超过半数的节点检测到某个节点失效时则判定该节点失效;
  5. 使用端与 Redis 节点链接,不需要中间 proxy 层,直接可以操作,使用端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

优点

  1. 无中心架构,节点间数据共享,可动态调整数据分布;
  2. 节点可动态添加删除,扩展性比较灵活;
  3. 部分节点异常,不影响整体集群的可用性。

缺点

  1. 集群实现比较复杂;
  2. 批量操作指令( mget、mset 等)支持有限;
  3. 事务操作支持有限。

# 主从模型详解

Redis 中的主从复制,也就是 Master-Slave 模型,多个 Redis 实例间的数据同步以及 Redis 集群中数据同步会使用主从复制。 主从复制主要是数据同步, 数据同步分为全量同步增量同步全量同步: 全量同步一般发生在 Slave 机器初始化阶段, 这时候 Slave 需要将 Master 上的所有数据都进行同步复制。

大概步骤如下所示:

  1. 从服务器发送 SYNC 命令,链接主服务器
  2. 主服务器收到 SYNC 命令后,进行存盘的操作,并继续收集后续的写命令,存储缓冲区
  3. 存盘结束后,将对应的数据文件发送到 Slave 中,完成一次全量同步
  4. 主服务数据发送完毕后,将进行增量的缓冲区数据同步
  5. Slave 加载数据文件和缓冲区数据,开始接受命令请求,提供操作

增量更新:

Slave 节点初始化完成之后,开始正常工作,Master 节点进行的写操作都会同步到 Slave 节点上面。Master 节点每执行一个写命令都会向从服务器发送相同的写命令,从服务器接收到命令,并执行。

# 模式比较

# Redis 的主从复制模式优缺点

  • **优点:**可靠性相对于单个节点部署模式有所提高,实现读写分离提高读写效率
  • **缺点:**写数据依赖于主节点,主节点空间有限,而且主节点存在单点的风险

# Redis sentinel(哨兵)模式优缺点

  • **优点:**保证高可用,各个节点自动故障转移
  • **缺点:**主从模式,依旧存在主节点单点风险,主从切换有丢失数据的问题

# 集群的实现方案

1. Redis Cluster 集群方案(服务端 Sharding 技术) Redis Cluster 是 3.0 版本开始正式提供的服务器 Sharding 技术。引入 slot(槽)的概念,整个集群共有 16384 个槽。根据 key 进行散列(CRC16 后 16384 取模),分配到其中一个槽当中。 2. Redis Sharding 集群(客户端 Sharding 技术) Redis Sharding 出现先与 Redis Cluster 方案,他是多 Redis 实例集群方案。 客户端 Sharding 方式,该向哪个 Redis 节点操作数据,由客户端来进行控制。服务端 Redis 还是一个个相对独立的 Redis 实例节点,没有做任何变动。节点选择可采用的方法:一致性 hash 算法或者虚拟节点算法 3. Twemproxy 中间件实现 Twemproxy 就是一种中间件 Sharding 分片的技术,处于客户端和服务器的中间,将客户端发来的请求,进行一定的处理后(如 Sharding),再转发给后端真正的 Redis 服务器。 也就是说,客户端不直接访问 Redis 服务器,而是通过 Twemproxy 代理中间件间接访问

4. Codis 中间件实现 目前用的最多的集群方案, 基本和 twemproxy 一致的效果, 但它支持在 节点数量改变情况下, 旧节点数据可恢复到新 hash 节点

# Redis分区

分区可以让 Redis 管理更大的内存, Redis 将可以使用所有机器的内存。如果没有分区, 你最多只能使用一台机器的内存。分区使 Redis 的计算能力通过简单地增加计算机得到成倍提升,Redis 的网络带宽也会随着计算机和网卡的增加而成倍增长

# 缺点

涉及多个 key 的操作通常不会被支持。例如你不能对两个集合求交集, 因为他们可能被存储到不同的 Redis 实例(实际上这种情况也有办法, 但是不能直接使用交集指令)。

同时操作多个 key,则不能使用 Redis 事务.分区使用的粒度是key,不能使用一个非常长的排序key存储一个数据集;

当使用分区的时候, 数据处理会非常复杂。 例如为了备份你必须从不同的 Redis 实例和主机同时收集 RDB / AOF 文件。

**分区时动态扩容或缩容可能非常复杂。**Redis 集群在运行时增加或者删除 Redis 节点, 能做到最大程度对用户透明地数据再平衡,但其他一些客户端分区或者代理分区方法则不支持这种特性。然而, 有一种预分片的技术也可以较好的解决这个问题


# 慢查询

# Redis 慢查询及配置

所谓慢查询就是指,系统执行命令之后,计算统计每条指令执行的时间,如果执行时间超过设置的阈值,就说明该命令为慢指令。

Redis 慢查询配置参数为:

  1. **slowlog-log-slower-than:**设置慢查询定义阈值,超过这个阈值就是慢查询。单位为微秒,默认为 10000
  2. slowlog-max-len:慢查询的日志列表的最大长度,当慢查询日志列表处于最大长度的时候,最早插入的一个命令将从列表中移除。

# 慢查询修复经验

  1. 将一些效率比较低或者算法复杂度比较高的命令,禁用或者替换为效率较高的指令。 例如禁用:sort、keys 命令
  2. 拆分大对象数据,防止一次命令操作过多的数据

# Redis优化

# 优化 Redis 服务的性能

  1. Master 节点禁止持久化工作
  2. 持久化策略要有正确的选择,关键数据可以采用 slave 节点 AOF 备份
  3. 主从节点部署在同一个局域网内,保证复制速度与稳定性
  4. 设置或者增加从库需要考虑主库现有的压力
  5. 主从复制一定要单向结构,避免使用图状结构

# 内存消耗分类及内存统计命令

Redis的内存消耗分为:

  1. **对象内存:**这是占用最大的一块,存储用户的所有数据。可以理解为:所有 key 的大小 + 所有 value 的大小
  2. **缓冲内存:**客户端缓冲、复制积压缓冲、AOF 缓冲
  3. **内存碎片:**更新操作、过期数据都可能造成内存碎片

# 内存管理方式

Redis 内存管理方式主要方向上有两个:

  1. 控制内存上限; Maxmemory 参数可以限制最大可用内存
  2. 优化回收策略,进行内存回收

# Redis 报内存不足怎么处理

  1. 修改配置文件,增加 Redis 的内存空间 maxmemory
  2. 设置缓存淘汰策略, 具体的淘汰策略;
  3. 使用 Redis 集群模式来存储

# 内存优化

  • Redis 的所有数据都进行 redisObject 来封装
  • 缩减键、值对象的长度,简化键名,提高内存使用效率
  • 尽量使用 hash 数据结构,减少 key 的数量
  • 共享对象池,并设置空间极限值

# 几个可能导致 Redis 阻塞的原因

内部原因:

  1. Redis 的 API 或者指令数据结构使用不合理
  2. Redis 主机 CPU 负载过高,导致系统崩溃
  3. 持久化工作资源占用过多

外部原因:

  1. CPU 竞争
  2. 内存交换
  3. 网络问题

# 怎么去发现 Redis 阻塞异常情况

1. 通过应用服务监控发现

当 Redis 阻塞的时候,线上应用服务应该会感知发现。比如说发现 Redis 链接超时等。这种就需要应用服务增加对于异常的统计,并针对 Redis 相关的异常,进行报警。

2. 通过 Redis 自身监控系统

借助 Redis 监控系统发现阻塞问题,当监控系统发现各个监控指标存在异常的时候,发送报警。 指标有:CPU/内存/磁盘等, 慢查询,命令耗时增加等。


# 问题

# Redis 集群会有写操作丢失吗?为什么?

Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作

# 什么是 bigkey? 有什么影响?

bigkey 是指存储 value 占用内存空间非常大的 key。例如一个 String 类型的 value 占用了 100MB 空间。

redis-cli-bigkeys 命令可以统计 bigkey 的分布

生产环境下执行 debug object key 查看 serializedlength 属性,表示 key 对应的 value 序列化之后的字节数

bigkey 的影响主要体现在:

  1. **造成内存空间不平衡:**如果 bigkey 存储量比较大,同一个 key 在同一个节点或者服务器中存储,造成一定的影响
  2. **超时阻塞:**由于占用空间比较大,那么操作起来效率肯定比较低,也就表示出现阻塞可能性增加
  3. **网络阻塞:**获取 bigkey 的时候,自然传输的数据量比较大,导致宽带的压力。

# 为什么Redis集群有16384个槽?

(1)如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。

如上所述,在消息头中,最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是: 65536÷8÷1024=8kb 因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。

(2)redis的集群主节点数量基本不可能超过1000个

如上所述,集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。

(3)槽位越小,节点少的情况下,压缩比高

Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。

上次更新: 2022/04/15, 05:41:32
×