一:redis主从配置
-
1、环境准备
master : 192.168.50.10 6179 slave1: 192.168.50.10 6279 slave2: 192.168.50.10 6379 -
2、redis.conf配置文件配置
-
master
port 6179 requirepass 123456 #密码认证,可以不设置 dir "/var/redis/6179" #工作目录,dump.rdb会保留在这个目录 -
slave1
port 6279 slaveof 192.168.50.10 6179 #master的ip和端口,不能使用127.0.0.1 6179 masterauth 123456 #如果master设置了requirepass,则这里需要配置 slave-read-only yes #默认就是yes dir "/var/redis/6279" -
slave2
port 6379 slaveof 192.168.50.10 6179 #master的ip和端口,不能使用127.0.0.1 6179 masterauth 123456 #如果master设置了requirepass,则这里需要配置 slave-read-only yes #默认就是yes dir "/var/redis/6379"
注意:如果slaveof 127.0.0.1 6179,则链接sentinel时提示是127.0.0.1,无法连接

-
-
3、启动redis并测试 ==> 如果设置了daemonize yes则没有日志输出,默认是no
-
启动: nohup redis-server /redis/redis.conf $1>>/var/log/redis/redis.log 2>&1 &
master 127.0.0.1:6179>info replication

slave1 127.0.0.1:6279>info replication

slave2 127.0.0.1:6379>info replication

-
在master中执行如下语句,如果所有机器执行keys* 都能查出name这个key说明能够复制
127.0.0.1:6179> set name nametest
-
-
4、日志分析
-
slave1和slave2一启动就会去链接master

-
master启动后,接受slave1和slave2的信息同步请求,进行RDB持久化(在内存中持久化)

-
-
5、redis主从同步规则
Salve会发送sync命令到Master Master启动一个后台进程,将Redis中的数据快照保存到文件中 启动后台进程的同时,Master会将保存数据快照期间接收到的写命令缓存起来 Master完成写文件操作后,将该文件发送给Salve Salve将文件保存到磁盘上,然后加载文件到内存恢复数据快照到Salve的Redis上 当Salve完成数据快照的恢复后,Master将这期间收集的写命令发送给Salve端 后续Master收集到的写命令都会通过之前建立的连接,增量发送给salve端总结一下,主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步
注意:在redis2.8开始,slave重新启动,会发送psync到master进行部分同步,而不是sync全量同步
二:Sentinel 组件实现HA配置
-
1、介绍
-
Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,功能类似于zk,用于监控redis master状态,进行切换。
-
sentinel是和redis独立的组件,不需要每个redis节点都启动sentinel,可以在任何机器上部署,只要能够连接redis master即可。
-
其功能类似于zk,用于监听和选举,可以启动多个sentinel作为集群,只要连接的master相同,则认为是统一集群,sentinel集群中各个sentinel也有互相通信,通过gossip协议
-
一个sentinel可以监听多个redis集群,他们是通过连接到redis master,利用发布/订阅功能来发现其他sentinel的存在。
-
-
2、配置参数介绍
-
集群1 mymaster
# 至少2个sentinel认为mymaster挂了,才真正认为是挂了,所以sentinel至少要有2个在运行 sentinel monitor mymaster 192.168.50.10 6179 2 # sentinel向master发送ping,如果在这时间内没有响应,则这个sentinel认为master挂了 sentinel down-after-milliseconds mymaster 60000 # sentinel failover-timeout mymaster 180000 sentinel parallel-syncs mymaster 1 -
集群2 resque
sentinel monitor resque 192.168.50.10 6179 4 sentinel down-after-milliseconds resque 10000 sentinel failover-timeout resque 180000 sentinel parallel-syncs resque 5
-
-
3、工作原理
-
链接master,获取slave和其他sentinel信息,记录到自己的sentinel.conf中,如下图

-
sentinel发现down-after-milliseconds 时间内master没有回复,则认为failor,它会问集群其他sentinel是否也有人认为失败,个数达到sentinel monitor mymaster xxx 2,才会触发failover
-
sentinel集群选举其中一个sentinel拿着一个唯一的版本号去进行master切换。此sentinel指定一个slave发送SLAVE OF NO ONE,将其转化为master,同时将这些配置信息广播给其他sentinel,进行更新master信息

-
-
4、启动 ===> 如果设置了daemonize yes则没有日志输出
nohup redis-server redis-slave1/sentinel.conf --sentinel $1>>/var/log/sentinel/sentinel.log 2>&1 & -
5、失败测试=> 6379变成了6179的redis

-
6、注意
当一个master配置为需要密码才能连接时,客户端和slave在连接时都需要提供密码。 master通过requirepass设置自身的密码,不提供密码无法连接到这个master。 slave通过masterauth来设置访问master时的密码。 但是当使用了sentinel时,由于一个master可能会变成一个slave,一个slave也可能会变成master,所以需要同时设置上述两个配置项。
三:动态切换master测试
-
1、pom依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> -
2、代码
public class JedisSentinelTest { public static void main(String[] args) { /** * 获取master链接~方法一 */ HashSet<String> sentinelSet = new HashSet<>(); sentinelSet.add("192.168.50.10:26179"); // 这个节点目前是挂掉的,也可以配置,后续启动有效 sentinelSet.add("192.168.50.10:26279"); sentinelSet.add("192.168.50.10:26379"); JedisSentinelPool myMasterSentinel = new JedisSentinelPool("mymaster", sentinelSet); Jedis master = myMasterSentinel.getResource(); master.set("aaaa", "aaaTest"); master.close(); /** * 获取master链接~方法二 */ Jedis sentinelNode = new Jedis("192.168.50.10", 26179); List<Map<String, String>> masterList = sentinelNode.sentinelMasters(); Map<String, String> masterMap = null; for (Map<String, String> temp : masterList){ if ("mymaster".equals(temp.get("name"))){ masterMap = temp; break; } } System.out.println("masterIp:" + masterMap.get("ip")); System.out.println("masterPort:" + masterMap.get("port")); List<String> mymaster = sentinelNode.sentinelGetMasterAddrByName("mymaster"); System.out.println("masterIp:" + mymaster.get(0)); System.out.println("masterPort:" + mymaster.get(1)); /** * 获取slaves */ Jedis jedis = new Jedis("192.168.50.10", 26179); List<Map<String, String>> slaves = jedis.sentinelSlaves("mymaster"); for (Map<String, String> temp : slaves){ System.out.println("slaveIp:" + temp.get("ip")); System.out.println("slaveIp:" + temp.get("port")); } /** * 主从切换 */ Map<String, String> first = slaves.get(0); Jedis toBeMaster = new Jedis(first.get("ip"), Integer.parseInt(first.get("port"))); String flag = toBeMaster.slaveofNoOne(); // 将自己设置为主节点 for (int i = 1; i < slaves.size(); i++){ Map<String, String> temp = slaves.get(i); Jedis ortherSlave = new Jedis(temp.get("ip"), Integer.parseInt(temp.get("port"))); ortherSlave.slaveof(first.get("ip"), Integer.parseInt(first.get("port"))); } Jedis slave = new Jedis("192.168.50.10", 6279); /** * 重新加载配置信息,复原 */ slave.configResetStat(); /** * 手动触发RDB(save、bgsave)以及aof rewrite */ slave.save(); slave.bgsave(); slave.bgrewriteaof(); /** * 获取信息,可以知道自己是什么角色 */ String info = slave.info(); String replication = slave.info("replication"); } }
来源:oschina
链接:https://my.oschina.net/u/3062408/blog/3026883








