Redis单机搭建主从

Redis单机主从切换部署说明


准备工作

redis.io下载部署包 :redis-3.2.8.tar.gz

新建主从目录

make -p /usr/local/redis/master/

make -p /usr/local/redis/slave/

分别在两个目录下面安装redis

tar –zxf redis-3.2.8.tar.gz

cd redis-3.2.8

make #编译

make test #期望全部测试通过

可能出现问题:缺少gcc或者tcl组件,使用命令yum install gcc或者 yum install tcl

修改配置参数

修改master_redis配置

cd /usr/local/redis/master/redis-3.2.8/

vi redis.conf

bind 127.0.0.1 —-> bind 本机IP(绑定地址)

daemonize no —-> daemonize yes(不影响当前会话,启动过程隐藏,守护进程)

protected-mode yes —> protected-mode no(关闭保护模式,其他服务器可访问)

修改slave_redis配置

cd /usr/local/redis/slave/redis-3.2.8/

vi redis.conf

bind 127.0.0.1 —-> bind 本机IP(绑定地址)

daemonize no —-> daemonize yes(不影响当前会话,启动过程隐藏,守护进程)

protected-mode yes —> protected-mode no(关闭保护模式,其他服务器可访问)

port 6379 —> port 6380(修改端口)

slaveof master_redis所在机器IP 6379

pidfile /var/run/redis_ 6379.pid —-> pidfile /var/run/redis_ 6380.pid

redis以守护进程方式运行时,系统默认会把pid写入/var/run/redis.pid,可以通过pidfile指 定pid文件

启动master_ redis和slave_ redis并使用客户端连接

cd /usr/local/redis/master/redis-3.2.8/src/

./redis-server /usr/local/redis/master/redis-3.2.8/redis.conf(加载配置文件)

./redis-cli -h IP -p 6379 (客户端连接master_redis)

cd /usr/local/redis/slave/redis-3.2.8/src/

./redis-server /usr/local/redis/slave/redis-3.2.8/redis.conf(加载配置文件)

./redis-cli -h IP -p 6380 (客户端连接slave_redis)

使用 info 命令查看redis主从信息

master_redis客户端连接下执行: info replication

显示:role:master connected_slaves:1

slave_redis客户端连接下执行: info replication

显示:role:slave master_ link_ status:up

测试主从复制,读写分离

master_redis客户端连接下执行:set name zhangsan

master_redis客户端连接下执行:get name 结果: zhangsan

slave_redis客户端连接下执行:get name 结果: zhangsan

slave_redis客户端连接下执行:set name lisi

