redis主从复制以及哨兵机制

7 Redis的主从复制

7.1 什么是主从复制

持久化保证了即使redis服务重启也不会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到内存中,但是当redis服务器的硬盘损坏了可能会导致数据丢失,如果通过redis的主从复制机制就可以避免这种单点故障,如下图:

图1

说明:

  • 主redis中的数据有两个副本(replication)即从redis1和从redis2,即使一台redis服务器宕机其它两台redis服务也可以继续提供服务。
  • 主redis中的数据和从redis上的数据保持实时同步,当主redis写入数据时通过主从复制机制会复制到两个从redis服务上。
  • 只有一个主redis,可以有多个从redis。
  • 主从复制不会阻塞master,在同步数据时,master 可以继续处理client 请求
  • 一个redis可以即是主又是从,如下图:
    图2

7.2 主从配置
7.2.1 主redis配置
无需特殊配置。

7.2.2 从redis配置
方式一:修改从redis服务器上的redis.conf文件

# slaveof <masterip> <masterport>
slaveof 127.0.0.1 6379

上边的配置说明当前该【从redis服务器】所对应的【主redis服务器】的IP是192.168.101.3,端口是6379

方式2:动态设置

通过redis-cli 连接到从节点服务器,执行下面命令即可。
slaveof 192.168.33.130 6379
演示结果和手动方式一致。

主从复制过程

这里写图片描述

过程:
1:当一个从数据库启动时,会向主数据库发送sync命令,
2:主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并将保存期间接收到的命令缓存起来
3:当快照完成后,redis会将快照文件和所有缓存的命令发送给从数据库。
4:从数据库收到后,会载入快照文件并执行收到的缓存的命令。

注意:redis2.8之前的版本:当主从数据库同步的时候从数据库因为网络原因断开重连后会重新执行上述操作,不支持断点续传。
redis2.8之后支持断点续传。

redis的Sentinel(哨兵机制)

sentinel功能

redis的sentinel系统用于管理多个redis服务器,该系统主要执行三个任务:监控、提醒、自动故障转移。

1、监控(Monitoring): Redis Sentinel实时监控主服务器和从服务器运行状态,并且实现自动切换。
2、提醒(Notification):当被监控的某个 Redis 服务器出现问题时, Redis Sentinel 可以向系统管理员发送通知, 也可以通过 API 向其他程序发送通知。
3、自动故障转移(Automatic failover): 当一个主服务器不能正常工作时,Redis Sentinel 可以将一个从服务器升级为主服务器, 并对其他从服务器进行配置,让它们使用新的主服务器。当应用程序连接Redis 服务器时, Redis Sentinel会告之新的主服务器地址和端口。

注意:在使用sentinel监控主从节点的时候,从节点需要是使用动态方式配置的,如果直接修改配置文件,后期sentinel实现故障转移的时候会出问题。

图示sentinel
这里写图片描述

主观下线和客观下线:
1、主观下线状态:当一个sentinel认为一个redis服务连接不上的时候,会给这个服务打个标记为下线状态。
2、客观下线状态:当多个sentinel认为一个redids连接不上的时候,则认为这个redis服务确实下线了。这里的多个sentinel的个数可以在配置文件中设置。

主节点:主观下线和客观下线
从节点:主观下线状态

sentinel配置

修改sentinel.conf文件

[python] view plain copy
sentinel monitor mymaster 192.168.33.130 6379 2     #最后一个参数视情况决定  

这里写图片描述
最后一个参数为需要判定客观下线所需的主观下线sentinel个数,这个参数不可以大于sentinel个数。

启动sentinel

[python] view plain copy
redis-sentinel sentinel.conf

启动后结果图示:
这里写图片描述

sentinel日志明细说明
http://redisdoc.com/topic/sentinel.html

通过订阅指定的频道信息,当服务器出现故障得时候通知管理员
客户端可以将 Sentinel 看作是一个只提供了订阅功能的 Redis 服务器,你不可以使用 PUBLISH 命令向这个服务器发送信息,但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通过订阅给定的频道来获取相应的事件提醒。
一个频道能够接收和这个频道的名字相同的事件。 比如说, 名为 +sdown 的频道就可以接收所有实例进入主观下线(SDOWN)状态的事件。

sentinel的一些命令

[python] view plain copy
INFO  

sentinel的基本状态信息

[python] view plain copy
SENTINEL masters  

列出所有被监视的主服务器,以及这些主服务器的当前状态

[python] view plain copy
SENTINEL slaves <master name>  

列出给定主服务器的所有从服务器,以及这些从服务器的当前状态

[python] view plain copy
SENTINEL get-master-addr-by-name <master name>  

返回给定名字的主服务器的 IP 地址和端口号

[python] view plain copy
SENTINEL reset <pattern>  

重置所有名字和给定模式 pattern 相匹配的主服务器。重置操作清除主服务器目前的所有状态, 包括正在执行中的故障转移, 并移除目前已经发现和关联的, 主服务器的所有从服务器和 Sentinel 。

[python] view plain copy
SENTINEL failover <master name>  

当主服务器失效时, 在不询问其他 Sentinel 意见的情况下, 强制开始一次自动故障迁移,但是它会给其他sentinel发送一个最新的配置,其他sentinel会根据这个配置进行更新

java操作sentinel

代码示例:

[java] view plain copy
import java.util.HashSet;  
//需要在pom.xml文件中引入jedis依赖  
import redis.clients.jedis.HostAndPort;  
import redis.clients.jedis.Jedis;  
import redis.clients.jedis.JedisPoolConfig;  
import redis.clients.jedis.JedisSentinelPool;  

public class SentinelTest {  

    public static void main(String[] args) {  
        // 使用HashSet添加多个sentinel  
        HashSet<String> sentinels = new HashSet<String>();  
        // 添加sentinel主机和端口  
        sentinels.add("192.168.33.131:26379");  

        // 创建config  
        JedisPoolConfig poolConfig = new JedisPoolConfig();  
        // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。  
        poolConfig.setMaxIdle(10);  
        // 控制一个pool最多有多少个jedis实例。  
        poolConfig.setMaxTotal(100);  
        // 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;  
        poolConfig.setMaxWaitMillis(2000);  
        // 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;  
        poolConfig.setTestOnBorrow(true);  

        // 通过Jedis连接池创建一个Sentinel连接池  
        JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels,poolConfig);  
        // 获取master的主机和端口  
        HostAndPort currentHostMaster = pool.getCurrentHostMaster();  
        System.out.println(currentHostMaster.getHost() + "--"+ currentHostMaster.getPort());  
        // 从Sentinel池中获取资源  
        Jedis resource = pool.getResource();  
        // 打印资源中key为name的值  
        System.out.println(resource.get("name"));  
        // 关闭资源  
        resource.close();  
    }  
}  
打印结果:

参考文章:http://blog.csdn.net/u011204847/article/details/51307044

posted @ 2017-11-01 22:31  lin819747263  阅读(149)  评论(0编辑  收藏  举报