redis集群-主从同步、哨兵模式、Cluster 集群

集群的三种模式:

 

一、主从同步/复制

 

一、Redis 复制


复制(Replication):是 Redis 实现高可用的基础。且在复制过程中,主节点/从节点都是非阻塞的,但是从节点在执行同步时使用的是旧数据集提供查询。

Redis 复制启动图与流程说明:

img

1)、当从节点连接到主节点时,会发送 psync 命令给主节点,runId 是主节点的 ID;offset 是从节点保存复制偏移量,如果没有默认是 -1,主节点根据复制偏移量仅发送从节点所需的增量部分,如果是第一次复制则为 -1; 2)、如果主节点回复 +FULLRESYNC,那么从节点将触发全量复制流程; 3)、如果主节点回复 +CONTINUE,那么从节点触发部分复制; 4)、如果主节点回复 +ERR,说名主节点不支持该命令;

二、Redis 主从全量复制


主从复制:主机数据更新后根据配置和策略,自动同步到备机的 master/slaver 机制,Master以写为主,Slave以读为主。

img

三、Redis 主从部分复制


img

四、Redis 主从搭建


【1】修改主节点 redis.conf 文件:使用[./redis-server redis.conf]启动主节点。

复制代码

 1 bind 127.0.0.1
 2 Port 7000
 3 
 4 #是否开启保护模式,默认为 yes 是开启。要是配置里没有指定 bind 和密码。开启该参数后,redis只会本地进行访问,拒绝外部访问。
 5 #要是开启了密码和 bind,可以开启。否则最好关闭,设置为no。
 6 protected-mode no 
 7 #修改 redis 安全密码
 8 requirepass "123456789"
 9 # master 设置密码
10 masterauth "123456789"
11 #开启appendonly 模式后,redis 将每一次写操作请求都追加到appendonly.aof 文件中
12 appendonly yes

复制代码

【2】新建从节点并配置复制主节点信息(配从(库)不配主(库))每次与 master 断开之后,都需要重新连接,除非你配置进 redis.conf 文件 info replication(Redis Sentinel 还使用该信息来发现 slave 实例)

1 #slaveof 主库IP 主库端口
2 slaveof 127.0.0.0 7000

【3】Redis 主/从复制注意点:1)、主/从节点应启用持久化:master 和 slave 中应启用持久化。当由于性能要求不能启用持久化时,应配置实例避免自动重启,因为主节点未持久化又重启时,内存数据为空,会导致从节点同步主节点空数据。 2)、从节点应配置只读属性:主从复制中,从节点应配置只读属性[replica-read-only yes]。 3)、从节点应配置对主节点的验证:主节点通过 requirepass 配置了密码时,从节点应使用[masterauth <password>]配置对主节点的访问密码。 4)、主节点配置写查询接收条件:为了尽量保证主从一致性,主节点应配置当至少有 N 个 slave,并且滞后小于 M 秒时,才接收客户端写入命令[min-slaves-to-write <slave 数量> min-slaves-max-lag <秒数>]

五、主从复制常用3招


✘ 一主二仆: 一个 Master 两个 Slave; ✘ 薪火相传:上一个 Slave 可以是下一个 Slave 的 Master,Slave 同样可以接收其他 Slaves 的连接和同步请求,那么该 Slave 作为了链条中下一个的 Master,可以有效减轻 Master 的写压力。中途变更转向会清除之前的数据,重新建立拷贝最新的slaveof 新主库IP 新主库端口; ✘ 反客为主:SLAVEOF NO ONE。使当前数据库停止与其他数据库的同步,转成主数据库

六、主从复制原理


【1】slave 启动成功连接到 master 后会发送一个 sync 命令。 【2】Master 接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master 将传送整个数据文件到 slave,以完成一次完全同步。 【3】全量复制:而 slave 服务在接收到数据库文件数据后,将其存盘并加载到内存中。 【4】增量复制:Master 继续将新的所有收集到的修改命令依次传给 slave,完成同步。 【5】但是只要是重新连接 master,一次完全同步(全量复制)将被自动执行。

