七、Redis主从复制
1、Redis主从复制简介
-
主机数据更新后根据配置和策略,自动同步到从机的master/slaver机制,Master以写为主,Slave以读为主
-
主从复制的目的
- 读写分离,性能扩展
- 容灾快速恢复
-
效果图
2、搭建主从复制
-
使用一台服务器多个端口实现,多态服务器也是同理
-
第一步:将redis.conf配置文件复制到myredis文件夹下,并创建三个配置文件(一主两从)
[root@localhost ~]# mkdir /myredis [root@localhost ~]# cp /etc/redis.conf /myredis [root@localhost myredis]# vim redis6379.conf [root@localhost myredis]# vim redis6380.conf [root@localhost myredis]# vim redis6381.conf
-
第二步:分别在三个配置文件中,根据自己的端口配置如下内容
include /myredis/redis.conf pidfile /var/run/redis_6379.pid port 6379 dbfilename dump6379.rdb
-
第三步:启动三台redis服务器,并查看进程,是否启动成功
[root@localhost myredis]# redis-server redis6379.conf [root@localhost myredis]# redis-server redis6380.conf [root@localhost myredis]# redis-server redis6381.conf [root@localhost myredis]# ps -ef | grep redis root 9689 1 0 10:37 ? 00:00:00 redis-server *:6379 root 9715 1 0 10:39 ? 00:00:00 redis-server *:6380 root 9721 1 0 10:39 ? 00:00:00 redis-server *:6381 root 9760 9253 0 10:40 pts/0 00:00:00 grep --color=auto redis
-
第四步:开启客户端,通过指定端口来实现连接不同的服务器
[root@localhost myredis]# redis-cli -p 6379 127.0.0.1:6379> ping PONG 127.0.0.1:6379> # 其他两台连接方法一致 连接不同的端口号 # 查看每台服务器的主从信息 127.0.0.1:6379> info replication # Replication role:master # 可以发现每一台都是主服务器,因为还没有配置主从复制 connected_slaves:0 master_failover_state:no-failover master_replid:325ea47b75fcb7812e9b105673522db3238dec3f 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:6381> slaveof 127.0.0.1 6379 # 该命令只需要从服务器执行即可 OK 127.0.0.1:6381> info replication # Replication role:slave # 使用info replication 发现是状态master变为slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:4 master_sync_in_progress:0 slave_repl_offset:70 slave_priority:100 slave_read_only:1 connected_slaves:0 master_failover_state:no-failover master_replid:c949037adcd0695b027551df0a34e3c5df5736a5 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
-
有下面三点需要注意
- 1、只有主服务器拥有读写权限,从服务器只有读权限
- 2、主服务器宕机重启后,依然是主服务器
- 3、从服务器宕机重启后,不再是从服务器,是独立的主服务器
3、薪火相传模式
-
上一个Slave可以是下一个Slave的Master,Slave同样可以接收其他Slave的连接和同步请求,那么该Slave作为了链条下一个的master,可由有效减轻master的写压力,去中心化降低风险
-
命令 :slaveof ip port
-
特点
- 中途变更转向:会清除之前的数据,重新建立连接拷贝最新的
- 风险:一旦某个slave宕机,后面的slave都无法备份
- 主机挂了,从机还是从机,无法写数据
-
效果图
4、反客为主模式
- 当一个master宕机之后,后面的slave可以like省委master,其后面的slave不用做任何修改
- 命令:slaveof no one # 将从机变为主机
5、主从复制原理
-
1、Slave启动成功连接到master后会发送一个同步(sync)命令
-
2、Master在接收到命令启动后台的存盘进程,同时收集所有接收到用于修改数据集命令,在后台进程执行完毕之后,Master将传送整个数据文件到Slave以完成一次完全同步
-
3、全量复制:Slave服务在接收到数据库文件数据后,将其存盘并加载到内存中
-
4、增量复制:Master继续将新的所有收集到的修改命令一次传给Slave完成同步
-
5、但是只要是重新建立连接,Master一次完成同步(全量复制)将被自动执行
6、哨兵模式
-
哨兵模式:反客为主的自动版
-
第一步:在编写配置文件sentinel.conf,配置内容
sentinel monitor mymaster 127.0.0.1 6379 1
- mymaster : 别名
- 1 :至少有多少个哨兵同意迁移的数量
-
第二步:启动哨兵
[root@localhost bin]# redis-sentinel /myredis/sentinel.conf ########..... 11301:X 22 Nov 2021 12:32:06.442 # +monitor master mymaster 127.0.0.1 6379 quorum 1 11301:X 22 Nov 2021 12:32:06.444 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 11301:X 22 Nov 2021 12:32:06.445 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
-
哨兵占用的端口号为:26379
-
当主服务器宕机后,如何从从服务器中选举主服务器?
- 1、选择优先级高的
- 优先级在redis.conf中配置replace-priority 100 (100默认值,值越小优先级越高)
- 2、若优先级一致,选择偏移量大的
- 偏移量:获得原主机数据最全的
- 3、偏移量一致,选择runid最小的
- 每个redis服务启动后都会随机分配一个40位的runid
- 1、选择优先级高的
7、java语言实现主从复制
private static JedisSentinelPool jedisSentinelPool=null;
public static Jedis getJedisFromSentinel(){
if(jedisSentinelPool==null){
Set<String> sentinelSet=new HashSet<>();
sentinelSet.add("192.168.11.103:26379");
JedisPoolConfig jedisPoolConfig =new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(10); //最大可用连接数
jedisPoolConfig.setMaxIdle(5); //最大闲置连接数
jedisPoolConfig.setMinIdle(5); //最小闲置连接数
jedisPoolConfig.setBlockWhenExhausted(true); //连接耗尽是否等待
jedisPoolConfig.setMaxWaitMillis(2000); //等待时间
jedisPoolConfig.setTestOnBorrow(true); //取连接的时候进行一下测试 ping pong
jedisSentinelPool=new JedisSentinelPool("mymaster",sentinelSet,jedisPoolConfig);
return jedisSentinelPool.getResource();
}else{
return jedisSentinelPool.getResource();
}
}