是什么
主机数据更新后根据配置和策略,
自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主
能干嘛
读写分离,性能扩展
容灾快速恢复(当其中一台从服务器挂掉了,可以快速切换到其他好的从服务器上)
主从复制只能有一台主服务器,不可以有多个。
因为从服务器不知道改同步那个主服务器的数据。
如果主服务器宕机了,该怎么办?
答案就是使用集群。
怎么玩:主从复制
拷贝多个redis.conf文件include(写绝对路径)
开启daemonize yes
Pid文件名字pidfile
指定端口port
Log文件名字
dump.rdb名字dbfilename
Appendonly 关掉或者换名字
配置主从复制
配置一主两从为例:
1.创建myredis文件夹
mkdir /myredis
2.复制redis.conf文件到创建的文件夹中
cp /etc/redis.conf /myredis/redis.conf
3.配置一主两从,创建3个配置文件
redis6379.conf
redis6380.conf
redis6381.conf
先将redis.conf内容做修改
依次创建文件
vi redis6379.conf
然后进入编辑模式 使用 i
include /myredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb
然后保存退出。此时6379文件中就可以了。
接着做6380和6381文件。
为了方便就是使用复制的形式进行创建了。
cp redis6379.conf redis6380.conf
cp redis6379.conf redis6381.conf
4.在三个文件中写入内容
include /myredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb
对6380和6381文件进行编辑
修改pid,port,dbfilename
5.启动三个redis服务
查看当前主机运行情况
在从机上执行 slaveof 主机ip 端口号
启动三个redis服务:
redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf
查看系统进程,看看三台服务器是否启动
ps -ef|grep redis
查看三台主机运行情况(打印主从复制的相关信息)
先打开三个终端,分别使用命令对三台redis进行连接
redis-cli -p 6379
redis-cli -p 6380
redis-cli -p 6381
依次使用命令对主机运行情况进行查看
info replication
6379:
6380:
6381:
解读:
role:master 代表是主服务器
connected_slaves:0 代表没有从服务器
master_failover_state:no-failover
master_replid:f7047f5f59309be5b9bf4fe1c9606ec7406c8153
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
开始配置主从服务器:
slaveof
成为某个实例的从服务器
1.配从(库)不配主(库)
以6380和6381作为从机为例:
分别在6380和6381服务器上执行命令slaveof 127.0.0.1 6379
在6380和6381从服务器上使用命令info replication
进行查看
role:slave 代表从机
master_host:127.0.0.1 代表主机是127.0.1
master_port:6379 代表主机端口号是6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:224
slave_priority:100
slave_read_only:1
connected_slaves:0
master_failover_state:no-failover
master_replid:560e763bbb458b682bc906053fd01191acc0fc25
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:224
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:224
在6379主机服务器上进行查看:
role:master 代表是主机
connected_slaves:2 代表有2个从机
slave0:ip=127.0.0.1,port=6380,state=online,offset=336,lag=0
代表从机1的IP地址 端口号,状态
slave1:ip=127.0.0.1,port=6381,state=online,offset=336,lag=0
代表从机2的IP地址 端口号,状态
master_failover_state:no-failover
master_replid:560e763bbb458b682bc906053fd01191acc0fc25
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:336
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:336
此时一主2从的服务器就搭建好了。
现进行测试:
在主机上(6379)写,在从机上(6380和6381)可以读取数据
在从机上写数据报错
在主机上写set k100 v100
在从机上查 keys *
在从机上进行写操作,就报错了。
分别在6380和6381上进行写操作,set k99 v99
主从中的三个典型问题:
一主二仆
薪火相传
反客为主
一主二仆
目前有三个redis,有一主6379,两从6380和6381服务器
演示场景:
现在某台从服务器(6380)宕机了。
在主服务器进行查看info replication
:
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=2828,lag=0
master_failover_state:no-failover
master_replid:560e763bbb458b682bc906053fd01191acc0fc25
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2828
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:2828
此时在做主服务器中做添加数据的操作。
set a3 v3
此时主服务器中有2个key,在6381中是可以看到的2个key。
现在将6380的服务器再次启动起来。
在使用info replication
查看6380(重新启动的服务器),变成主服务器了。
特点一:当从服务器宕机之后,再次重启,那么重启后的服务器并不能作为主从中的从服务器进行工作。他不能直接变成从服务器。
现在手动将6380变为从服务器
在主服务器中进行查看
6380中进行查看。
问题:在6380单机的时候,向主服务器中添加了1条数据。
在6380重新启动之后还能看到刚刚添加的数据。
特点二:从服务器宕机后,在重新加入到主从中,那么从服务器就会把主服务器中的数据从头复制到从服务器中。
演示场景:
主服务器宕机了
在从服务中查看:
2个从服务器还是从弄个服务器。只不过状态是主机宕机了。
通俗的说:
当大哥(主服务器)挂掉了,小弟(从服务器)不会谋权篡位。从服务器还是充当从服务器。
现在将主服务器再重新启动:
重新启动后主服务器还是主服务器:
特点三:当主服务器挂掉之后,从服务器还是充当从服务器,主服务器重启后还是主服务器。
主从复制原理:
Slave启动成功连接到master后会发送一个sync命令
Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令, 在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
薪火相传
缺点:当主服务器向从服务器同步的时候,从服务器挂掉了。后面就不能进行数据同步了。因为主服务器无法直接向从服务器下面的服务器进行传输。
演示:
让6379充当主服务器,6380充当6379的从服务器,6381充当6380的从服务器。
查看:
6379:
6380:
6381:
6381的主机就变成6380了。6379的从机只有1台(6380)一个从服务器下面再挂一个从服务器。
特点:
主服务器挂掉了,从服务器还是从服务器,不会越权,主服务器启动之后还是主服务器。
反客为主
当一个master(主机)宕机后,后面的slave(从机)可以立刻升为master(主机),其后面的slave(从机)不用做任何修改。
用 slaveof no one
将从机变为主机。
演示:
6379挂掉了。
此时6380和6381还是从服务器。
现在想让6380充当主服务器,使用命令slaveof no one
实现
缺点:当主机挂掉后,还得手动完成从服务器充当主服务器的操作。
哨兵模式
是什么
反客为主的自动版,
能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
使用步骤
1.调整为一主二仆模式,6379带着6380、6381
2.自定义的/myredis目录下新建sentinel.conf文件,名字绝不能错
3…配置哨兵,填写内容
sentinel monitor mymaster 127.0.0.1 6379 1
其中mymaster为监控对象起的服务器名称,
1 为至少有多少个哨兵同意迁移的数量。
填写完后保存退出即可。
4.启动哨兵
redis-sentinel sentinel.conf
5.当主机挂掉,从机选举中产生新的主机
(大概10秒左右可以看到哨兵窗口日志,切换了新的主机)
哪个从机会被选举为主机呢?
根据优先级别:slave-priority
原主机重启后会变为从机。
开始演示:
现在是一主两从。
当主机挂掉之后,看现象。
哨兵窗口出现如下界面:
解读:
2776906:X 08 Jan 2022 13:31:47.861 # Sentinel ID is 750ee29441dfbaf3e016f43b8c0189e4d9335600
2776906:X 08 Jan 2022 13:31:47.861 # +monitor master mymaster 127.0.0.1 6379 quorum 1
2776906:X 08 Jan 2022 13:31:47.861 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:31:47.872 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:09.395 # +sdown master mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:09.395 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
2776906:X 08 Jan 2022 13:35:09.395 # +new-epoch 1
2776906:X 08 Jan 2022 13:35:09.395 # +try-failover master mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:09.406 # +vote-for-leader 750ee29441dfbaf3e016f43b8c0189e4d9335600 1
2776906:X 08 Jan 2022 13:35:09.406 # +elected-leader master mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:09.406 # +failover-state-select-slave master mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:09.489 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:09.489 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:09.589 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:10.567 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:10.567 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:10.576 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:11.555 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:11.555 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:11.613 # +failover-end master mymaster 127.0.0.1 6379
2776906:X 08 Jan 2022 13:35:11.613 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
2776906:X 08 Jan 2022 13:35:11.613 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380
2776906:X 08 Jan 2022 13:35:11.613 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
2776906:X 08 Jan 2022 13:35:41.627 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
查看:
6381:
6380:
重新启动6379,因为刚刚6379已经挂掉了,此时6379变为从服务器了,主机是6380
再看6380:
此时他的从服务器就是6379和6381
缺点:复制延时
由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
故障恢复
当主机宕机后,从机的选取作为主机的规则。
1.优先级在redis.conf中默认:slave-priority 100,
(redis6中是replice-priority 10)值越小优先级越高
2.偏移量是指获得原主机数据最全的
3.每个redis实例启动后都会随机生成一个40位的runid
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();
}
}