一、redis主从的特性
一个 master 可以拥有多个 slave,废话,这也是业界的标配吧。
slave 可以接收来自其他 slave 的连接。意思是不是就是说 slave 在接收其他的slave的连接之后成为 master ?答案是 fou,仍然是slave,并不会升级为master
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.这句话我也没理解什么意思。
先打开三个终端,然后起三个实例,分别用三个 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测试
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
In [32]: r1.set('key', 'value')
Out[32]: True
In [34]: r2.get('key')
Out[34]: 'value'
向slave写入后发现报错
In [35]: r2.set('key2', 'value')
ReadOnlyError: You can't write against a read only slave
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,
即使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
In [41]: r1.get('key')
In [42]:
In [43]: r1.get('key')
Out[43]: 'value'
向slave写入:
In [45]: r2.set('key2', 'value')
ReadOnlyError: You can't write against a read only slave.
可以向slave写入数据,但是不会同步到master
In [50]: r2.set('key2', 'value')
Out[50]: True
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的数据同时被删除
总结(部分测试未写出来):