在分布式系统架构设计中高可用是必须考虑的因素之一。高可用通常是指,通过设计减少系统不能提供服务的时间。而单点是系统高可用的最大的败笔,如果单点出现问题的话,那么整个服务就不能使用了,所以应该尽量在系统设计的过程中避免单点。对于 redis 服务也是这样,今天我们就来实现 Redis 的高可用的基础 --> 主从配置。

主从概念

有多台 Redis 服务器(至少两台或以上),其中一台是主服务器(master) 负责写指令的操作,其他都是从服务器(slave)负责读指令的操作。

主从服务器之间会进行数据的同步(即:主服务器会将数据同步到从服务器去),保证数据是一致的。从服务器将读指令操作分流减少服务器压力,而且其中一台从服务器出现错误,不影响其他从服务器的使用。

如果是主服务器出现问题,那么就需要实现故障转移(手动/自动)将其中一台从服务器提升为主服务器,其他从服务器都从这个新的主服务器同步数据。

从上面这段话中我们可以知道 Redis 实现高可用的两个功能点:

  • 主从复制
  • 故障转移

主从复制

主从复制流程

1)从服务器连接主服务器,发送SYNC命令;

2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;

3)主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;

4)从服务器收到快照文件后丢弃所有旧数据(如果有的话),载入收到的快照;

5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;

6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;

7) 主服务器接收到的每一个写指令都向从服务器发送,从服务器接收并执行收到的写命令。

注:主从服务器刚连接的时候,会进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

主从复制实现方式

  • slaveof 命令
  • 配置文件

主从复制实践

前期准备

1)复制两份 redis-6379.conf 配置文件,分别命名为 redis-7000.confredis-7001.conf

2) 编辑 redis-7000.confredis-7001.conf 文件将端口分别修改为 7000 和7001并将日志文件格式以端口命名,以 redis-6379.conf 为例:

# 允许远程访问
## bind 127.0.0.1
protected-mode no
# 服务端口号
port 6379
# 以守护进程启动
daemonize yes
# 日志文件名称
logfile "redis-6379.log"
# 启用日志文件
syslog-enabled yes

3)分别启动 6379,7000 和 7001 Redis 服务

主从复制实践之 slaveof 命令

我们将会让 6379 成为主服务器,70007001 为从服务器。

1)进入 7000 并将其设置为 6379 的从服务器

[root@VM_0_15_centos redis4]# ./redis-cli -p 7000
127.0.0.1:7000> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:7000> exit

2)查看 6379 信息

[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 info replication

输出如下:

# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=7000,state=online,offset=210,lag=0
master_replid:9fe7d7ca84fe33cf8e916be1ee3a1b0423675ef8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210

2)查看 7000 信息

[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 info replication

输出如下:

# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:336
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:9fe7d7ca84fe33cf8e916be1ee3a1b0423675ef8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:336
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:336

可以看到 6379rolemaster 表示为主服务器,而 7000roleslave

表示为从服务器,证明我们刚刚的配置成功了。

3)我们尝试在 6379 设置一些值

[root@VM_0_15_centos redis4]# ./redis-cli -p 6379
127.0.0.1:6379> set name MarkLogZhu
OK
127.0.0.1:6379> set age 18
OK

然后进 7000 看看是不是会将数据同步过来(执行此操作前,先将两边的数据都清空)

[root@VM_0_15_centos redis4]# ./redis-cli -p 7000
127.0.0.1:7000> get name
"MarkLogZhu"
127.0.0.1:7000> get age
"18"

可以看到数据同步过来了,我们试试在 7000 上写入下数据

127.0.0.1:7000> set name1 123
(error) READONLY You can't write against a read only slave.

可以看到从服务器上不能执行写指令操作的。

  1. 启动 7001 并将其也设置为 6379的从服务器,看看是否也会同步数据过来
127.0.0.1:7001> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:7001> get name
"MarkLogZhu"
127.0.0.1:7001> get age
"18"

可以看到会将 6379 之前的数据也同步过来。

  1. 7000 上将主从绑定取消
[root@VM_0_15_centos redis4]# ./redis-cli -p 7000
127.0.0.1:7000> slaveof no one
OK

6)查看主服务器信息

[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=7001,state=online,offset=70,lag=0
master_replid:b3a6488a9667dd3f80c9549146ed012a4ec1d465
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
[root@VM_0_15_centos redis4]#

可以看到就一个从服务器,端口号为 7001,要注意的是 7000 上的数据还是存在的不会主动清空。

主从复制实践之配置文件

1)将 Redis 服务都关闭