复制的缺点:由于所有的写操作都是先在 Master 上操作,然后同步更新到 Slave 上,所以从 Master 同步到 Slave 机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave 机器数量的增加也会使这个问题更加严重。

redis有俩种复制模式:Rdb和aof

redis持久化问题;会有数据损失吗,开启aof的持久化吗;

redis提供2种持久化方案。rdb和aof

redis有自己默认的持久化方案 (Rdb 方案)

Rdb(默认):在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
AOF:append only file。以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

优缺点:

相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。

由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。

二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。不过生产环境其实更多都是二者结合使用的。

常用配置

RDB持久化配置

Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:

save 900 1              #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10            #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

AOF持久化配置

在Redis的配置文件中存在三种同步方式,它们分别是:

appendfsync always     #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec  #每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no          #从不同步。高效但是数据不会被持久化。

(1)首先从节点根据当前状态,决定如何调用psync命令:

  • 如果从节点之前未执行过slaveof或最近执行了slaveof no one,则从节点发送命令为psync ? -1,向主节点请求全量复制;
  • 如果从节点之前执行了slaveof,则发送命令为psync <runid> <offset>,其中runid为上次复制的主节点的runid,offset为上次复制截止时从节点保存的复制偏移量。

(2)主节点根据收到的psync命令,及当前服务器状态,决定执行全量复制还是部分复制:

  • 如果主节点版本低于Redis2.8,则返回-ERR回复,此时从节点重新发送sync命令执行全量复制;
  • 如果主节点版本够新,且runid与从节点发送的runid相同,且从节点发送的offset之后的数据在复制积压缓冲区中都存在,则回复+CONTINUE,表示将进行部分复制,从节点等待主节点发送其缺少的数据即可;
  • 如果主节点版本够新,但是runid与从节点发送的runid不同,或从节点发送的offset之后的数据已不在复制积压缓冲区中(在队列中被挤出了),则回复+FULLRESYNC <runid> <offset>,表示要进行全量复制,其中runid表示主节点当前的runid,offset表示主节点当前的offset,从节点保存这两个值,以备使用。

二、哨兵模式

 

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库[基于主从复制模块]。

一、Redis 哨兵概念


img

哨兵(Sentinel):是一个分布式系统,可自动干预 Redis 主从切换,主要用于管理多个 Redis 服务器,执行监控(Monitoring)、通知(Notification)、自动故障迁移(Automatic failover)任务。

二、Redis 哨兵监控


img

■ 如果 Redis 节点未在 [master-down-after-milliseconds] 指定的时间内,对向它发送 PING 命令的哨兵返回一个有效回复,该哨兵就会将这个服务器标记为下线。

■ 当某个哨兵先检测到主节点不可用时,系统并不会马上进行 failover 过程【最终只有一个 sentinel 节点作为 failover 的发起者,就需要选举一个 leader(采用类似 Raft 协议实现选举算法)】。该哨兵会通知其它哨兵,发送 [SENTINEL is-master-down-by-addr] 来询问其他哨兵是否认为主节点的服务器已下线并提议选举自己为领导者哨兵。 ■ 如果在规定的时间内接收到多个哨兵(哨兵数量大于3且为奇数)的同意时,领导者哨兵产生。

三、Redis 哨兵通知及故障转移


img

■ 领导者哨兵选出一个从节点,并将其升级为主节点。 ■ 向被选中的从节点发送 SLAVEOF NO ONE 命令,让它转变为主节点。 ■ 通过发布与订阅功能,将更新后的配置传播给所有其他 Sentinel,其他 Sentinel 对他们自己的配置进行更新。 ■ 向其他从节点发送 SLAVE OF 命令,让它们去复制新的主节点。 ■ 当所有的从节点都已经开始复制新的主节点时,领导者哨兵终止此次故障迁移操作。 ■ 每当一个 Redis 实例被重新配置(reconfigured),无论是被设置成主节点、从节点、又或者被设置成其他主节点的从节点,哨兵都会向被重新配置的实例发送一个 CONFIG REWRITE 命令,从而确保这些配置会持久化到硬盘。

