1. 主从复制简介
主机数据更新后根据配置和策略, 自动同步到备机(从机)的 master/slaver 机制,Master 以写为主,Slave 以读为主。
优点:
- 读写分离,性能扩展。读写操作都在同一台服务器压力很大。
- 容灾快速恢复。当一台从机挂掉之后,可以从其他从机读取。
2. 一主二从案例
配置一个一主机两从机的案例:
1、创建 /myredis 文件夹:mkdir /myredis
2、复制 redis.conf 配置文件到文件夹 /myredis:cp /etc/redis.conf /myredis/redis.conf
3、因为要搭建一个一主两从的案例,所以要在3个端口都启动 redis 服务,需要创建 3 个配置文件,分别取名为 redis6379.conf、redis6380.conf 和 redis6381.conf:
4、在三个配置文件中分别写入配置内容:
include /myredis/redis.conf # 表示引入 /myredis/redis.conf 配置文件
pidfile /var/run/redis_端口号.pid # 覆盖 /myredis/redis.conf 配置文件的 pidfile 设置,下面同理
port 端口号
dbfilename dump端口号.rdb
以 redis6379.conf 为例,其他两个同理:
5、启动 3 个 redis 服务:
此时3个 redis 服务还没有配置主从之分。服务启动后可以通过 redis-cli -p 端口号
来连接 3 个 redis 服务,连接之后,通过 info replication
指令来查看当前redis服务运行情况:
6、建立主从关系。在从机上执行 slaveof 主机ip 端口号
,使当前 redis 实例成为某个 redis 实例的从服务器:
在 6381 端口的redis也执行上述操作。然后在 6379 主机里面可以看到:
7、在主机上写入数据,在从机上可以读取数据:
3. 一些知识
3.1 主从复制原理
主机挂掉,重启就行,一切如初。即当主机关闭后,从机仍然可以读取数据;当主机重启后,仍然与之前的从机保持主从关系。
从机关机,重启后需重新设置 slaveof 主机IP 端口号
,使其成为某个主机的从机,并且主机的所有数据会同步到新连接的从机上。也可以将配置增加到文件中,永久生效。
实际上从机重启后相当于新开的 redis 实例,默认是一个主机。
主从复制原理(数据同步的原理):
- 当从机(从服务器)连接上主机(主服务器)之后,从机会向主机发送请求数据同步的消息。
- 主机接到从机发送过来的消息后,会把主机数据进行持久化,形成 rdb 文件,然后把 rdb 文件发送给从机,从机拿到 rdb 文件进行读取并进行数据同步。这个过程又叫做全量复制。
- 每次主机进行写操作之后,会主动和从机进行数据同步。这个过程又叫做增量复制。
3.2 复制延时
由于所有的写操作都是先在 Master上操作,然后同步更新到 Slave上,所以从 Master 同步到 Slave 机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave 机器数量的增加也会使这个问题更加严重。
3.3 薪火相传
一个主机可以有多个从机,一个从机也可以成为其他从机的主机,这样可以有效减轻主机的写压力,去中心化降低风险。
某个服务器中途变更转向(成为某个主机的从机),会清除之前的数据,重新建立拷贝最新的。
风险是一旦某个从机宕机,该从机后面的从机都没法备份。
主机挂了,从机还是从机,无法写数据。
使用的指令仍然是:slaveof 主机IP 端口号
,案例如下:
3.4 反从为主
当一个 master 宕机后,后面的 slave 可以立刻升为 master,而该 slave 后面的 slave 不用做任何修改。用 slaveof no one
将从机变为主机。
案例如下:
注意:虽然上面的6380与6379断开了从主关系,但是6380中仍然有6379的数据,并且6380现在作为主机,可以进行写操作了。
在项目上线后,如果主机挂掉,那么就没法进行写操作了,此时需要让一个从机上位成为主机,而这一过程的手动设置就是上面的案例,实际上通常是让某个从机自动成为主机,这是通过第4节的哨兵模式实现的。
4. 哨兵模式
所谓的哨兵模式,简而言之就是反客为主的自动版。哨兵模式能够在后台自动监控主机是否故障,如果故障了则根据投票数自动将从库转换为主库。
案例如下:
1、首先配置一个一主二从的环境,跟第2节一样,6379端口启动主机redis,6380和6381启动从机redis。
2、在自定义目录 /myredis 下新建一个 sentinel.conf,作为哨兵模式的配置文件,注意名字绝对不能错。输入内容如下:
上面是配置:
sentinel monitor <master-name> <ip> <redis-port> <quorum>
分别是 主节点名字、主节点的 IP 地址和端口号以及 quorum 值
- sentinel monitor mymaster 表示作为哨兵来监控主机 mymaster,其中 mymaster 是给监控对象起的服务器名称,127.0.0.1 6379 是要监控的主机的IP和端口。最后面的 1 表示至少有多少个哨兵同意迁移的数量(这里设置为1)。
3、启动哨兵:
4、当主机挂掉,从机选举中产生新的主机。当 shutdown 6379后,哨兵输出日志内容如下:
因为上面将 6379(原主机)作为了6380(现主机)的从机,所以6379再次启动后,将会自动成为 6380 的从机。
注意:主机挂掉后,哨兵会根据从机的优先级别:slave-priority,来选择谁是新的主机。
整个流程如下:
-
优先级在 redis.conf 中,默认配置是:replica-priority 100,值越小优先级越高:
偏移量大的从机,是指获得原主机数据最全的从机。
每个redis实例启动后都会随机生成一个40位的runid。
在哨兵模式中,如何写java代码来识别哪个是主机哪个是从机呢,实际上就只需要改一下jedis连接池部分即可,如下:
private static JedisSentinelPool jedisSentinelPool=null;
//下面这个方法得到的 jedis就可以实现主从复制或者说主从操作的特点
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);//指定主机的名字为“mymaster”
return jedisSentinelPool.getResource();
}else{
return jedisSentinelPool.getResource();
}
}
(“mymaster”, sentinelSet, jedisPoolConfig);//指定主机的名字为“mymaster”
return jedisSentinelPool.getResource();
}else{
return jedisSentinelPool.getResource();
}
}