1. 主从复制中存在的问题:java
2. Redis Sentinal主要就是解决了主从复制中的手动故障转移所带来的麻烦,从而实现了自动故障转移,主从复制中的故障转移问题详见上一篇博客Redis应用学习(六)——主从复制,Redis Sentinal就是负责监控全部的主从节点、实现自动故障转移流程而且通知客户端故障迁移(客户端故障迁移指客户端所链接的Redis发生了故障,客户端的链接会迁移到另外一个正常的Redis上),但注意,sentinel只能对主节点进行故障转移和通知客户端迁移链接,对于从节点,sentinel没法进行故障转移,也没法通知客户端进行链接迁移,只能对其作一个下线操做。linux
1. Redis Sentinal架构:多个Sentinal节点构成一个Redis Sentinal,每一个Sentinal节点都会监控着Redis中的每个主从节点,多个Sentinal节点组成Redis Sentinal功能提供了Redis Sentinal功能的高可用型,好比当某个Sentinal节点判断Redis主节点为故障时,其余Sentinal节点也会测试该Redis主节点是否故障,进行一个相似于投票的过程,若是投票结果肯定该Redis主节点确实故障,那么就会进行故障转移,并且即使某个Sentinal节点发生故障,其余的Sentinal节点也能保持Redis Sentinal功能的正常运行。而对于客户端来讲,其不须要记录(直连)某个Redis节点的信息(IP地址和端口等)来进行读写,而是记录Redis Sentinal的信息(IP地址和端口等)进行交互redis
2. Sentinal节点:每一个Sentinal节点实际上就至关于一个特殊的Redis,可是不能存储数据,默认占用端口26379,能够经过一个配置文件来修改启动的相关配置apache
3. Sentinal对于主节点故障的处理:大体原理过程和手动过程相似,可是是由Sentinal自动完成的,从节点故障不会进行故障转移和通知客户端进行链接迁移centos
4. 一个Redis Sentinal能够监控多套主从节点,详细实现下面会进行说明。架构
1. 安装过程:运维
sentinel parallel-syncs master-name count:当主节点master-name被肯定为故障时,就会发生故障转移,此时某个从节点就会被sentinel设置为新的主节点,其余从节点就会从新和该新主节点创建主从关系,而且每一个从节点都会和新主节点执行一次全量复制,然后面的参数count就表示是同时只容许count个从节点进行全量复制dom
sentinel failover-timeout master-name number:进行故障转移的时间性能
daemonize yes:表示进行启动sentinel节点以守护线程方式启动学习
1. Sentinal的服务端与客户端的高可用:若是Sentinal不能实现主节点自动故障转移后通知客户端,那么Sentinal功能就仅仅只是实现了服务端的高可用,好比发生故障迁移后新的Redis节点IP地址和端口号不发送给客户端,那么Sentinal所实现的自动故障转移对于客户端来讲至关于无效的,因此Sentinal还会在自动故障转移以后,通知客户端Redis主节点的变化,并返回信息,使得客户端也得以作出相应的改变从新链接到新的Redis主节点,那么就能够实现客户端的高可用。
2. 经过Redis Sentinal实现客户端高可用的原理:
3. Java客户端jedis实现对Redis Sentinal监控下的Redis主节点的链接以及发送命令:jedis客户端的实现原理基本与上面所写吻合,示例代码
import java.util.LinkedHashSet; import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisSentinelPool; /** * @ClassName:TestJedisSentinelPool * @Description:链接由Redis Sentinel监视的Redis主节点 */ public class TestJedisSentinelPool { //注意,Dubug测试该方法时要保证linux系统的防火墙关闭(centos7关闭指令为systemctl stop firewalld) public static void main(String[] args) { /* * 建立一个jedis链接池,不过该链接池建立的jedis对象所链接的Redis是被Sentinel监控的主节点 * masterName表示Sentinel配置中的Redis主节点名 * sentinels表示全部的Sentinel节点的IP地址与端口号信息 * poolConfig表示该链接池的相关配置参数 */ String masterName="mymaster"; Set<String> sentinels=new LinkedHashSet<String>(); sentinels.add("192.168.10.128:26380"); sentinels.add("192.168.10.128:26381"); sentinels.add("192.168.10.128:26382"); GenericObjectPoolConfig poolConfig=new GenericObjectPoolConfig(); JedisSentinelPool pool=new JedisSentinelPool(masterName, sentinels, poolConfig); Jedis jedis=null; try { //注意,这里返回的jedis对象链接的仍然是Redis节点,并非sentinel节点 jedis=pool.getResource(); //经过jedis就能够执行Redis的相关命令 String response=jedis.set("user", "lisi"); System.out.println(response); } catch (Exception e) { // 异常处理 }finally { if(jedis!=null){ //回收jedis链接对象 jedis.close(); } } } }
Debug测试结果截图:
4. 模拟故障转移,观察jedis客户端的变化:要观察这种变化,须要模拟真正应用环境中,jedis客户端会不停的执行一些操做,因此更改上面的示例代码,添加一个while死循环来生成随机数,而后运行客户端测试程序,而后关闭linux系统中的Redis主节点,就能够观察到jedis中的变化,观察到服务端故障转移的过程,一旦链接的Redis主节点故障,客户端就会一直报错,可是报错一段时间以后又会中止报错继续成功执行,这个变化就是服务端自动故障转移的表现。
//测试观察服务端自动故障转移在客户端的表现 public void test(){ String masterName="mymaster"; Set<String> sentinels=new LinkedHashSet<String>(); sentinels.add("192.168.10.128:26380"); sentinels.add("192.168.10.128:26381"); sentinels.add("192.168.10.128:26382"); GenericObjectPoolConfig poolConfig=new GenericObjectPoolConfig(); JedisSentinelPool pool=new JedisSentinelPool(masterName, sentinels, poolConfig); Jedis jedis=null; Random rand=new Random(); String key=null; int value=0; int count=0; while(true){ count++; try { value=rand.nextInt(10000); key="key-"+value; jedis=pool.getResource(); String response=jedis.set(key, value+""); //每隔1秒输出一次成功执行的结果 if(count%100==0){ System.out.println("set "+key+":"+value+" "+response); } TimeUnit.MILLISECONDS.sleep(10);//每10毫秒执行一次循环 } catch (Exception e) { // 错误提示 System.out.println("set "+key+":"+value+" failed"); //sentinel断定Redis主节点是否为故障,若是肯定主节点故障,则进行自动故障转移 System.out.println("服务端Redis节点异常,判断是否进行自动故障转移"); }finally { if(jedis!=null){ //回收jedis链接对象 jedis.close(); } } } }
1. 三个定时任务:三个定时任务实现了自动故障转移中最重要的故障检测,经过如下三个定时任务就能发现出现故障的各个节点
2. 主观下线和客观下线:两个相关配置参数
3. 领导者选举:上面说过,在进行自动故障转移以前,sentinel节点群必需要选出一个sentinel节点做为领导者,领导者来执行故障转移操做
4. 故障转移中的从节点选择:在故障转移中,若是主节点确认下线,那么则须要选择一个从节点来做为新的主节点,选择规则有
1. 节点运维:就是节点的手动上线和下线操做,针对的目标是Redis主节点、从节点和sentinel节点。
2. 节点运维解决的问题:当下面这些问题发生时,应该由手动执行节点的上下线操做来进行一个故障转移
3. 对于主节点的下线:手动指定一个sentinel节点做为领导者,并对指定的Redis主节点进行故障转移:sentinel failover master-name,在某个sentinel节点的客户端运行该命令就是指定该sentinel节点为领导者,而且对其所监控的master-name节点进行故障转移
4. 对于从节点的下线:首先须要肯定是临时下线(暂时关闭该节点,以后还会进行重启)仍是永久下线(再也不使用这台机器做为一个从节点提供服务),下线后是否须要进行一些清理工做,好比从节点的一些配置,AOF、RDB以及日志文件的清理,好比若是要临时下线来启动一下其余进程,要保证从节点的相关配置不会干扰到新进程的运行。此外,从节点的下线还要考虑读写分离的问题。
5. 对于sentinel节点的下线:与从节点相似
6. 节点上线:对于Redis主节点的上线,一样使用sentinel failover命令切换主节点便可;而对于从节点的上线使用slaveof命令将该从节点关联到主节点便可,sentinel会自动感知;对于sentinel节点的上线,只须要写好配置文件直接启动便可。
1. Redis Sentinal中读写分离存在的问题:客户端链接到一个从节点只进行读操做,但若是该从节点下线后,客户端没法获知下线信息,也没法将链接转移到另外一个从节点上,由于sentinel只对从节点进行一个主观下线操做,但不会通知客户端从节点的下线信息,也就没法作客户端链接迁移(将链接原从节点的客户端转移到另外一个从节点上)。
2. 要实现高可用的读写分离,客户端就要知道从节点变化的三个消息:
3. 实现原理:链接从节点的客户端必须能感知到全部从节点的变化,也就是上面的三条消息,可是Java客户端里并无提供这种从节点的读写分离实现,须要咱们本身去实现,能够参考JedisSentinelPool的实现来手动编写一个从节点高可用链接池。但很明显,sentinel环境下实现读写分离的高可用很是复杂,对于性能提升、容量扩展的时候,这种方式是比较复杂的,因此,推荐使用集群(redis-cluster)。