主从复制
就是主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。
用处
读写分离,性能扩展
容灾快速恢复
示意图:
配置Redis
1、拷贝多个redis.conf文件include,因为redis.conf可以配置共有的配置。如果有不同,include后,可以自行配置,会覆盖redis.conf中的配置。
首先在主目录下,新建master-slave文件夹(其实就是随便建个目录放文件),里面添加不同端口的配置文件,起3个服务,形成三个redis节点。
同时include共有的配置:
然后,共有的配置到redis.conf中修改,不同的配置在单独的配置文件中修改。
2、开启daemonize yes
使用的是一台机器启动多个服务的方法,所以需要配置后台启动。
在redis.conf中:
# By default Redis does not run as a daemon. Use 'yes' if you need it. # Note that Redis will write a pid file in /var/run/redis.pid when daemonized. daemonize yes
3、Pid文件名字pidfile
这个在redis.conf中找到,各自配置下,如果是单独的机器,这个不用配置:
pidfile /var/run/redis_6379.pid
4、指定端口
port 6379
5、Log文件名字
logfile /usr/local/src/bchen/redis-5.0.8/master-slave/file_6379.log
6、Dump.rdb名字dbfilename,涉及到一个文件名称和一个路径名称
dbfilename dump_6379.rdb
dir /usr/local/src/bchen/redis-5.0.8/master-slave
7、Appendonly 关掉或者换名字
这个是aof持久化相关的,我们可以不用配置,直接关了就好,有开rdb就可以了。直接在共有的redis.conf中配置。
appendonly no
其实默认就是no。
8、其他实例也配置下,最终配置文件长这样:
6379:
include /usr/local/src/bchen/redis-5.0.8/redis.conf pidfile /var/run/redis_6379.pid port 6379 logfile /usr/local/src/bchen/redis-5.0.8/master-slave/file_6379.log dbfilename /usr/local/src/bchen/redis-5.0.8/master-slave/dump_6379.rdb
6380:
include /usr/local/src/bchen/redis-5.0.8/redis.conf pidfile /var/run/redis_6380.pid port 6380 logfile /usr/local/src/bchen/redis-5.0.8/master-slave/file_6380.log dbfilename /usr/local/src/bchen/redis-5.0.8/master-slave/dump_6380.rdb
6381:
include /usr/local/src/bchen/redis-5.0.8/redis.conf pidfile /var/run/redis_6381.pid port 6381 logfile /usr/local/src/bchen/redis-5.0.8/master-slave/file_6381.log dbfilename /usr/local/src/bchen/redis-5.0.8/master-slave/dump_6381.rdb
启动
启动命令
查看进程:
三个pid文件:
日志文件:
搭建简单的一主二仆模式
这三个实例其实现在是互不关联的,需要额外的操作使之互相起作用。
先熟悉两个重要的命令:
info replication:打印主从复制的相关信息
slaveof <ip> <port> : 成为某个实例的从服务器,相当于现在的小弟找大哥。
先三台机器各自执行下,info replication命令:
可以看到初始角色全部都是master。
接下来把6380和6381配置slave。
192.168.71.131:6381> slaveof 192.168.71.131 6379 OK
192.168.71.131:6380> slaveof 192.168.71.131 6379 OK
查看下主从关系:
192.168.71.131:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=192.168.71.131,port=6381,state=online,offset=392,lag=0 slave1:ip=192.168.71.131,port=6380,state=online,offset=392,lag=0 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:392 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:392
192.168.71.131:6380> info replication # Replication role:slave master_host:192.168.71.131 master_port:6379 master_link_status:up master_last_io_seconds_ago:4 master_sync_in_progress:0 slave_repl_offset:378 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:378 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:323 repl_backlog_histlen:56
192.168.71.131:6381> info replication # Replication role:slave master_host:192.168.71.131 master_port:6379 master_link_status:up master_last_io_seconds_ago:9 master_sync_in_progress:0 slave_repl_offset:392 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:392 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:392
可以看到6379已经变成了master, 6380和6381为slave。
测试主从复制
尝试从slave(6380)写入:
192.168.71.131:6380> select 0 OK 192.168.71.131:6380> keys * (empty list or set) 192.168.71.131:6380> set k1 v1 (error) READONLY You can't write against a read only replica.
报错!
尝试从master写入:
192.168.71.131:6379> 192.168.71.131:6379> SELECT 0 OK 192.168.71.131:6379> keys * (empty list or set) 192.168.71.131:6379> set k1 v1 OK 192.168.71.131:6379> get k1 "v1"
可以看到master可以写入也可以读取。
再从slave中读取数据:
192.168.71.131:6380> get k1 "v1"
6380中可以读取到,同样的6381中也可以读取到。
问题刨析
1、从机是否可以写?set可否?
以上已经测试过了,可以看出从机不能写,只能读。
2、切入点问题。slave第一次加入进来,是从头开始复制还是从切入点开始复制。
先把6380(或者6381)关闭掉,然后启动,删除所有数据,然后重新接入到6379成为slave,看下6380能否有之前的数据。
可以看到没有6380这个进程,然后看下6379的主从关系。
[root@localhost src]# ./redis-cli -h 192.168.71.131 -p 6379 192.168.71.131:6379> info replication # Replication role:master connected_slaves:1 slave0:ip=192.168.71.131,port=6381,state=online,offset=12652,lag=1 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:12652 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:12652
这时候没有了6380这个slave。
启动6380
[root@localhost src]# ./redis-server ../master-slave/redis6380.conf [root@localhost src]# ps -ef | grep redis root 86740 1 0 03:26 ? 00:00:12 ./redis-server 192.168.71.131:6379 root 86750 1 0 03:26 ? 00:00:11 ./redis-server 192.168.71.131:6381 root 86941 86919 0 07:33 pts/0 00:00:00 ./redis-cli -h 192.168.71.131 -p 6379 root 86967 1 0 07:36 ? 00:00:00 ./redis-server 192.168.71.131:6380 root 86972 86946 0 07:36 pts/2 00:00:00 grep --color=auto redis
再次查看6379:
192.168.71.131:6379> info replication # Replication role:master connected_slaves:1 slave0:ip=192.168.71.131,port=6381,state=online,offset=13002,lag=1 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:13002 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:13002
可以看出,slave不会保存上次的记忆,不会自动成为79的从机。
这时候,我们把6380的数据全部清空。
[root@localhost src]# ./redis-cli -h 192.168.71.131 -p 6380 192.168.71.131:6380> keys * 1) "k1" 192.168.71.131:6380> FLUSHALL OK 192.168.71.131:6380> keys * (empty list or set)
然后再让它成为6379的从机:
192.168.71.131:6380> slaveof 192.168.71.131 6379 OK 192.168.71.131:6380> keys * 1) "k1"
发现6380已经把全部数据同步过来了。并从新成为6379的slave。
当一个全新的节点成为某个master的slave的时候,他会从master那边同步一份最全的数据过来,而并不是从切入点开始复制。
3、其中一台从机运行了一段时间,然后down后情况如何?再次接入后,是怎么样的?
shutdown 8081
192.168.71.131:6381> shutdown not connected>
查看6379(要稍微等一会)
192.168.71.131:6379> info replication # Replication role:master connected_slaves:1 slave0:ip=192.168.71.131,port=6380,state=online,offset=25070,lag=1 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:25070 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:25070 192.168.71.131:6379> info replication # Replication role:master connected_slaves:1 slave0:ip=192.168.71.131,port=6380,state=online,offset=25140,lag=0 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:25140 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:25140
然后对6379写入新的键值对:
192.168.71.131:6379> set k2 v2 OK 192.168.71.131:6379> set k3 v3 OK
192.168.71.131:6379> keys * 1) "k3" 2) "k1" 3) "k2"
192.168.71.131:6380> keys * 1) "k3" 2) "k2" 3) "k1"
在6379和6380中都可以看到值的变化。
这时候启动8081,并执行slaveof命令,成为6379的slave。
[root@localhost src]# ./redis-server ../master-slave/redis6381.conf [root@localhost src]# ps -aux | grep redis root 86740 0.0 0.0 145188 2300 ? Ssl 03:26 0:20 ./redis-server 192.168.71.131:6379 root 86967 0.0 0.0 145188 2316 ? Ssl 07:36 0:07 ./redis-server 192.168.71.131:6380 root 87119 0.0 0.0 14080 1208 pts/0 S+ 09:56 0:00 ./redis-cli -h 192.168.71.131 -p 6379 root 87120 0.0 0.0 14080 1200 pts/1 S+ 09:56 0:00 ./redis-cli -h 192.168.71.131 -p 6380 root 87145 0.0 0.0 144024 2040 ? Ssl 10:06 0:00 ./redis-server 192.168.71.131:6381 root 87150 0.0 0.0 112720 952 pts/2 S+ 10:06 0:00 grep --color=auto redis [root@localhost src]# ./redis-cli -h 192.168.71.131 -p 6381 192.168.71.131:6381> keys * 1) "k1" 192.168.71.131:6381> SLAVEOF 192.168.71.131 6379 OK 192.168.71.131:6381> keys * 1) "k2" 2) "k3" 3) "k1"
可以看到重新成为slave的时候,可以重新拿数据,从而跟上大部队。
4、主机shutdown后情况如何?从机是上位成为master还是原地待命
192.168.71.131:6379> SHUTDOWN not connected> exit
关闭6379后。
稍微等会,再查看6380和6381的情况
192.168.71.131:6380> info replication # Replication role:slave master_host:192.168.71.131 master_port:6379 master_link_status:down master_last_io_seconds_ago:-1 master_sync_in_progress:0 slave_repl_offset:25949 master_link_down_since_seconds:113 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:25949 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:13311 repl_backlog_histlen:12639
192.168.71.131:6381> info replication # Replication role:slave master_host:192.168.71.131 master_port:6379 master_link_status:down master_last_io_seconds_ago:-1 master_sync_in_progress:0 slave_repl_offset:25949 master_link_down_since_seconds:148 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:25949 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:25698 repl_backlog_histlen:252
可以看到如果slave没有人为的额外的操作,仍然只是一个slave的角色。 不会上位成为master。
5、主机又回来了后,主机新增记录,从机还能否顺利复制?
现在我们启动6379
[root@localhost src]# ./redis-server ../master-slave/redis6379.conf [root@localhost src]# ps -aux | grep redis root 86967 0.0 0.0 145184 2308 ? Ssl 07:36 0:07 ./redis-server 192.168.71.131:6380 root 87120 0.0 0.0 14080 1204 pts/1 S+ 09:56 0:00 ./redis-cli -h 192.168.71.131 -p 6380 root 87145 0.0 0.0 145168 2280 ? Ssl 10:06 0:00 ./redis-server 192.168.71.131:6381 root 87151 0.0 0.0 14080 1212 pts/2 S+ 10:07 0:00 ./redis-cli -h 192.168.71.131 -p 6381 root 87155 0.0 0.0 145172 2232 ? Ssl 10:17 0:00 ./redis-server 192.168.71.131:6379 root 87162 0.0 0.0 112720 956 pts/0 S+ 10:17 0:00 grep --color=auto redis
查看下信息:
192.168.71.131:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=192.168.71.131,port=6380,state=online,offset=210,lag=0 slave1:ip=192.168.71.131,port=6381,state=online,offset=196,lag=1 master_replid:33bfcec0a2af6009b3e21df66a6bac7aeabcf64d 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
测试能否正常工作:
192.168.71.131:6379> set k4 v4 OK
192.168.71.131:6380> get k4 "v4"
192.168.71.131:6381> get k4 "v4"
可以正常工作。
当down掉的master重新回来的时候,是不用额外的操作,redis自动会维持原有的主从关系,并可以正常工作。
复制原理
1、每次从机联通后,都会给主机发送sync指令
2、主机立刻进行存盘操作,发送RDB文件,给从机
3、从机收到RDB文件后,进行全盘加载
4、之后每次主机的写操作,都会立刻发送给从机,从机执行相同的命令