Redis单机搭建主从(1)

Redis单机主从切换部署说明


准备工作

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

  • 新建主从目录

mkdir -p /usr/local/redis/master/
mkdir -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客户端连接下执行:
172.20.1.47:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.20.1.47,port=6380,state=online,offset=38335325,lag=0
master_repl_offset:38335461
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:37286886
repl_backlog_histlen:1048576
  • slave_redis客户端连接下执行:
172.20.1.47:6380> info replication
# Replicatio
role:slave
master_host:172.20.1.47
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:38343419
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

测试主从复制,读写分离

  • 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

配置主从切换

  • kill掉当前所有redis进程
ps -ef | grep redis
kill -9 pid
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();
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值