一、简介
1、什么是主从复制
主机数据更新后根据配置和策略,自动同步到备机的master/slave机制
Matser以写为主,Slave以读为主,简单来说如下图
2、主从复制的好处
- 读写分离:Matser以写为主,Slave以读为主
- 容灾的快速恢复:当一台从服务器发生宕机,可以快速切换到其他的从服务器提供读操作
二、搭建一主多从
由于我本地只有一台虚拟机,所以我打算开启三个redis进程来模拟一主多从
前提:redis.conf中的protected-mode改为 fasle,否则不能进行主从复制
1、在根目录创建myredis文件夹
mkdir myredis
2、复制我们当前的redis配置文件到/myredis文件夹路径下
cp /opt/decade/redis.conf /myredis/redis.conf
3、配置一主两从,创建配置文件
touch redis6379.conf
4、分别修改配置文件的内容
可以使用include来引入我们原本的redis.conf
然后修改pid、端口和RDB相关配置
问题:是否需要关闭AOF,防止后面主从复制的时候,生成的RDB持久化文件为空?
include /myredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb
然后使用cp拷贝一下redis6379.conf,使用vi
修改配置
5、分别启动三个redis服务
cd /opt/decade/redis/bin/
redis-server /myredis/redis6379.conf
redis-server /myredis/redis6380.conf
redis-server /myredis/redis6381.conf
6、客户端使用指定端口号连接服务器
redis-cli -p 6379
redis-cli -p 6380
redis-cli -p 6381
使用info replication
获取 主/从 服务器的详细信息
127.0.0.1:6379> info replication
# Replication
role:master //当前角色 : 主服务器
connected_slaves:0 //连接的从服务器的个数
master_failover_state:no-failover
master_replid:b1642741686dc1a03075ae00a67269a41b53b0e8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379>
7、设置从机
只需要使用客户端连接指定端口号的服务器
使用slaveof [ip] [port]
就可以,我们使用6380和6381执行此命令
然后分别使用info replication
查看主从服务器详情,并且在master上执行set操作
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=70,lag=1
slave1:ip=127.0.0.1,port=6380,state=online,offset=70,lag=1
master_failover_state:no-failover
master_replid:09702c2e350d2ddaebeeda41fed8e0396031bce7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
127.0.0.1:6379>
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379>
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> keys *
1) "k1"
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379>
我们发现,master上设置的数据会同步到slave上,但是slave不能使用set操作,这就是上面说的读写分离
[root@192 bin]# redis-cli -p 6380
127.0.0.1:6380>
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:10
master_sync_in_progress:0
slave_read_repl_offset:42
slave_repl_offset:42
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:09702c2e350d2ddaebeeda41fed8e0396031bce7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:29
repl_backlog_histlen:14
127.0.0.1:6380>
127.0.0.1:6380> get k1
"v1"
127.0.0.1:6380> set k2 v2
(error) READONLY You can't write against a read only replica.
127.0.0.1:6380>
[root@192 bin]# redis-cli -p 6381
127.0.0.1:6381>
127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_read_repl_offset:56
slave_repl_offset:56
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:09702c2e350d2ddaebeeda41fed8e0396031bce7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:56
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:42
127.0.0.1:6381>
127.0.0.1:6381> get k1
"v1"
127.0.0.1:6381>
三、复制原理和一主二仆
一主二仆就是一个master下面有两个slave
1、当从服务器宕机之后
- 重启该服务器,并不会恢复为slave角色,而是会成为单独的master
- 当我们使用
slaveof host port
命令将从服务器重新加入到主从关系中后,从服务器会重新复制主服务器的数据(结合主从复制原理看)
2、当主服务器宕机之后
- 从服务器并不会抢夺主服务器的master角色,只是会显示master的状态master_link_status为down
- 主服务器重启之后,仍然是master角色
3、主从复制原理
-
全量同步阶段
- 从服务器连接到主服务器,发送
sync
命令 - 主服务器接收到该命令,开始执行
BGSAVE
命令生成RDB文件,并使用缓冲区记录此后执行的所有写命令 - 当主服务器
BGSAVE
执行完后,向所有从服务器发送RDB快照文件,并在发送期间继续记录被执行的写命令 - 从服务器收到快照文件后丢弃所有旧数据,重新读取收到的快照文件
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
- 完成上述步骤之后,从服务器就可以开始接收来自客户端的读请求
- 从服务器连接到主服务器,发送
-
增量同步阶段
- 主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令
简单概括一下就是:主从刚刚连接的时候,进行全量同步,全同步结束后,进行增量同步,从服务器在任何时候都可以要求全量同步
四、薪火相传和反客为主
1、薪火相传
薪火相传可以理解为,slave从服务器还存在属于它自己的从服务器,主服务器master的数据会沿着关系链往下同步
我现在令6379端口为master,6380为它的slave,然后再设置6381作为6380的slave
可以看出,master中设置的key会传递到slave下的slave中
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=168,lag=1
master_failover_state:no-failover
master_replid:67b215bc1ddef32238a07d2fad45b2d37d8fbed3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:168
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:168
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379>
127.0.0.1:6379> keys *
1) "k1"
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380>
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_read_repl_offset:234
slave_repl_offset:234
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=234,lag=1
master_failover_state:no-failover
master_replid:67b215bc1ddef32238a07d2fad45b2d37d8fbed3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:234
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:169
repl_backlog_histlen:66
127.0.0.1:6381> get k1
"v1"
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_read_repl_offset:346
slave_repl_offset:346
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:67b215bc1ddef32238a07d2fad45b2d37d8fbed3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:346
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:169
repl_backlog_histlen:178
127.0.0.1:6381>
127.0.0.1:6381> get k1
"v1"
2、反客为主
当master宕机之后,在它下面的slave上手动使用slaveof no one
命令将其立即晋升为master
思考:
- master重启之后还是master吗?
- 如果是一主二仆,那么另外一个仆也会归属于这个slave吗?
五、哨兵模式
1、什么是哨兵模式
可以理解为上面反客为主的自动版,我们会在后台监控主机是否发生故障,如果主服务器宕机,选择出一个从服务器,将他们作为新的主服务器,其余的从服务器跟随新的主服务器
2、如何使用哨兵模式
-
创建一个sentinel.conf并填写要监控的master信息
sentinel monitor < master-name > < ip > < port > < count >
master-name:给主服务器起的名字
count:最少需要几台 Sentinel哨兵 发现有问题,才会发生故障转移 -
然后使用redis安装目录bin下的redis-sentinel来启动哨兵
例如redis-sentinel /myredis/sentinel.conf
-
停掉master进程,看看会发生什么
3、预期结果
选举出一个slave来代替原来的master,而且旧master重启之后,它的角色也不会变回去
4、转换过程
- 新主登基:从旧master的slave中挑选一个作为新master
- 群仆俯首:sentinel向旧master的剩余slave发送slaveof指令,让它们变为新master的从服务器
- 旧主俯首:旧master重启后,sentinel向其发送slaveof指令,让它变为新master的从服务器
5、选举原则
- 根据配置文件redis.conf中的优先级配置replica-priority大小选出新的主机,值越小优先级越高
- 选择偏移量最大的:选举和旧master同步率较高或者从旧master获取数据较全的那个slave
- 选择runid最小的:每个redis实例启动时会生成40位runid
6、Java开发
涉及到哨兵模式时,连接池就不能使用之前的JedisPool了,而是换成JedisSentinelPool类
如有错误,欢迎指正!!!