[root@VM_0_15_centos redis4]# ps -ef |grep redis
root 4220 1 0 15:10 ? 00:00:00 ./redis-server *:6379
root 4238 1 0 15:11 ? 00:00:00 ./redis-server *:7000
root 4325 1 0 15:13 ? 00:00:00 ./redis-server *:7001
root 4830 1579 0 15:18 pts/0 00:00:00 grep --color=auto redis
[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 shutdown
[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 shutdown
[root@VM_0_15_centos redis4]# ./redis-cli -p 7001 shutdown
  1. 编辑 redis-7000.conf 增加如下内容:
slaveof 127.0.0.1 6379
  1. 编辑 redis-7001.conf 增加如下内容:
slaveof 127.0.0.1 6379
  1. 依次启动服务
[root@VM_0_15_centos redis4]# ./redis-server redis-6379.conf
[root@VM_0_15_centos redis4]# ./redis-server redis-7000.conf
[root@VM_0_15_centos redis4]# ./redis-server redis-7001.conf
  1. 查看主从状态
[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=7000,state=online,offset=84,lag=1
slave1:ip=127.0.0.1,port=7001,state=online,offset=84,lag=0
master_replid:645cc6d0869b23998c1265af1d556e671330d2f0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84

可以看到服务一启动就已经自动配置为一主二从了,在实际项目中通过配置文件的形式更常见。

主从故障

什么是主从故障

主从故障就是主服务器出现问题,导致无法执行写命令。我们来演示下主服务器故障看看

  1. 启动三个服务
[root@VM_0_15_centos redis4]# ./redis-server redis-6379.conf
[root@VM_0_15_centos redis4]# ./redis-server redis-7000.conf
[root@VM_0_15_centos redis4]# ./redis-server redis-7001.conf
  1. 将主服务器进程关闭(模拟突然出现问题)
[root@VM_0_15_centos redis4]# ps -ef |grep redis
root 5538 1 0 15:25 ? 00:00:00 ./redis-server *:6379
root 5545 1 0 15:25 ? 00:00:00 ./redis-server *:7000
root 5551 1 0 15:25 ? 00:00:00 ./redis-server *:7001
root 6179 1579 0 15:34 pts/0 00:00:00 grep --color=auto redis
[root@VM_0_15_centos redis4]# kill -9 5538

3)查看主从状态

[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:891
master_link_down_since_seconds:216
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:645cc6d0869b23998c1265af1d556e671330d2f0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:891
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:891

可以看到 Redis 是无法自动切换的,只能通过人为执行命令解除主从配置,并将其中一个从服务器提升为主服务器。除了人为来操作之外 Redis 提供了一个 sentinel(哨兵)来实现故障自动转移。

Sentinel(哨兵)

什么是 sentinel

sentinel 就相当于是一个哨兵,当 Redis 主服务器出现故障的时候,代替我们人为的将其中一个服务器提升为主服务器,当主服务器修复故障后自动降格为从服务器加入进来。

多个哨兵节点(至少三个,并且是奇数)会使用 Raft算法(选举算法)实现选举机制,选出一个哨兵节点当作领导者来完成转移和通知。

Sentinel 是如何实现故障转移的?

Sentinel 做到故障转移是基于三个定时任务的执行:

  1. 每隔 10s 每个 sentinel 会对 master 节点和 slave 节点执行 info 命令
作用就是发现 slave 节点,并且确认主从关系,因为 redis-Sentinel 节点启动的时候是知道master节点的,只是没有配置相应的 slave 节点的信息
  1. 每隔两秒,sentinel 都会通过 master节点内部的 channel 来交换信息(基于发布订阅)
作用是通过master节点的频道来交互每个Sentinel对master节点的判断信息
  1. 每隔一秒每个 sentinel 对其他的redis节点(master,slave,sentinel)执行ping操作
对于 master 来说若超过 30s 内没有回复,就对该 master进行主观下线并询问其他的 Sentinel节点是否可以客观下线

客观下线和主观下线

  • 主观下线:每个Sentinel节点对Redis节点失败的“偏见”
  • 客观下线:所有Sentinel节点对Redis节点失败达成共识

在进行领导者选举之后进行故障转移,这个过程由成为 leader 的 Sentinel 的来完成。

Sentinel 的选举流程(Raft算法)

1)每个做出主观下线操作的 Sentinel 节点向其他 Sentinel 节点发送命令,要求成为领导者。

2)收到命令的 Sentinel 节点默认同意第一个收到的请求,其他拒绝

3)当其中一个 Sentinel 节点获取到的票数一次超过 Sentinel 集合半数并且超过配置里的 quorum,那么它将成为领导者。