四、Redis 哨兵配置


配置项参数类型作用
sentinel down-after-milliseconds<服务名称><毫秒数(整数)>指定哨兵在监控Redis服务时,当 Redis 服务在一个默认毫秒数内都无法回答时,单个哨兵认为的主管下线时间,默认为30000<30秒>
sentinel parallel-syncs<服务名称><服务器数(整数)>这个配置项指定了在发生 failover 主备切换时最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
sentinel failover-timeout<服务名称><毫秒数(整数)>指定故障切换允许的毫秒数,超过这个时间,就认为故障切换失败,默认是3分钟。
sentinel notification-script<服务名称><脚本路径>指定 sentinelnel 检测到该监控的 redis 实例指向的实例异常时,调用的报警脚本。可以通过脚本来通知管理员。一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。

五、Redis 哨兵搭建


【1】搭建 1 主 2 从共 3 个节点的 Redis 主从复制节点。

#7000 为主节点端口,7001和7002为对应从节点
7000>./redis-server redis.conf
7001>./redis-server redis.conf
7002>./redis-server redis.conf

【2】新建 3 个哨兵节点并配置哨兵 sentinel.conf 文件。新建端口为17000、17001、17002 共三个哨兵节点,启动:./redis-sentinel sentinel.conf

bind 127.0.0.1
port 17000 #其他两个分别为 7002、7003
protected-mode no  #若想从远程连接redis集群,需要将sentinel的protected-mode修改为no
sentinel myid sentinel-1  #设定sentinel myid 每个都不一样,使用yum安装的时候,直接就生成了
sentinel monitor mymaster 127.0.0.1 7000 2 #数字2,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机。
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 15000
sentinel parallel-syncs mymaster 2
sentinel auth-pass mymaster 123456789  #设置用于与主服务器和从服务器进行身份验证的密码

六、Redis 哨兵使用


【1】使用 Redis-cli 连接

$redis-cli -h 127.0.0.1 -p 7000 -a 123456789

Redis -cli 连接到主库可以执行 set 命令,连接到从库执行 set 命令会有异常提示

(error)READONLY You cant write against a read only save

【2】使用 Jedis.jar 连接 Redis 哨兵

Set<String> sentinels = new HashSet<String>(Arrays.asList(
    "127.0.0.1:17000",
    "127.0.0.1:17001",
    "127.0.0.1:17002"
));
JedisSentinelPool pool = new JedisSentinelPool("mymaster",sentinels,jedisPoolConfig,"123456789");

  Redis Sentinel是Redis高可用的实现方案。Sentinel是一个管理多个Redis实例的工具,它可以实现对Redis的监控、通知、自动故障转移。

Redis Sentinel的工作流程

由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求 。如下图:

Sentinel负责监控集群中的所有主、从Redis,当发现主故障时,Sentinel会在所有的从中选一个成为新的主。并且会把其余的从变为新主的从。同时那台有问题的旧主也会变为新主的从,也就是说当旧的主即使恢复时,并不会恢复原来的主身份,而是作为新主的一个从。

在Redis高可用架构中,Sentinel往往不是只有一个,而是有3个或者以上。目的是为了让其更加可靠,毕竟主和从切换角色这个过程还是蛮复杂的。

  • 主观失效

    SDOWN(subjectively down),直接翻译的为”主观”失效,即当前sentinel实例认为某个redis服务为”不可用”状态.

  • 客观失效

    ODOWN(objectively down),直接翻译为”客观”失效,即多个sentinel实例都认为master处于”SDOWN”状态,那么此时master将处于ODOWN,ODOWN可以简单理解为master已经被集群确定为”不可用”,将会开启failover

