主从复制:主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master主服务器以写为主,Slave从服务器以读为主。如下图:
两个优势:
如果只有一台服务器,读和写操作都在一台服务器上进行,这台服务器的压力就会很大。而使用主从复制可以达到读写分离效果,写操作都在master主服务器进行,写操作进行完成之后,把内容复制到它的从服务器去;读操作都在slave从服务器进行。
如果主服务器中进行写操作之后,复制到了从服务器(从服务器一般有多台),如果第一台从服务器在读的过程中突然挂掉,就会切换到另外一台从服务器进行读操作,此即为容灾快速恢复。
一个缺陷:
主从复制存在的缺点是复制延时:
由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
注意:
“领导多了,员工不知道听谁的。”—因此:主从一般都为一主多从。主服务器只能有一个。
在一台服务器上,搭建一主两从的模拟环境。(因为是一台服务器,因此要保证三者的端口不同)操作如下:
①为了方便先创建一个myRedis的文件夹
②复制Redis.conf文件到此文件夹
③配置一主两从,创建三个配置文件:redis6379.conf、redis6380.conf、redis6381.conf(保证三者端口不同)
④由于redis配置文件redis.conf中有公共配置部分,所以在三个新建的配置文件中只需要引入公共配置(使用include),其他不同的地方(进程号pid、端口号、rdb持久化文件的名称)进行单独配置。
配置完成后 :wq 保存退出
⑤启动三台Redis服务器
注意:如果本机的redis服务器也为6379,就会和此处用于演示的redis6379服务器冲突,可以使用kill命令先关闭原有的reis进程,再开启我们自定义的myredis目录下用于演示的redis6379服务器。
redis-server redis6379.conf:根据配置文件启动相应的Redis服务器。 如下图:
redis-cli -p 端口号:通过端口号连接Redis服务器。 如下图:
info replication:打印主从复制的相关信息,用来查看运行情况。 如下图:
注意:此命令需要连上Redis后使用。 如下图:
目前虽然启动了三台Redis服务器,但此时并没有主从的效果。想要实现主从,还需要在目标从服务器使用slaveof命令
要想设置6379为主机,6380、6381为从机:需要
在从机上
使用slaveof命令进行配置。(小弟认大哥的过程,小弟要主动)
一主两从效果搭建完成。如下图:
搭建好一主二从之后,进行测试。
在主服务器中进行写操作,可以在从服务器中成功读到。如下图:
特殊情形一:
一主(6379)二从(6380、6381)。如果某一台从服务器(如6380)挂掉(可以使用shutdown命令)了,还会剩一个6381从服务器正常运行。此时在主服务器(6379)中添加数据,如下图:
正常运行的从服务器(6381)可以读到数据,如下图:
若此时把挂掉的6380从服务器再次启动起来(redis-server redis6380.conf),连接Redis(redis-cli -p 6380),查看6380Redis服务器状态信息(info replication)会出现什么效果?如下图:
此时若想让6380Redis服务器继续做6379主服务器的从服务器可以使用slaveof命令,如下图:
此时查看6380Redis服务器中的key值信息,如下图:
也就是说,如果主机在从服务器挂掉之后修改了数据,再把挂掉的服务器 **作为主机的从服务器重新启动** ,主机中的最新的数据依然会被复制到从服务器中去。
就好比 “只要小弟(从服务器)做大哥(主服务器)的人,大哥有什么资源都会毫无保留地和小弟分享。”
特殊情形二:
如果6379主服务器挂掉了,如下图:
查看从服务器(6380、6381)的状态信息(info replication),如下图:
查看后发现,从服务器的角色依然为从服务器,并没有“篡位”变为主服务器。
再次对6379主服务器进行启动(redis-server redis6379.conf),连接(redis-cli -p 6379),查看信息(info replication)。如下图:
也就是说,即使6379主服务器挂掉了,6380和6381两个服务器的角色依然是从服务器,而且认为主服务器依然为6379。(大哥永远是大哥)
就好比,“即使大哥挂掉了,小弟依然把他当作大哥,并不会上位。”
从服务器只在第一次主动请求同步,其他大部分过程都是主服务器发起的。
了解两个概念:
- 全量复制: 从服务器在接收到数据库文件数据后,将其存盘**并加载到内存中。
- 增量复制: 主服务器继续将 新的所有收集到的修改命令 依次传给slave,完成同步。
只要是重新连接主服务器,就会自动进行一次完全同步(全量复制)
上一个Slave从服务器可以是下一个slave从服务器的主服务器。Slave从服务器同样可以接收其他slave从服务器(可以是多个)的连接和同步请求,那么该slave从服务器作为了链条中下一个slave从服务器的主服务器,可以有效减轻master的写压力,去中心化降低风险。类似数据结构中的树形结构,等级森严。
这种薪火相传的模式肯定会有一个缺点:如果某一个从服务器挂掉了,它下面的服务器就不能再进行数据同步。
当一个主服务器挂掉后,手动把后面的从服务器升级为主服务器,其后面的从服务器不用做任何修改。
效果演示:
①让6379主服务器挂掉(shutdown)
②查看6381从服务器的状态信息(info replication)
③手动让6380从服务器“上位”,变为主服务器(slaveof no one)
④查看6380服务器的状态信息
slaveof no one:把从机变为主机
此即为反客为主
这种 反客为主模式会有一个缺点:需要手动完成。 如果服务器大半夜挂掉了,还需要我们大半夜爬起来去手动切换,很不方便。
能不能让这个过程自动完成?实现主服务器如果挂掉了,从服务器立马挑起大梁,晋升为主服务器。
此即为接下来要介绍的哨兵模式实现的效果。
哨兵模式即为反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
演示:
调整到一主二从状态进行演示:
配置哨兵(sentinel):
①在自定义的/myredis目录下新建sentinel.conf文件,名字绝不能错
②写入内容:
sentinel monitor mymaster 服务器ip 端口号 1:其中mymaster为监控对象起的服务器名称;最后的参数表示至少有多少个哨兵同意迁移的数量。(此处最后参数为1则表示只要有一个哨兵同意就能进行切换)
③启动哨兵(redis-sentinel /myredis/sentinel.conf )
最终切换为主机的服务器是从被监视服务器的从服务器中取。
④关闭6379主服务器
⑤哨兵监控窗口信息如下:
⑥查看6381服务器状态
此时连接的从服务器(connected_slaves)只有一个6380,因为6379还没有重新启动。
⑦查看6380服务器状态
⑧重启6379服务器,并查看状态信息
总结哨兵模式:
①选择优先级高的从服务器作为主服务器(值越小,优先级越高)
在redis的配置文件中都会有相应的优先级(默认值为100),如下图:
②如果优先级相同,选择偏移量最大的从服务器作为主服务器
即两台从服务器中,和主机的的数据同步程度最高的从服务器,偏移量较大,更适合转化为主服务器。
③如果优先级和偏移量都相同,选择runid最小的从服务器作为主服务器
每个redis实例启动后都会随机生成一个40位的runid。选择runid最小的
想使用Java代码实现主从操作特点,可以使用JedisSentinelPool连接池。
JedisSentinelPool模板如下:
private static JedisSentinelPool jedisSentinelPool = null;
public static Jedis getJedisFromSentinel() {
if (jedisSentinelPool == null) {
Set<String> sentinelSet = new HashSet<>();
sentinelSet.add("47.116.4.200:26379"); //服务器ip:哨兵端口号(默认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, "******"); //如果Redis服务器配置了密码,需要在最后一个参数写入密码
return jedisSentinelPool.getResource();
} else {
return jedisSentinelPool.getResource();
}
}
注意:想要使用如上哨兵模式连接池,需要在服务器上配置26379端口的安全组或使用宝塔面板放行26379端口、还要确保哨兵服务器的正常运行状态。否则上述程序无法运行成功。