4)如果此过程中存在多个 Sentinel 节点成为领导者,那么将等待一段时间后重新进行选举。

故障转移

1)从 slave 节点中选出一个 “合适的” 节点作为新的 master 节点

2)对选中的 slave 节点执行 slaveof no one 命令,让其成为 master 节点

3)对剩余的 slave 节点发送命令,让他们成为新的 master 节点的slave 节点,复制规则和 parallel-syncs 参数有关。

4)将原来的 master 节点配置为 slave,并保持对其的 "关注",当它恢复后令它去复制新的 master 节点。

“合适的” slave 节点

1.选择 slave-priority(slave节点优先级)最高的 slave 节点,如果存在则返回,否则继续。

2.选择复制偏移量最大的 slave 节点(复制的最完整的),如果存在则返回,否则继续。

3.选择 runId 最小的 slave 节点。

实践

1)编辑 sentinel 配置文件

vim sentinel-26379.conf

内容如下:

# 配置 sentinel 端口号
port 26379
# 以守护进程启动
daemonize yes
# 绑定只在本地使用
bind 127.0.0.1
# 日志文件名称
logfile "sentinel_26379.log"
# 日志文件存放地址
dir "./"
# 监控 master 名字叫做 mymaster,地址是 127.0.0.1 端口号是 6379,1 表示有几个 sentinel 认为该 master 出现故障,触发主备切换动作
sentinel monitor mymaster 127.0.0.1 6379 1
# 3000 毫秒没有响应就判断出现故障
sentinel down-after-milliseconds mymaster 30000
# 主备切换时,多少个从服务器同步更新数据,数值越小越好
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
  1. 启动 sentinel
[root@VM_0_15_centos redis4]# ./redis-sentinel sentinel-26379.conf

3)将主服务器进程关闭(模拟突然出现问题)

[root@VM_0_15_centos redis4]# kill -9 9149
[root@VM_0_15_centos redis4]# ps -ef |grep redis
root 5550 1 0 16:17 ? 00:00:00 ./redis-server *:7000
root 5551 1 0 15:25 ? 00:00:03 ./redis-server *:7001
root 13044 1 0 16:14 ? 00:00:00 ./redis-sentinel 127.0.0.1:26379 [sentinel]
root 13306 1579 0 16:17 pts/0 00:00:00 grep --color=auto redis
  1. 查看 7000 主从信息
[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:7001
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:17931
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:0219097153045d031f7bcfdccebd52b336e542e5
master_replid2:66aa7374642058a6bb26c9c0258e3c8b2fc7d760
master_repl_offset:17931
second_repl_offset:12757
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:17931
[root@VM_0_15_centos redis4]#

可以看到现在主服务器是端口 7001

5)将 6379 端口服务重新启动,然后查看 7001 主从状态

[root@VM_0_15_centos redis4]# ./redis-cli -p 7001 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=7000,state=online,offset=29364,lag=1
slave1:ip=127.0.0.1,port=6379,state=online,offset=29364,lag=0
master_replid:0219097153045d031f7bcfdccebd52b336e542e5
master_replid2:66aa7374642058a6bb26c9c0258e3c8b2fc7d760
master_repl_offset:29364
second_repl_offset:12757
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset

可以看到 6379 端口也变成了一个从服务器添加进来了。要注意的是这个时候配置文件已经被 sentinel 修改了,就算你重启服务,也是按目前的主从来设置,而不是重新以 6379 为主服务器,我们可以来看看:

[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 shutdown
[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 shutdown
[root@VM_0_15_centos redis4]# ./redis-cli -p 7001 shutdown
[root@VM_0_15_centos redis4]# ./redis-server redis-6379.conf
[root@VM_0_15_centos redis4]# ./redis-server redis-7000.conf
[root@VM_0_15_centos redis4]# ./redis-server redis-7001.conf
[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:7001
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:835
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:f3ed896873d5a9024a8139dac59b86381e53ad08
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:835
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:835

重启服务后我们可以看到 6379 还是充当从服务器的角色。

Redis学习总结(四)--Redis主从配置的更多相关文章

  1. Redis集群(四):主从配置二

    一.本文目的        主要介绍redis主从模式下各种情况 二.说明 主从的基本概念:Master用于写入,Slaver用于读取,不能写入或修改,一个Master可以对应多个Slaver Mas ...

  2. redis原理及集群主从配置

    一.简介 存储系统背景 存储系统有三类: RDBMS oracle,dh2,postgresql,mysql,sql server NoSQL: KV NoSQL:redis,memcached 列式 ...

  3. redis学习教程四《管理、备份、客户端连接》

    redis学习教程四<管理.备份.客户端连接>  一:Redis服务器命令 Redis服务器命令 下表列出了与Redis服务器相关的一些基本命令. 序号 命令 说明 1 BGREWRITE ...

  4. CentOS 7 学习(四)Git配置(一)

    CentOS 7 学习(四)Git配置(一) 1.对于版本管理系统,目前常用的是Subverion和Git,Subversion是集中式版本管理系统中最好的,所有人的代码都要提交到服务器上,如果要知道 ...

  5. 分布式缓存技术redis学习(四)——redis高级应用(集群搭建、集群分区原理、集群操作)

    本文是redis学习系列的第四篇,前面我们学习了redis的数据结构和一些高级特性,点击下面链接可回看 <详细讲解redis数据结构(内存模型)以及常用命令> <redis高级应用( ...

  6. Redis学习笔记之Redis单机,伪集群,Sentinel主从复制的安装和配置

    0x00 Redis简介 Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure server). Redis的键值 ...

  7. redis学习五,redis集群搭建及添加主从节点

    redis集群 java架构师项目实战,高并发集群分布式,大数据高可用,视频教程 在redis3.0之前,出现了sentinel工具来监控各个Master的状态(可以看上一篇博客).如果Master异 ...

  8. redis 非集群的主从配置及切换

    单纯的master-slave不能称之为集群,只能叫做读写分离.此案例只针对master为单点服务,且程序端写死master为可写,slave为只读.若master宕机则不可用,若主从未开启持久化,不 ...

  9. 【Redis学习专题】- Redis主从+哨兵集群部署

    集群版本: redis-4.0.14 集群节点: 节点角色 IP redis-master 10.100.8.21 redis-slave1 10.100.8.22 redis-slave2 10.1 ...

随机推荐

  1. 用tcp协议实现一个并发的socketserver 进行密文登录

    先在客户端进行摘要,客户端把用户名作为盐. 然后在服务端进行二次摘要,用固定的盐(不能让别人知道你的盐是什么),然后存到文件中,密文存储.或者和文件中的密文对比. 这样即使在网络上用户信息被截获,和存 ...

  2. CIDR的介绍

    CIDR的介绍: CIDR(Classless Inter-Domain Routing,无类域间路由选择)它消除了传统的A类.B类和C类地址以及划分子网的概念,因而可以更加有效地分配IPv4的地址空 ...

  3. linux初学者-磁盘拉伸缩减篇

    linux初学者-磁盘拉伸缩减篇 在系统的使用过程中,往往会出现这样的问题,由于刚开始无法估计需要的磁盘空间,导致后期磁盘空间不够,使得数据没地方存储,又或者后期磁盘空间过大,造成资源的浪费.这种在使 ...

  4. 从零开发一款自己的小程序UI组件库(一)

    写在前面:有开发过小程序的朋友肯定知道组件化开发的特性,高内聚与低耦合.使用已有的UI组件库,诸如:vantUI-weapp.minUI-weapp等UI组件库的诞生使我们的开发速度大大的加快,丰富的 ...

  5. rabbitMQ_integeration_spring(七)

    参考了其他博主的资料,整理成完整的代码,直接拷贝就可以测试. 一.创建一个properties文件 mq.host=127.0.0.1 mq.username=root mq.password=roo ...

  6. 【Android】Fresco 初次使用遇到的坑

    初次使用开源框架 Fresco,结果遇到了坑,被虐了半下午--暂且记下. 下面的错误 android.view.InflateException: Binary XML file line #** 报 ...

  7. Mac Android 配置环境变量

    进入终端,输入以下命令: cd ~ touch .bash_profile //没有该文件的话新建一个 vi .bash_profile //vim 形式打开 输入内容jdk变量配置内容: expor ...

  8. 使用request获取访问者的真实IP

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...

  9. 异步编程CompletableFuture实现高并发系统优化之请求合并

    先说场景: 根据Redis官网介绍,单机版Redis的读写性能是12万/秒,批量处理可以达到70万/秒.不管是缓存或者是数据库,都有批量处理的功能.当我们的系统达到瓶颈的时候,我们考虑充分的压榨缓存和 ...

  10. linux集群实施与部署-----Nginx

    ( 1 ) 配置基本环境 //安装虚拟工具 #cd /media/VMware\ Tools/ #cp VMwareTools--.tar.gz/tmp/ #cd /tmp/ #tar-xvzf VM ...