三、Cluster 集群

一、Redis-Cluster 简介

 


【1】Redis 集群(Redis-Cluster)提供了在多个 Redis 节点间共享数据的功能。
【2】Redis 集群通过分区来提高可用性。可自动分割数据到不同的节点上,集群的部分节点失败或者不可达时能够继续处理请求。
【3】Redis Cluster 集群模式通常具有高可用性、可扩展性、分布式等特性。
【4】Redis 集群采用 P2P 模式,是完全去中心化的,不存在中心节点或者代理节点。
【5】Redis 集群是没有统一的入口,客户端连接集群的任意节点(node)即可,集群内部的节点是相互通信的(PING-PONG机制),每个节点都是一个 Redis 实例。
【6】为了实现集群的高可用,即判断节点是否健康[能否正常使用],redis-cluster有这么一个投票容错机制:如果集群中超过半数的节点投票认为某个节点挂了,那么这个节点就挂了(fail)。这是判断节点是否挂了的方法。如果集群中任意一个节点挂了,而且该节点没有从节点(备份节点),那么这个集群就挂了。这是判断集群是否挂了的方法。
【7】那么为什么任意一个节点挂了(没有从节点)这个集群就挂了呢?  因为集群内置了16384个slot(哈希槽),并且把所有的物理节点映射到了这16384[0-16383]个slot上,或者说把这些 slot均等的分配给了各个节点。当需要在 Redis集群存放一个数据(key-value)时,redis会先对这个key进行 CRC16 算法,然后得到一个结果。再把这个结果对 16384进行求余,这个余数会对应[0-16383]其中一个槽,进而决定 key-value存储到哪个节点中。所以一旦某个节点挂了,该节点对应的 slot 就无法使用,那么就会导致集群无法正常工作。综上所述,每个 Redis集群理论上最多可以有16384个节点。

二、Redis-Cluster 查询路由方案


■  客户端随机地请求任意一个 Redis实例,然后由 Redis将请求转发给正确的 Redis节点。
■  Redis-Cluster 实现了一种混合形式的查询路由,但不是直接将请求从一个 Redis 节点转发到另一个 Redis 节点,而是在客户端帮助下直接重定向(redirected)到正确的 Redis 节点。如果访问的第一个节点就是目标节点,则直接返回结果。

三、Redis-Cluster 数据分片


1)、Redis-Cluster 没有使用一致性哈希,而是引入了哈希槽(slot)的概念。
2)、Redis-Cluster 有16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置在那个槽,集群中的每一个节点负责一部分 hash 槽。

■ 解耦数据和节点之间的关系,简化了节点扩容和收缩难度。
■ 节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区元数据。
■ 支持节点、槽、键之间的映射查询,用于数据路由、在线伸缩等场景。
■ 无论添加、删除或者改变某个节点的哈希槽数量都不会造成集群不可用的状态。

四、Redis-Cluster 一致性保存


【1】Redis-Cluster 使用了异步复制:主节点对客户端请求回复状态后,异步发起写操作给从节点,会存在一个时间间隙。
【2】Redis-Cluster 出现网络分区时,当一个客户端与至少包含一个主节点在内的少数节点被孤立,可能导致在节点超时时间(node timeout)内,另一个网络分区内的大部分节点重新选举被孤立主节点的从节点为新的主节点。节点超时时间选项为 cluster-node-timeout 15000(毫秒)

五、使用 redis-trib.rb 搭建 Redis-Cluster


Redis集群至少需要3个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以2个节点无法构成集群。 要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,所以Redis集群至少需要6台服务器。因为我没有那么多服务器,也启动不了那么多虚拟机,所在这里搭建的是伪分布式集群,即一台服务器虚拟运行6个redis实例,修改端口号为(7001-7006),当然实际生产环境的 Redis 集群搭建和这里是一样的。

【1】新建3主3从 Redis-cluster:6 个 Redis 启动目录,并新建 6 份 Redis 配置文件 redis.conf。并启动 6 个 Redis。

