try redis (五) -- master -slave 主从复制

时间:2021-03-07 16:24:42

参考官网原文:http://redis.io/topics/replication

 参考文章 :http://in.sdo.com/?p=1187


注意事项

Redis 的复制说白了就是通过配置 将slave  当做 masters 的复制。但是有有几个需要注意点:

1、Redis使用的是一部复制。从Redis 2.8开始,slaves 将定期确认从复制流中处理的数量

2、一个master 可以有多个slavers 

3、slaves可以接受其他slaves 的连接。

4、Redis的复制是不会阻塞master 的,也就是所谓的 non-blocking.这就意味着当一个或者多个slaves 在处理最初的同步时,master可以继续他的查询操作等。

5、为了有多个只读slaves,可以用俩做一些伸缩性的复制。

6、复制操作有可能也可以避免Redis将所有的数据集写入disk的损失。


master持久化变与复制的安全性

当 Redis 复制使用的时候,它是强烈建议master的持久化是开启的,当没法开启持久化比如需要延迟,Redis 需要配置成 禁止自动重启

为了更好的 理解为什么master 在自动重启的 情况下,关闭持久化配置是危险的。可能造成数据从master 和所有slaves 中擦除,我们看一个例子

1、我们启动nodeA 作为master,同时设置A 为持久化 turned down 。node B、C 从A 中复制数据

2、如果A 突然挂了,然后可以重启,但是由于没有开启持久化。重启后数据集为空

3、这个似乎 B 和 C将从 A 中复制空的数据集,这样原来的一些老的数据就被擦除了。

当 redis 系统为了提高可用率,会将master的持久化给关闭。但是任何时候,数据安全都是最重要的,复制功能在没有配置持久化,同时又自动重启的机器中是不可取的。



Reids 复制时怎么工作的

当启动一个slave ,连接后他会发送一个SYNC命令,在它第一次连接或者重新连接master的时候,这个都是正常的。

master 开始后台进行保存操作,同时开始开始缓存所有收到的改变数据集的命令。当后台保存成功,master将 保存在硬盘上的 数据集文件(dump.rdb) 读入到内存中 ,发送给slave。然后master将发送所有缓存命令,这好比是一个命令流,是redis协议本身实现的

Slaves 可以自动冲洗连接。当 master <-> salve 连接因为某些原因中断的时候。当master收到多个并发 slave 同步请求的时候,会有一个单独的线程专门来保存他们。


同时在网上找打一个 比较好的一个状态流程的解释


  1. Slave端在配置文件中添加了slave of指令,于是Slave启动时读取配置文件,初始状态为REDIS_REPL_CONNECT。
  2. Slave端在定时任务serverCron(Redis内部的定时器触发事件)中连接Master,发送sync命令,然后阻塞等待master发送回其内存快照文件(最新版的Redis已经不需要让Slave阻塞)。
  3. Master端收到sync命令简单判断是否有正在进行的内存快照子进程,没有则立即开始内存快照,有则等待其结束,当快照完成后会将该文件发送给Slave端。
  4. Slave端接收Master发来的内存快照文件,保存到本地,待接收完成后,清空内存表,重新读取Master发来的内存快照文件,重建整个内存表数据结构,并最终状态置位为 REDIS_REPL_CONNECTED状态,Slave状态机流转完成。
  5. Master端在发送快照文件过程中,接收的任何会改变数据集的命令都会暂时先保存在Slave网络连接的发送缓存队列里(list数据结构),待快照完成后,依次发给Slave,之后收到的命令相同处理,并将状态置位为 REDIS_REPL_ONLINE。

状态流程图如下:
try redis (五) -- master -slave 主从复制



redis.conf 关于  配置


port 6379

指定Redis监听端口,默认端口为6379

################################# REPLICATION ###################################

  maseter-slave 复制 需要注意几个点

1、redis 复制时一部实现的,但是你可以配置 master 在不能连接到一个给定数量的slaves 的时候,禁止写入

2、redis slaves 可以局部的再同步数据到master 如果master突然断掉。然后启动。

3、复制时自动进行的。不需要用户调用。如果slavers 与master 无法连接。slaves 会尝试连接master.同时再同步slaves上的数据到master上

######################################################################################


slaveof <masterId> <masterPort>

如果配置了slaveof 属性,意味着当前节点是 slave。同时确定了master的ip 和 端口


slave-serve-stale-data yes

当 slaves 和 master 失去联系或者 复制数据工作仍然在进行。这个适合slave 会有两种选择
 当配置 yes(默认的) 意味着slave 会反馈 客户端的请求
 当配置 no 客户端会反馈一个error "SYNC with master in progress" ,如果master 无法连接上,则会报"MASTERDOWN Link with MASTER is down and slave-serve-stale-data is set to 'no'."


slave-read-only yes

用官方的话说,就是保护slave ,不让它暴露在不受信任的客户端上。一般用来当做保护层,尤其在果断的client的时候。

当配置yes(默认)的时候,意味着客户端没法给slave 节点写入数据,一写就会报错"READONLY You can't write against a read only slave."

当配置成 no 的时候,任何客户端都可以写入


 masterauth

当master服务设置了密码保护时,slave服务连接master的密码


# requirepass foobared

设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH 命令提供密码,默认关闭


开始测试


感觉基本的属性就这些,下面感觉自己要开始做实验了。由于手头就两台机器,就准备搭建个三个节点的测试环境

masdter: A(10.13.145.36:6379)

slaves: B(10.13.145.35:7000)、C (10.13.145.36:7001)                               ---特别说明我的slaves放在一台机器上,起多个server服务模拟


A(10.13.145.36)就不用配置,全部使用默认配置即可

B的集群配置文件(redis_b.conf)如下:

... daemonize yes #后台启动 port 7000 #服务端口 slaveof 10.13.145.36 6379 #配置master A slave-serve-stale-data yes slave-read-only yes ...

启动 redis-server实例      ./redis-server redis_b.conf 


同理C 的配置如下:                                     

C的集群配置文件(redis_c.conf)如下:                                 --C的配置需要注意,我把slave-read-only 设置成 no 了

... daemonize yes #后台启动 port 7001 #服务端口 slaveof 10.13.145.36 6379 #配置master A slave-serve-stale-data yes slave-read-only no ...

启动 redis-server实例      ./redis-server redis_c.conf 


好。到此为止,所有的准备工作都 OK了。剩下的就是我们来测试 和验证下 Redis 的复制和替换功能。

有几种场景,我们都可以假设下,并且开始做实验。

一、A(master) 挂了。从B 、C 上是否可以取到数据

1在A(master) 中写入 key1 的数据

10.13.145.36:6379> SET key1 data1
OK
10.13.145.36:6379> get key1 
"data1"
2、这个时候,终止A 服务,然后开始从 B、C 上取值

从B上取值:

10.13.145.35:7000> get key1 
"data1"

从C 上取值:

10.13.145.36:7000> get key1 
"data1"
3、得出结论:master 挂了。还是可以从 B、C 上取到值


二、A(master) 挂了。从C写入数据data。看是否会复制到B。同时 A(master)又起来了。是否A上是否能查到data. 这时候 B上能否查到data

1、 停掉A,

2、在C中写入数据

10.13.145.35:7000> SET key2 data2
OK
10.13.145.35:7000> get key2
"data1"
3、启动A(master) 服务,从C 中读入数据 key2

10.13.145.35:7000> get key2
(nil)


三、A (master)一直ok ,然后B 挂了。给A 写入 data。然后B起来,看B上是否有data.

这个就不做测试了。slave每次启动发送 SYNC 命令,肯定会有数据


总结

  1. Redis的复制功能没有增量复制,每次重连都会把主库整个内存快照发给从库,所以需要避免向在线服务的压力较大的主库上增加从库。
  2. 启动时,resdis slaves 每秒都会ping master .确认复制流的进度.而master 每次都会记录每个slaver 最后 ping 的时间
  3. 自带的复制功能不好用。尤其是针对大的项目。现在开始去研究redis-cluster了。貌似3.0才支持。但是不是稳定版本。