(error)READONLY You can`t write against a read only slave.(slave_redis只读)

配置主从切换

准备sentinel.conf配置文件

    #守护进程,隐藏启动,不影响当前session
    daemonize yes  

    #关闭保护模式,类似于防火墙的功能
    protected-mode no   

    #sentinel 端口默认26379
    port  

    #哨兵监控的主redis 的IP 和端口,会自动监控到slave
    #sentinel monitor <master-name> <ip> <redis-port> <quorum>
    #告诉sentinel去监听地址为ip:port的一个master,quorum是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效         
    sentinel monitor master1 IP 6379 1

    #master被当前sentinel实例认定为“失效”的间隔时间.
    #sentinel down-after-milliseconds <mastername> <millseconds>  
    #如果当前sentinel与master直接的通讯中(不断发送程序包,并接受响应),在指定时间内没有响应或者响应错误代码,那么当前sentinel就认为master失效  
    sentinel down-after-milliseconds master1 5000

    #当failover(故障转移)开始后,在此时间内仍然没有触发任何failover操作,当前sentinel将会认为此次failover失败
    sentinel failover-timeout master1 15000

    #当新master产生时,可以同时进行slaveof到新master并进行“SYNC”(同步)的slave个数。(建议使用默认值1)
    #在salve执行salveof与同步时,将会终止客户端请求。此值较大,意味着“集群”终止客户端请求的时间总和和较大.
    #此值较小,意味着“集群”在故障转移期间,多个salve向客户端提供服务时仍然使用旧数据.
    sentinel parallel-syncs master1 1

配置主从切换

ps -ef | grep redis kill掉当前所有redis进程

rm -f /usr/local/redis/master/redis-3.2.8/sentinel.conf

rm -f /usr/local/redis/slave/redis-3.2.8/sentinel.conf

将准备好的sentinel.conf分别放置于对应目录下面(替换刚刚删除的两个conf文件)

cd /usr/local/redis/slave/redis-3.2.8/

vi sentinel.conf 修改 port 26379 —> port 26380

重新启动主从redis

cd /usr/local/redis/master/redis-3.2.8/src/

./redis-server /usr/local/redis/master/redis-3.2.8/redis.conf

cd /usr/local/redis/slave/redis-3.2.8/src/

./redis-server /usr/local/redis/slave/redis-3.2.8/redis.conf

启动主从redis的sentinel(哨兵)

cd /usr/local/redis/master/redis-3.2.8/src/

./redis-sentinel /usr/local/redis/master/redis-3.2.8/sentinel.conf

cd /usr/local/redis/slave/redis-3.2.8/src/

./redis-sentinel /usr/local/redis/slave/redis-3.2.8/sentienl.conf

ps -ef | grep redis 此时应该有四个进程(redis主从 + 两个哨兵)

使用客户端查看哨兵监控情况

使用客户端连接两个sentinel

cd /usr/local/redis/master/redis-3.2.8/src/

./redis-cli -h IP 26379

cd /usr/local/redis/slave/redis-3.2.8/src/

./redis-cli -h IP 26380

使用 info sentinel查看稍定监控详情,显示name=master1,status=ok,address=IP:6379(两个哨兵共同监控master_redis)

测试主从自动切换(具体操作参考上面命令)

kill 掉master_redis服务

然后使用客户端连接slave_redis

使用info replication 查看slave_ redis连接信息,会发现,slave_ redis已经升级为master_ redis

再使用客户端重新连接sentinel,使用info sentinel命令查看两个哨兵监控信息,会发现监控地址变成了address=IP:6380

重新启动kill 掉的master_ redis服务,启动后客户端连接,使用info replication命令查看,会发现role:slave (重新启动后自动变成slave_ redis)

Java代码实现redis主从

public class JedisUtil {


 private final static String REDIS_HOST = "172.20.1.47";
 private final static Integer REDIS_PORT = 6379;
 private final static Integer REDIS_MaxActive = 200;
 private final static Integer REDIS_MaxIdle = 1000;
 private final static Integer REDIS_MaxWait = 512;
 private final static Integer REDIS_ConnTimeout = 2000;
 private final static Integer REDIS_RetryNum = 3;
 private final static String SENTINEL_HOST_1 = "172.20.1.47:26381";
 private final static String SENTINEL_HOST_2 = "172.20.1.47:26380";
 private final static String CLUSTER_NAME = "master1";

/**
 * 私有构造器.
 */
private JedisUtil() {

}

private static Map<String, JedisSentinelPool> maps = new HashMap<String, JedisSentinelPool>();

/**
 * 获取连接池.
 * 
 * @return 连接池实例
 */
private static JedisSentinelPool getPool() {
    String key = REDIS_HOST + ":" + REDIS_PORT;
    Set<String> sentinels = new HashSet<String>();
    String hostAndPort1 = SENTINEL_HOST_1;
    String hostAndPort2 = SENTINEL_HOST_2;
    sentinels.add(hostAndPort1);
    sentinels.add(hostAndPort2);
    String clusterName = CLUSTER_NAME;

    JedisSentinelPool redisSentinelJedisPool = null;
    if (!maps.containsKey(key)) {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(REDIS_MaxActive);
        config.setMaxIdle(REDIS_MaxIdle);
        config.setMaxWaitMillis(REDIS_MaxWait);
        config.setTestOnBorrow(true);
        config.setTestOnReturn(true);
        try {
            /**
             * 如果你遇到 java.net.SocketTimeoutException: Read timed out exception的异常信息 请尝试在构造JedisPool的时候设置自己的超时值. JedisPool默认的超时时间是2秒(单位毫秒)
             */
            redisSentinelJedisPool = new JedisSentinelPool(clusterName, sentinels, config, REDIS_ConnTimeout);

            maps.put(key, redisSentinelJedisPool);
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        redisSentinelJedisPool = maps.get(key);
    }
    return redisSentinelJedisPool;
}

/**
 * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
 */
private static class RedisUtilHolder {
    /**
     * 静态初始化器,由JVM来保证线程安全
     */
    private static JedisUtil instance = new JedisUtil();
}

/**
 * 当getInstance方法第一次被调用的时候,它第一次读取 RedisUtilHolder.instance,导致RedisUtilHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静
 * 态域,从而创建RedisUtil的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。 这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。
 */
public static JedisUtil getInstance() {
    return RedisUtilHolder.instance;
}

/**
 * 获取Redis实例.
 * 
 * @return Redis工具类实例
 */
public Jedis getJedis() {
    Jedis jedis = null;
    int count = 0;
    do {
        try {
            jedis = getPool().getResource();
        } catch (Exception e) {
            e.printStackTrace();
            // 销毁对象
            if (jedis != null) {

                jedis.close();
            }
        }
        count++;
    } while (jedis == null && count < REDIS_RetryNum);
    return jedis;
}

/**
 * 释放redis实例到连接池.
 * 
 * @param jedis redis实例
 */
public void closeJedis(Jedis jedis) {
    if (jedis != null) {
        jedis.close();
    }
}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章