Redis 主从复制原来这么简单
- 2020 年 3 月 4 日
- 筆記
什么是redis主从复制
众所周知redis之所以火因为它有着读取速度快,可持久化的优点。redis的持久化保证了断电或重启数据不会丢失。但仅仅这样是不够的的,持久化是将数据定期写入磁盘中,万一哪一天这一台服务器挂掉了,那所有数据依旧会丢失。为了解决这个单点故障问题,所以就有了主从复制。
主从复制就是 将一台redis服务器的数据自动的复制到其他redis服务器上。一台服务器出故障的概率很高,但是多台服务器同时出故障的概率就很低了吧。所谓主从主从,当然是有主服务器 (master) 和从服务器 (slave) 啦,一个 master 可以将数据复制到多个 slave,但是特别注意的是,复制是单向的,只能从 master 到 slave 。一个master 可以有多个 slave ,一个slave 也可以有多个slave ,但是一个 slave 只能从属一个master 。如下图这样就是错误的。

主从复制的作用及场景
1、数据冗余:主从复制实现了数据的热备份,相当于一份数据在多个服务器上存储了,是持久化之外的一种数据冗余方式,这样做的目的是以空间换取安全性。如果主服务器挂掉了,可以通过从服务将数据恢复。
2、故障快速修复:当 master 出现问题的时候,可以快速的将一个 slave 切换成 master 继续提供服务 ,保证项目稳定性。
3、读写分离:主从复制实现读写分离非常简单,写入的时候只操作 master ,读取的时候只操作 slave ,这样读的话可以多个slave 满足项目高并发的操作。
4、负载均衡:既然实现了读写分离,当然就能实现负载均衡,多个 slave 承担 数据读取操作 ,从而分担 master 服务器的压力。
5、高可用的基石:主从复制还是哨兵模式和集群模式能够实施的基础。
既然主从复制有这些作用,那在实际应用中会用在哪些场景呢?
1、如果项目对数据安全性稳定性要求较高,就会使用主从复制搭建哨兵模式或者搭建集群。
2、海量数据读写,需要做读写分离提高防蚊效率,就会用到主从复制
3、容灾恢复,如果对数据依赖度很高,害怕数据在服务器挂掉后丢失,就可以通过主从复制防止数据丢失。
主从复制的模式
一主一从
这种模式在实际应用中还是比较少见的其实,一主一从主要是实现读写分离和容灾恢复。考虑到成本的问题,所以采用两台服务器,一个redis服务器master 负责读操作,并定期的复制到 另个一服务器slave 。slave 服务器负责读写操作。在项目中配置的时候配置两个redis连接。
一主多从
一主多从有可以分为几种,如下图:

这种就是所有的 slave 都从 master 中 进行复制,这样的好处是 配置简单,所有的slave 都只用关系 master 就好了,但是要考虑到其实复制也是会侵占CPU内存的,所有的slave 都从 master 复制,可能增大 master的负荷。
再来看看下图


这种模式也是一主多从,但是和上面的所有的 slave 都从 master 复制不一样。它是使一个到两个slave 从master 直接复制,其他的slave 从这两个slave 中复制。存在层级关系。这样的好处的降低的master 服务器的负荷,但是这样会导致如果中间某个 slave 挂掉了,那依附于它的所有slave 都不能用了。
主从复制部署
这里我使用的是Ubuntu安装的redis,redis怎么安装,可以看我这篇文章 Redis安装 安装好redis后,我们启动看看是否正常
redis-server /usr/local/redis/etc/redis.conf redis-cli -a 123456

证明是redis是正常启动的,那现在怎么配置主从模式呢?
按理说主次模式的redis服务器当然是搭建在不同的服务器上,但是我们条件有限,我这里的三台redis服务都搭建在一个服务器上,只是他们监听的端口不同。
1、修改redis.conf
我们先修改master的配置文件redis.conf 的一些配置
bind 0.0.0.0 表示可以被所有机器访问。 daemonize yes 表示可以后台启动 port 6379 pidfile /var/run/redis_6379.pid logfile "/usr/local/redis/logs/log_redis.log" requirepass 123456


2、复制两份redis.config
改好redis.conf 后,将/usr/local/redis/etc/ 目录下的redis.config 复制两份为redis_slave1.conf redis_slave2.config

3、修改rdis_slave1.conf
bind 本机ip 表示只能本机访问 daemonize yes port 6389 pidfile /var/run/redis_6389.pid logfile "/usr/local/redis/logs/log_redis_slaveof6389.log" requirepass 123456 ---上面的这些配置和redis.conf中基本一样修改一下就好了,日志是为了方便查看。下面看重点配置 slaveof 192.168.252.53 6379 设置master的ip 和port masterauth 123456 设置master的登录密码,就是redis.conf 中配置的requirepass


4、修改redis_slave2.conf
同样的
bind 192.168.252.53 daemonize yes port 6399 pidfile /var/run/redis_6399.pid logfile "/usr/local/redis/logs/log_redis_slaveof6399.log" requirepass 123456 slaveof 192.168.252.53 6379 masterauth 123456
5、启动redis服务
redis-server /usr/local/redis/etc/redis.conf redis-server /usr/local/redis/etc/redis_slaveof1.conf redis-server /usr/local/redis/etc/redis_slaveof2.conf
查看一下进程
ps -ef | grep redis

6、启动客户端
都启动来了,现在连到单个redis服务器看看
主服务 redis-cli -a 123456 从服务 redis-cli -h 192.168.252.53 -p 6389 -a 123456 redis-cli -h 192.168.252.53 -p 6399 -a 123456


7、测试
启动3台客户端,分别连上master和两个slave 在master中
set c 122

在slave1和slave2 中分别
get c


这样就说明你的主从复制服务已经搭建好啦。
8、问题记录
上面的是一个完美的过程搭建的主从复制的例子,但是我相信在实际搭建的时候肯定会出现各种问题,现在记录下我搭建的时候出现的问题吧 1、权限问题 在搭建好主从服务后,进入从节点查看info replication
发现
master_link_status:down
表明主从节点并没有建立连接,但是但是为什么一直是down 呢,看了一下日志

提示不能打开rdb这个快照,当然就不能将内容复制到从节点啦,再一看这个路径,是我自己建的路径,第一反应就是权限问题,然后进这个目录一看,发现我的etc目录是root用户的。所以就修改了文件的用户和用户组。在进到etc目录下,就发现了两个快照,再去看的时候发现down变成up 了。
quellanan@quellanan-Lenovo-G400:/usr/local/redis$ sudo chown quellanan etc [sudo] quellanan 的密码: quellanan@quellanan-Lenovo-G400:/usr/local/redis$ sudo chgrp quellanan etc quellanan@quellanan-Lenovo-G400:/usr/local/redis$ ll 总用量 20 drwxr-xr-x 5 root root 4096 8月 8 16:50 ./ drwxr-xr-x 13 root root 4096 8月 1 16:28 ../ drwxr-xr-x 2 root root 4096 8月 1 16:57 bin/ drwxr-xr-x 2 quellanan quellanan 4096 8月 15 09:50 etc/ drwxrwxrwx 2 root root 4096 8月 15 09:16 logs/ quellanan@quellanan-Lenovo-G400:/usr/local/redis$ cd etc/ quellanan@quellanan-Lenovo-G400:/usr/local/redis/etc$ ll 总用量 196 drwxr-xr-x 2 quellanan quellanan 4096 8月 15 09:50 ./ drwxr-xr-x 5 root root 4096 8月 8 16:50 ../ -rw-r--r-- 1 quellanan quellanan 188 8月 15 09:50 dump6389.rdb -rw-rw-r-- 1 quellanan quellanan 188 8月 15 09:50 dump.rdb -rw-rw-r-- 1 quellanan quellanan 58810 8月 14 09:18 redis.conf -rw-rw-r-- 1 quellanan quellanan 58882 8月 14 09:16 redis_slaveof1.conf -rw-r--r-- 1 quellanan quellanan 58882 8月 15 09:11 redis_slaveof2.conf
权限问题我感觉还是挺大的,因为我们一般都是远程到服务器上操作,所以用户权限很多都需要注意。
2、还有一个也是发现master_link_status:down,但是并不是用户权限问题导致的,查看一下防火墙的状态,将防火墙关闭了试试。
ufw status 查看防火墙状态 ufw enable 开启防火墙 ufw disable 关闭防火墙
3、在主节点插入数据的时候出现问题
127.0.0.1:6379> set a 1qaz (error) MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.
执行这个
127.0.0.1:6379> config set stop-writes-on-bgsave-error no OK 127.0.0.1:6379> set a 123456 OK 127.0.0.1:6379> get a "123456"
主从复制的原理
上面以及搭建了一个主从复制的样例,是一主两从的,那是怎么redis是怎么具体实现的呢? 在将原理之前,先来看看主从复制的几个概念。启动master后
127.0.0.1:6379> info server # Server redis_version:4.0.9 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:514e9a11b2a67dfc redis_mode:standalone os:Linux 5.0.0-23-generic x86_64 arch_bits:64 multiplexing_api:epoll atomicvar_api:atomic-builtin gcc_version:7.4.0 process_id:19688 run_id:136de716105e54294144003a881ba29cdfbccfb2 tcp_port:6379 uptime_in_seconds:4515 uptime_in_days:0 hz:10 lru_clock:5556386 executable:/usr/local/redis/etc/redis-server config_file:/usr/local/redis/etc/redis.conf
这个run_id 就是redis服务的唯一标识,重启redis服务号,这个run_id 会改变,多个redis客户端连接到同一个服务端,其run_id 是一样的,也就是说run_id 指的是服务端的id
127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=192.168.252.53,port=6389,state=online,offset=5541,lag=1 slave1:ip=192.168.252.53,port=6399,state=online,offset=5541,lag=0 master_replid:f0c89aa8040dfe869de82ee623a1212240456d76 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:5541 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:5541
其中repl_backlog_size 复制缓存区大小,默认大小为1M,如果mater_repl_offset在这个范围内,就看是部分复制,否则就开始全量复制。
全量复制
先看下图,图画的不是很好见谅

1、首先slave会向 master发送一个 psync 命令,因为是第一次,所以不知道run_id 和offset,所以传过来-1表示全量复制
2、 master在接收到psync 后,将run_id 和offset 发送给slave,slave存储起来
3、master进行bgsave生成rdb ,并将rdb 文件发送给slave
4、在bgsave 和send rdb 的过程中可能会产生write 的数据,那么就会把数据存到repl_back_buffer 中 并将buffer发送给slave .
5、slave 会清空就数据,然后加载rdb和buffer 将数据存储起来。
部分复制

既然是部分复制,那就是slave已经知道了master的run_id 和offset ,所以发送psync 命令带上这两个参数,master 就知道这是部分复制,然后通过偏移量将需要复制的数据发送给slave。
总结
主从复制的过程中既用到了全量复制也用到了部分复制,二者是相互配合使用的。看下面的流程图:

还有一点需要注意的是,如果master 重启了,那么它的run_id发生了改变,那么依赖它的slave都会进行一次全量复制后在进行部分复制。
哨兵模式
哨兵模式介绍
在将哨兵模式之前,先来说说主从复制的缺点吧。
如果主节点出了问题,那么主节点不在提供服务,需要手动的将从节点切换成主节点。
所以这个时候哨兵模式就出现啦,当主节出现故障时,Redis Sentinel会自动的发现主节点的故障并转移,并通知应用方,实现高可用。
下面是Redis官方文档对于哨兵功能的描述:
1、监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。
2、自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
3、配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
4、通知(Notification):哨兵可以将故障转移的结果发送给客户端。
哨兵模式的结构拓扑图大概如下,也是照书上画的哈哈

大意就是
1、每一个哨兵节点会监听其他的哨兵节点以及master 和所有的slave
2、所有哨兵节点会定期的ping 主节点,监控是否正常
3、如果认为主节点出现故障的哨兵数量达到阙zhi,就判定主节点死掉,主节点就会客观下线
4、主节点客观下线后,哨兵节点通过选举模式在 slave 中选择出一个升级为主节点
5、其他的salve 指向新的主节点
6、原来的master 变成 slave ,并且指向新的主节点
引用官方哨兵模式处理流程
每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
●如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)。
●如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态。
●当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)。
●在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
●当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
●若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
哨兵模式部署
1、首先到我们redis安装目录下,发现有sentinel.conf ,我们把它移到我们自己定义的文件夹中,和redis.conf 放在一起。
mv sentinel.conf /usr/local/redis/etc/

2、修改sentinel.conf文件
port 26379 dir /usr/local/redis/etc 这里默认的是“/tmp”,如果你没有这个目录的权限就需要换啦,换一个你有权限的目录,不然后果自负哈哈,我就是从坑里爬起来的 sentinel monitor mymaster 192.168.252.53 6379 2 sentinel auth-pass mymaster 123456 设置监控的主节点,2是一个阈值,代表有两台或两台以上哨兵判断主节点redis不通的话就认定这个节点有问题,实行故障转移。 daemonize yes 后台启动 logfile "/usr/local/redis/logs/redis_sentinel-26379.log" 加上日志 ,不加也无所谓

注意,这个auth-pass 要放在放在monitor 下面,不然会报错

配上一些参数说明:

3、将sentinel.conf 复制两份,分别为sentinel26389.conf,sentinel26399.conf并修改这个文件中的prot 和logfile
port 26389 logfile "/usr/local/redis/logs/redis_sentinel-26389.log" port 26399 logfile "/usr/local/redis/logs/redis_sentinel-26399.log"
4、启动哨兵
redis-sentinel /usr/local/redis/etc/sentinel.conf redis-sentinel /usr/local/redis/etc/sentinel26389.conf redis-sentinel /usr/local/redis/etc/sentinel26399.conf
查看一下,三个哨兵都已经启动了。

5、验证 先看看启动日志,,下图所示表明监控了三个节点。如果没有监控到这三个节点,证明没有配置成功。


没有配置成功的原因可能是防火墙导致的,关闭调防火墙。还有就是如果redis-server重启过,那在sentinel.conf中生成的pid 和最后的运行添加的几行需要删除掉,下图这些。然后重新运行。


好的,日志看的没有问题,如果不想看日志,我们来这样验证,我们已经启动了三个redis服务,三个哨兵。我们现在把 master 杀死看看是什么情况。
kill -9 19688
看日志,三个哨兵的监控日志基本上是一样的,下图贴出三个哨兵的日志,我们就看一下第一个哨兵的日志分析一下。

看上图,启动哨兵的时候,监控到了master 6379 和两个slave 6389和6399,以及另外两个哨兵,26389和26399.
然后sdown master mymaster 192.168.252.53 6379 表示刚刚我们杀死的master服务。
这个时候有一个哨兵表示其主观下线,等到odown 达到我们设置的2时,表明有两个哨兵表示其主观下线,那么就认为6379这个master 已经客观下线。
然后通过选举,选取26399 这个哨兵为这三个哨兵的领导者(leader)。
23699 这个leader 在salve中选择6399转为 master
将6389 这个slave 指向新的 master 6399
这个时候重启6379 这个redis服务
将6379 这个slave指向新的master 6399


好,下面我们来看看界面


可以看到master已经切换到6399 服务了,现在我们再切换一下,看下面这张图应该很清晰啦

到此为止,哨兵模式就搭建好啦,当 master 挂掉时,会自动的将一个slave 升级成 master 并将其他的 slave 指向新的master ,从新把原来的master启动后,会变成slave 执行新的master 。
总结
写到这,其实还有一部分没有写完,但是感觉实在是太长了,就先写这么多吧,还差一个怎么在项目中使用搭建的哨兵模式,也就是集群模式,怎么做到读写分离,实现高可用的。
因为前面这些讲的都是在redis数据库上直接操作,那现在部署好了,怎么在项目代码中使用呢,所以下篇接着将在项目中怎么使用redis集群。喜欢的小伙伴可以持续关注啦。
好了,上面都是题外话,下面总结一下这篇文章吧。
1、主从复制是什么以及作用。
2、怎样部署一个主从复制(案例一主两从)
3、怎样部署哨兵模式(三哨兵)
其实我感觉如果你通过这篇文章学会了这三点,就够了,其他的看看当了解。
谢谢大家
看到这的小伙伴,对文章有什么建议赶紧提出来吧!这一期想写 redis 的。从 redis 安装到redis 简单使用,redis主从复制,redis 持久化,哨兵模式,集群模式。由浅及深图文讲解帮助大家全面深刻的了解reidis 知识。如果大家感兴趣可以持续关注。觉得好看记得分享哟❤