1 port 7000
2 cluster-enabled yes
3 cluster-config-file nodes.conf  #集群配置名
4 cluster-node-timeout 15000
5 appendonly yes  #快照压缩功能开启

【2】配置 Ruby 运行环境:安装 Ruby 及 Ruby-Redis 管理工具(redis 的版本和 ruby 包的版本最好保持一致)

1 yum install ruby rubygems -y
2 gem install redis-5.0.4.gem

【3】配置 Redis-Cluster:
   ■ 使用 redis-trib.rb 的 create 命令创建 Redis-Cluster

1 ./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 
2 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 

   ■ 根据命令提示输入选项后(输入“yes”),会创建一个新的集群。
   ■ 选项 replicas 1:表示集群中的每个主节点对应一个从节点,后三个地址为从节点。
      

六、进行 Redis 主节点扩展


【1】添加一个新主节点:添加一个空的主节点

1 port 7006
2 cluster-enabled yes
3 cluster-config-file nodes.conf  #集群配置名
4 cluster-node-timeout 15000
5 appendonly yes  #快照压缩功能开启

  将该节点添加到现有集群中,第一个参数是新节点的地址,第二个参数是任意一个已经存在的节点的IP和端口。

./redis-trib add-node 127.0.0.1:7006 127.0.0.1:7000

【2】移动 slot(槽)到该节点:只需要指定集群中其中一个节点的地址,redis-trib 就会自动找到集群中的其他节点。根据提示填写每个节点需移动的 slot 数量。

./redis-trib reshard 127.0.0.1:7000

七、进行 Redis 从节点扩展


【1】使用 redis-trib.rb 进行从节点扩展:新建一个 Redis 服务,使用如下命令使其成为指定主节点的从节点。

1 #./redis-trib.rb add-node --slave --master-id <主节点ID> <新增从节点ip:port> <原集群中任一节点ip:port>
2 redis-trib.rb add-node --slave --master-id f413fb7e6460308b17cdb71442798e1341b56cbc 127.0.0.1:6379 127.0.0.1:6384

【2】使用 [CLUSTER REPLICATE] 进行从节点扩展:使用 redis 客户端连接到从节点,使用如下命令使其成为指定主节点的从节点

redis 127.0.0.1:7006>cluster replicate <主节点 id>

八、Redis 节点移除或迁移


【1】使用 [del-node] 命令移除 redis 节点:可以直接移除从节点,但是使用该方法移除主节点时,需要确保这个主节点是空的。如果不是空的,需要将这个节点的数据重新分片到其他主节点上,否则会导致集群不可用。

./redis-trib del-node <Redis集群中的任意节点ip:port> <待移除节点id>

【2】Redis 从节点迁移:建议去从节点最多的主节点上进行从节点的迁移,从节点的迁移能够提高整个 Redis 集群的可用性。

CLUSTER REPLICATE <master-node-id>

九、Redis-Cluster 使用


【1】redis-cli 工具

1 #-c:表示连接到集群
2 $redis-cli -c -h 127.0.0.1 -p 7000
3 redis 127.0.0.1:7000>set key value
4  ->Redirected to slot[12180] located at 127.0.0.1:7003
5 OK

【2】使用 Jedis.jar 连接 Redis-Cluster

 
1 Set<HostAndPort> nodes = new LinkedHashSet<HostAndPort>();
2 nodes.add(new HostAndPort("127.0.0.1",7000));
3 nodes.add(new HostAndPort("127.0.0.1",7001));
4 nodes.add(new HostAndPort("127.0.0.1",7002));
5 nodes.add(new HostAndPort("127.0.0.1",7003));
6 nodes.add(new HostAndPort("127.0.0.1",7004));
7 nodes.add(new HostAndPort("127.0.0.1",7005));
8 
9 JedisCluster cluster = new JedisCluster(nodes,poolConfig);
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值