Redis集群
Redis集群
主从复制
哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性 Redis主从复制原理
-
主从复制,是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称为 主节点(master),后者称为 从节点(slave)。且数据的复制是 单向 的,只能由主节点到从节点。Redis 主从复制支持 主从同步 和 从从同步 两种,后者是 Redis 后续版本新增的功能,以减轻主节点的同步负担。
-
主从复制的主要作用:
- 数据冗余: 主从复制实现了数据的热备份。
- 故障恢复: 当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复 。
- 读写分离: 在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务 (即写 Redis 数据时应用连接主节点,读 Redis 数据时应用连接从节点),分担服务器负载。尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高 Redis 服务器的并发量。
- 高可用基石: 除了上述作用以外,主从复制还是哨兵和集群能够实施的 基础,因此说主从复制是 Redis 高可用的基础。
-
实现原理:准备阶段-数据同步阶段-命令传播阶段。
-
Redis的主从复制有一主多从、主从链两种配置方式,配置了主从复制可以实现数据的热备份、避免单点故障、读写分析提高并发量,是哨兵和集群机制的基础。
Redis的主从复制大体可以分为建立连接、数据同步、命令传播三个阶段。建立连接阶段的话首先是从服务器slave发出slaveof命令,与主服务器master建立TCP连接。建立连接后slave还会发送ping命令来确认主服务器是否可用,如果主服务器回复pong则说明是可用的。另外如果设置了requirepass选项的话,从服务器还需要配置masterauth选项且保证密码一致才能通过验证。
接下来是数据同步阶段,如果是当前slave是第一次执行复制的话,会使用完整重同步。从服务器会发送
psync ?-1
同步命令,如果master返回+fullresync <runid> <offset>
表示将与slave进行完整重同步。此时master会把该客户端添加进slave列表,并启动一个子进程来执行bgsave命令来生成RDB文件并向所有从服务器发送RDB快照文件,此外还会使用缓冲区记录执行命令和发送快照期间所有的写命令。从服务器加载完RDB后,master会给从服务器发送缓存区保存的写命令进行执行。如果是断线后重连的场景,则会使用部分重同步。这时候salve发送的同步命令就会带上服务器的runid和复制偏移量offerset,master如果回复 +continue则表示将与slave执行部分重同步。然后master会根据复制偏移量发送复制积压缓冲区中的数据给slave执行。但是如果master的复制积压缓存区没有足够的命令记录,或者slave传的
runid
不对,还是会进行完整重同步,即slave会获得一个完整的数据集副本。最后是命令传播阶段,即每执行一个写命令就会向从服务器发送同样的写命令,目的是为了保证主从服务器的数据一致性。
另外主从复制一定要开启持久化,不然如果master宕机并重启的话,就会造成主从服务器数据的丢失。此外异步复制和主备切换造成的脑裂也会导致数据丢失,这时候可以配置从服务器的最少数量和从服务器的最大延迟两个参数来防止主服务器在不安全的情况下执行写命令。
-
宕机了怎么办
-
只配置了主从没有配置集群模式的情况下。假设,我们有一个社交网站,需要使用Redis存储图片资源,存储的格式为键值对,key值为图片名称,value为该图片所在文件服务器的路径,我们需要根据文件名查找该文件所在文件服务器上的路径,数据量大概有2000W左右,按照我们约定的规则进行分库,规则就是随机分配,我们可以部署8台缓存服务器,每台服务器大概含有500W条数据,并且进行主从复制,示意图如下:
简单的使用hash不能满足动态增删服务器数量,绝大多数数据都要重新存储。使用要使用一致性hash算法:
单个节点的缓存容量达到上限,无法继续单点增加内存,如何解决?单个节点支撑的QPS(每秒查询率)达到上限,如何解决?
增删机器时,希望大部分key依旧在原有的缓存服务器上保持不变。
举例来说:key1,key2,key3原先再Cache1机器上,现在增加一台缓存服务器,希望key1,key2,key3依旧在Cache1机器上,而不是在Cache2机器上。
- 一致性Hash算法是对2^32取模,形成一个环状的hash空间
- 然后将各个服务器进行hash操作,key可以选择服务器的IP或者主机名等,确定服务器在环状hash空间的位置
- 存入数据的时候,先根据key计算出hash值,确定在环上的位置。然后将其保存到沿顺时针方向遇到的第一台服务器上
- 假设有服务器宕机,受影响的数据会放到该服务器的前一台中。并不会影响其他服务器。新增服务器也是一样,只需要重定位环空间的一小部分数据即可。
-
一致性Hash算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。
- 数据倾斜问题:服务节点太少时,容易因为节点分部不均匀而造成 对象大部分集中缓存在某一台服务器上
- 为了解决这种数据倾斜问题,一致性Hash算法引入了虚拟节点机制,即对每一个服务器计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以在服务器IP或主机名的后面增加编号来实现。
哨兵模式
- 哨兵节点: 哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的 Redis 节点,不存储数据;他可以监控redis的主从节点是否工作正常,如果有redis实例发生故障,那么哨兵会发送警报给管理员。另外如果master主节点挂了,哨兵节点会执行主节点故障转移到从节点,并且通知客户端新的master地址。
- 集群监控,负责监控redis master和slave进程是否正常工作
- 消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
- 故障转移,如果master node挂掉了,会自动转移到slave node上
- 配置中心,如果故障转移发生了,通知client客户端新的master地址
- 数据节点: 主节点和从节点都是数据节点;
新的主服务器是怎样被挑选出来的
-
领头的哨兵节点会把失效主服务的所有服务器保存在一个列表中,在挑选新的主服务器的时候。它会删除列表中所有处于下线或者断线状态的服务器,然后删除列表中最近 5s 内没有回复过PING命令的从服务器,最后删除所有与失效主服务器连接断开的时长超过 down-after选项(指定了判断主服务器下线所需的时间)指定时长十倍的服务器。 最后选出复制偏移量最大的从服务器作为新的主服务器,如果复制偏移量不可用就选运行id最新的从服务器。
-
在失效主服务器的从服务器当中, 那些被标记为主观下线、已断线、或者最后一次回复 PING 命令的时间大于五秒钟的从服务器都会被 淘汰。
-
在失效主服务器的从服务器当中, 那些与失效主服务器连接断开的时长超过 down-after 选项指定的时长十倍的从服务器都会被 淘汰。
- 在 经历了以上两轮淘汰之后 剩下来的从服务器中, 我们选出 复制偏移量(衡量数据不一致的情况)最大 的那个 从服务器 作为新的主服务器;如果复制偏移量不可用,或者从服务器的复制偏移量相同,那么 带有最小运行 ID 的那个从服务器成为新的主服务器。
为什么要三个哨兵实例
- 因为有一个majority规定了授权进行主从切换的最少的哨兵数量。只部署了2个哨兵实例的majority是2,如果其中一个哨兵宕机了,就无法满足majority>=2这个条件,那么在master发生故障的时候也就无法进行主从切换。
集群模式
集群的主要作用
- 数据分区: 数据分区 (或称数据分片) 是集群最核心的功能。着眼于扩展性,在单个 redis 内存不足时,使用 Cluster 进行分片存储,解决了 Redis 单机内存大小的限制;
- cluster可以说是sentinel和主从模式的结合体,通过cluster可以实现主从和master重选功能,所以如果配置两个副本三个分片的话,就需要六个Redis实例。因为Redis的数据是根据一定规则分配到cluster的不同机器的,当数据量过大时,可以新增机器进行扩容。
-
cluster集群特点:
- 多个redis节点网络互联,数据共享
- 所有的节点都是一主一从(也可以是一主多从),其中从不提供服务,仅作为备用
- 支持在线增加、删除节点
- 客户端可以连接任何一个主节点进行读写
集群模式节点挂了怎么办
redis集群是有很多个redis一起工作,那么就需要这个集群不是那么容易挂掉,所以呢,理论上就应该给集群中的每个节点至少一个备用的redis服务。这个备用的redis称为从节点(slave)。
集群是如何判断是否有某个节点挂掉
首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。
集群进入fail状态的必要条件
- 某个主节点和所有从节点全部挂掉,我们集群就进入faill状态。
- 如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态.
- 如果集群任意master挂掉,且当前master没有slave.集群进入fail状态
redis的投票机制
- 投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超时(cluster-node-timeout),认为当前master节点挂掉。选举过程的话失效主服务的所有从服务器保存在一个列表中,在挑选新的主服务器的时候。它会删除列表中所有处于下线或者断线状态的服务器,然后删除列表中最近 5s 内没有回复过PING命令的从服务器,最后删除所有与失效主服务器连接断开的时长超过 down-after选项(指定了判断主服务器下线所需的时间)指定时长十倍的服务器。 最后选出复制偏移量最大的从服务器作为新的主服务器,如果复制偏移量不可用就选运行id最新的从服务器。
- 脑裂:最后当旧主重新连接后将其变为新主的从服务器。注意如果客户端与旧主服务器分隔在一起,写入的数据在恢复后由于旧主会复制新主的数据会造成数据丢失。
集群中的主从复制
- 集群中的每个节点都有1个至N个复制品,其中一个为主节点,其余的为从节点,如果主节点下线了,集群就会把这个主节点的一个从节点设置为新的主节点继续工作,这样集群就不会因为一个主节点的下线而无法正常工作。注意:
- 如果某一个主节点和他所有的从节点都下线的话,redis集群就会停止工作了。redis集群不保证数据的强一致性,在特定的情况下,redis集群会丢失已经被执行过的写命令。
- 使用异步复制(asynchronous replication)是redis 集群可能会丢失写命令的其中一个原因,有时候由于网络原因,如果网络断开时间太长,redis集群就会启用新的主节点,之前发给主节点的数据就会丢失。
Redis 集群使用过吗?原理?/分区
- Redis 集群中内置了
16384
个哈希槽。当客户端连接到 Redis 集群之后,会同时得到一份关于这个 集群的配置信息,当客户端具体对某一个key
值进行操作时,会计算出它的一个 Hash 值,然后把结果对16384
求余数,这样每个key
都会对应一个编号在0-16383
之间的哈希槽,Redis 会根据节点数量 大致均等 的将哈希槽映射到不同的节点。 - 再结合集群的配置信息就能够知道这个
key
值应该存储在哪一个具体的 Redis 节点中,如果不属于自己管,那么就会使用一个特殊的MOVED
命令来进行一个跳转,告诉客户端去连接这个节点以获取数据: - 在 redis-cluster 架构中,redis-master节点一般用于接收读写,而redis-slave节点则一般只用于备份, 其与对应的 master 拥有相同的 slot 集合,若某个 redis-master 意外失效,则再将其对应的 slave 进行升级为临时 redis-master。
在Redis 集群模式Cluster中,Redis采用的是分片Sharding的方式,也就是将数据采用一定的分区策略,分发到相应的集群节点中。但是我们使用上述HASH算法进行缓存时,会出现一些缺陷,主要体现在服务器数量变动的时候,所有缓存的位置都要发生改变!具体来讲就是说第一,当缓存服务器数量发生变化时,会引起缓存的雪崩,可能会引起整体系统压力过大而崩溃(大量缓存同一时间失效)。第二当缓存服务器数量发生变化时,几乎所有缓存的位置都会发生改变。
节点之间的通信机制了解吗?
- 在 集群 中,没有数据节点与非数据节点之分:所有的节点都存储数据,也都参与集群状态的维护。为此,集群中的每个节点,都提供了两个 TCP 端口:
- 普通端口: 普通端口主要用于为客户端提供服务;但在节点间数据迁移时也会使用。
- 集群端口: 集群端口只用于节点之间的通信,如搭建集群、增减节点、故障转移等操作时节点间的通信;为了保证集群可以正常工作,在配置防火墙时,要同时开启普通端口和集群端口。
- 采用Gossip 协议进行通信,每个节点都 “随机” 地与部分节点通信,最终所有节点的状态很快会达到一致。这种方式的 负载 (比广播)低、去中心化、容错性高 (因为通信有冗余)等;不过集群的收敛速度会有点慢。
- 通信的消息类型:集群中的节点采用 固定频率(每秒10次) 的 定时任务 进行通信相关的工作:判断是否需要发送消息及消息类型、确定接收节点、发送消息等。节点间发送的消息主要分为
5
种:meet 消息
、ping 消息
、pong 消息
、fail 消息
、publish 消息
。
Redis 集群方案什么情况下会导致整个集群不可用?
- 有 A,B,C 三个节点的集群,在没有复制模型的情况下,如果节点 B 失败了,那么整个集群就会以为缺少 5501-11000 这个范围的槽而不可用。
生产环境中的redis是怎么部署的
- 采用了redis 集群的部署方式,10台机器,5台机器部署了redis主节点,另外5台机器部署了redis的从节点。每个主节点挂了一个从节点,5个节点对外提供读写服务,每个节点的读写高峰QPS可能可以达到每秒5万,5台机器最多是25万个QPS。
- 32G内存+8核CPU+1T磁盘,但是分配给redis进程的是10g内存,一般线上生产环境,redis的内存尽量不要超过10g,超过10g可能会有问题。5台机器对外提供读写,一共有50g内存。因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移,redis从实例会自动变成主实例继续提供读写服务。
- redis主要放的是商品数据,每条数据是10kb。100条数据是1mb,10万条数据是1g。常驻内存的是200万条商品数据,占用内存是20g,仅仅不到总内存的50%。目前高峰期每秒就是3500左右的请求量。
Redis主备切换的数据丢失问题:异步复制、集群脑裂
- 异步复制导致的数据丢失:因为master -> slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了,此时这些部分数据就丢失了。
-
脑裂:主备切换后,某个slave被切换成了master,但是有些client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据。导致数据丢失。
-
解决异步复制和脑裂导致数据丢失:
- 配置从节点数据复制和同步的延迟不能超过10秒
min-slaves-to-write 1 min-slaves-max-lag 10
既已览卷至此,何不品评一二: