一、redis主从的特性
- redis 使用异步复制。从 redis 2.8 开始,slave 也会周期性的告诉 master 现在的数据量。可能只是个机制,用途应该不大。
-
一个 master 可以拥有多个 slave,废话,这也是业界的标配吧。
-
slave 可以接收来自其他 slave 的连接。意思是不是就是说 slave 在接收其他的slave的连接之后成为 master ?答案是 fou,仍然是slave,并不会升级为master
- redis 复制在 master 这一端是非阻塞的,也就是说在和 slave 同步数据的时候,master 仍然可以执行客户端的操作命令而不受其影响。这点都不能保证,要你干嘛?
- redis 复制在 slave 这一端也是非阻塞的。在配置文件里面有 slave-serve-stale-data 这一项,如果它为 yes ,slave 在执行同步时,它可以使用老版本的数据来处理查询请求,如果是 no ,slave 将返回一个错误。在完成同步后,slave 需要删除老数据,加载新数据,在这个阶段,slave 会阻止连接进来。
-
Replication can be used both for scalability, in order to have multiple slaves for read-only queries (for example, heavy SORT operations can be offloaded to slaves), or simply for data redundancy.这句话我也没理解什么意思。
- 使用复制可以避免 master 因为需要把全部的数据集写入磁盘而造成的开销,因此可以把 master 中 save 配置项全部注释掉,不让它进行保存,然后配置 slave ,让 slave 保存。虽然有这个特性,但是我们好像一般不这么做。
先打开三个终端,然后起三个实例,分别用三个 client 去连接它们:
zhaoguihuadediannao:src zhaogh$ ./redis-server --port 10000 --daemonize yes
zhaoguihuadediannao:src zhaogh$
zhaoguihuadediannao:src zhaogh$ ./redis-cli -p 10000
端口10000的做 master。
slave 01:
zhaoguihuadediannao:src zhaogh$ ./redis-server --port 10001 --daemonize yes
zhaoguihuadediannao:src zhaogh$
zhaoguihuadediannao:src zhaogh$ ./redis-cli -p 10001
slave 02:
zhaoguihuadediannao:src zhaogh$ ./redis-server --port 10002 --daemonize yes
zhaoguihuadediannao:src zhaogh$
zhaoguihuadediannao:src zhaogh$ ./redis-cli -p 10002
上面只是让它们的实例启动了并用客户端去连接它,并没有设置主从关系。在 slave 01 和 slave 02 上执行下面的命令:
127.0.0.1:10001> slaveof 127.0.0.1 10000
OK
127.0.0.1:10001>
这样就设置好了主从关系。我们来试试有没有效果。
127.0.0.1:10001> get testkey001
(nil)
127.0.0.1:10001>
这个时候是没有值的。
master 上执行:
127.0.0.1:10000> set testkey001 testvalue001
OK
127.0.0.1:10000>
然后看看 slave 上有没有:
127.0.0.1:10001> get testkey001
"testvalue001"
127.0.0.1:10001>
127.0.0.1:10002> get testkey001
"testvalue001"
127.0.0.1:10002>
有了,是不是比***点读机还 easy ?已经有了感性的认识,我们来介绍一下它的原理吧。
当你设置了主从关系后,slave 在第一次连接或者重新连接 master 时,slave 都会发送一条同步指令给 master ;
master 接到指令后,开始启动后台保存进程保存数据,接着收集所有的数据修改指令。后台保存完了,master 就把这份数据发送给 slave,slave 先把数据保存到磁盘,然后把它加载到内存中,master 接着就把收集的数据修改指令一行一行的发给 slave,slave 接收到之后重新执行该指令,这样就实现了数据同步。
slave 在与 master 失去联系后,自动的重新连接。如果 master 收到了多个 slave 的同步请求,它会执行单个后台保存来为所有的 slave 服务。
一旦 master 和 slave 在失去联系并重新连接上,总是会重新进行一次完整的同步
三、slave ---master测试
0. 初始情况下各节点info情况(部分有用信息):
MASTER ->
'connected_slaves': 1, #可判断slave存活状况
SLAVE ->
'master_host': '127.0.0.1',
'master_last_io_seconds_ago': 5,
'master_link_status': 'up', #可判断master与slave存活状况
'master_port': 6378
1. 正常读写:
In [32]: r1.set('key', 'value')
Out[32]: True
In [34]: r2.get('key')
Out[34]: 'value'
2. 主备正常连接下, 默认slave(不配置slave-read-only on)
向slave写入后发现报错
In [35]: r2.set('key2', 'value')
ReadOnlyError: You can't write against a read only slave
3. Master闪断:
Crash掉主节点:
'master_host': '127.0.0.1',
'master_last_io_seconds_ago': -1,
'master_link_down_since_seconds': 4,
'master_link_status': 'down',
'master_port': 6378
重启主节点后,slave自动从从新建立连接
'master_host': '127.0.0.1',
'master_last_io_seconds_ago': 9,
'master_link_status': 'up',
'master_port': 6378,
4. Crash掉主节点,slave默认(不配置slave-read-only on 情况)
即使master挂掉,slave写入依然报错
SLAVE ->
'master_host': '127.0.0.1',
'master_last_io_seconds_ago': -1,
'master_link_down_since_seconds': 6,
'master_link_status': 'down',
'master_port': 6378
In [37]: r2.set('key', 'value')
ReadOnlyError: You can't write against a read only slave.
设置slave为readonly,发现报错
zb@ubuntu:~/codes/test$ redis-cli -h 127.0.0.1 -p 6379 set slave-read-only no
(error) READONLY You can't write against a read only slave.
需要关闭slave的slave特性, 将其升级为主节点
zb@ubuntu:~/codes/test$ redis-cli -h 127.0.0.1 -p 6379 slaveof NO ONE
OK
zb@ubuntu:~/codes/test$ redis-cli -h 127.0.0.1 -p 6379 set slave-read-only no
OK
升级为主节点后,继续向slave写入:
In [38]: r2.set('key', 'value')
Out[38]: True
5. 重启master, 如果将slave升级为master, 此时master与slave已经隔离, 都作为主节点存在(注意此时的主节点是没有数据的)
In [41]: r1.get('key')
In [42]:
6. 拷贝R2的dump数据到R1后重启:
In [43]: r1.get('key')
Out[43]: 'value'
7. 从新将R2设置为R1的slave(slave默认配置):
向slave写入:
In [45]: r2.set('key2', 'value')
ReadOnlyError: You can't write against a read only slave.
8. 如果将slave-read-only 属性写到配置文件中:
可以向slave写入数据,但是不会同步到master
In [50]: r2.set('key2', 'value')
Out[50]: True
9. Crash掉R1,往R2写数据(关掉slave-read-only):
SLAVE ->
'master_link_status': 'down'
In [75]: r2.set('key2', 'value')
Out[75]: True
重启Master(此时的master无数据):
In [85]: r2.get('key2')
In [86]: r2.get('key3')
可以看到,重启了Master后,slave同步了master状态,由于master没有数据,slave的数据同时被删除
总结(部分测试未写出来):
- slave 配置为slave-read-only on需要升级为主节点或者写入配置文件中, 而不能在默认slave情况下直接设置
- master与slave断开后会检测心跳, 从新建立连接.
- 可以直接copy DUMP文件从新重启master
- 在Master为空以后,slave同步数据会抹掉全部数据.