Windows 下部署Redis 主从模式+哨兵模式+JAVA连接方式

前言

之前项目需求部署redis高可用,走了很多弯路以及相关配置来回折腾浪费了很多时间,特地记录下。

主从模式:实现多台redis实例进行服务运行,并且数据相互同步;
哨兵模式:实现主服务器和从服务器进行监听,当主服务器宕机,会立马进行主服务选举, 选出新的主服务器。


一、redis安装

链接:https://pan.baidu.com/s/1us7TeMD2xCF2Pxm-mu-nGw 
提取码:ae4u

1.下载redis

网盘提供的是windows下的5.0.10版本,若是想要其他版本的需要自行百度;

2.安装

 直接双击进行安装,全部就是next即可,全程都不需要更改的,就是注意安装位置,不要放在C盘就行。

 安装好就是这样的,我是放在E盘下:E:\\development\redisPool\redis下的

 3.再把redis文件复制一份

把redis先复制一份,并且修改两个文件,master_6379做主服务,salve_6380做从服务

 二、主从服务配置

1.修改配置文件

修改两个文件中的redis.windows.conf文件如下配置,其他不改,要删除如下配置前面的#符号,不然被注释不会采用新的配置信息。

master_6379 文件中redis.windows.conf修改配置如下:

     #是否开启保护模式,选择no

      protected-mode no

     # 配置redis从服务器密码

      requirepass 123456

     # 配置redis主服务器密码,requirepass和masterauth两个密码必须一样
      masterauth 123456

     #是否是集群模式的标志,这里改为no
      cluster-enabled no

     # 改为0.0.0.0 便于其他服务器可以访问到此redis服务
      bind 0.0.0.0 

salve_6380 文件中redis.windows.conf修改配置如下:

   # salve_6380 比master_6379多个端口的修改,master_6379端口默认6379

   port 6380
   protected-mode no

   # 主节点ip和端口,即master_6379服务的ip和端口
   slaveof 127.0.0.1 6379  
   requirepass 123456
   masterauth 123456
   cluster-enabled no
   bind 0.0.0.0 

2.启动两个主从服务

windows下进行cmd命令,打开终端,进入到redis根目录,输入如下命令:

redis-server.exe ./redis.windows.conf

启动主服务,一定要切换到主redis服务的根目录master_6379下执行命令否则会报错:

 启动从服务,一定要切换到主redis服务的根目录salve_6380下执行命令否则会报错:

如此,两个主从服务算是一直运行中,不能关闭命令窗口,关闭服务便停止了。 

3.验证服务是否正常运行

随便进入某个redis服务的根目录,通过终端连接redis,输入命令:

redis-cli -p 6379   # -p  指定连接redis的端口号

auth  123456       # 输入redis密码,在redis.windows.conf文件中设置的密码

get key                # 查询某个key的值

info replication    # 查询当前服务是主服务还是,从服务

 或者

从命令可以看出6380的服务role为slave,即从服务,而6379的服务是master,即主服务;

且6379服务下redis的connected_slaves为1,slave0:ip=20.20.0.219,port=6380,state=online

也指出从服务的端口,以及状态都是正常的。

4.测试从主服务写入数据从服务是否可以正常同步过来

 在主服务6379下输入命令,设置数据:

set test redis

在从服务6380下输入命令,获取数据:

set test

  如上可以看出两台redis正常工作,且一主一从模式,并且数据也能够达到同步效果。直接关闭窗口即可。

  现在配置的方式是只能在主服务器下进行写数据操作

  但是在某个条件下主服务宕机了,就无法实现业务正常运作了,因为从服务无法进行写数据,所以这时候我们要在主从模式基础上进行哨兵配置,便于监听主服务宕机,可以立马将从服务升级为主服务,保证业务可用。哨兵模式如下:

三、哨兵模式配置

1.增加sentinel.conf文件

分别在master_6379、salve_6380文件夹下新建文件sentinel.conf,文件内容如下:

【master_6379】主服务的sentinel.conf内容

  # 当前Sentinel服务运行的端口
   port 26379
  # 禁止保护模式
   protected-mode no
  # 哨兵监听的主服务器 后面的1表示主机挂掉以后进行投票,只需要1票就可以从机变主机
   sentinel monitor mymaster 127.0.0.1 6379 1
  # 3s内mymaster无响应,则认为mymaster宕机了
   sentinel down-after-milliseconds mymaster 3000
  #如果10秒后,mysater仍没启动过来,则启动failover
   sentinel failover-timeout mymaster 10000
  # 设置哨兵sentinel连接主从的密码,主从必须设置一样密码,没有的话不用设置
   sentinel auth-pass mymaster 123456
  # 执行故障转移时, 最多有1个从服务器同时对新的主服务器进行同步
   sentinel config-epoch mymaster 21

【salve_6380】从服务的sentinel.conf内容

  # 当前Sentinel服务运行的端口
   port 26380
  # 禁止保护模式
   protected-mode no
  # 哨兵监听的主服务器 后面的1表示主机挂掉以后进行投票,只需要1票就可以从机变主机
   sentinel monitor mymaster 127.0.0.1 6379 1
  # 3s内mymaster无响应,则认为mymaster宕机了
   sentinel down-after-milliseconds mymaster 3000
  #如果10秒后,mysater仍没启动过来,则启动failover
   sentinel failover-timeout mymaster 10000
  # 设置哨兵sentinel连接主从的密码,主从必须设置一样密码,没有的话不用设置
   sentinel auth-pass mymaster 123456
  # 执行故障转移时, 最多有1个从服务器同时对新的主服务器进行同步
   sentinel config-epoch mymaster 21

2.增加哨兵sentinel启动脚本

分别在master_6379、salve_6380文件夹下新建文件startSentinel.bat,文件内容如下:  

redis-server.exe sentinel.conf --sentinel

 3.增加redis启动脚本

分别在master_6379、salve_6380文件夹下新建文件startup.bat,不然每次都得在终端下输入命令,文件内容如下:  

redis-server.exe ./redis.windows.conf

创建好的文件如下:

 4.验证哨兵模式

先分别双击执行主从服务redis、再执行主从两个哨兵,顺序如下:

     1.master_6379下:startup.bat

     2.slave_6380下:startup.bat

     3.master_6379下:startSentinel.bat

     4.slave_6380下:startSentinel.bat

按照2.3步骤方式进行验证redis主从服务是否正常,如下:都是正常的;

 关闭主服务6379,shutdown,两个哨兵均不能关闭,再验证6380是否可以成为主服务

 可见6380成为主服务了

 再把6379,启动,验证是不是应该成为从服务

 从信息上面看,把6379启动之后,6380依然是主服务,只是新增一个从节点的连接,也就是说6379被重启之后就会成为从节点。

至此主从模式+哨兵模式部署完成。

四、Springboot 访问主从哨兵模式的redis

1.增加一个配置文件RedisClusterConfig

import com.chinamobile.zj.util.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * redis主从模式,避免单节点redis宕机引发服务不可用问题
 */
@Configuration
@EnableAutoConfiguration
@Slf4j
public class RedisClusterConfig{

    @Bean
    public JedisSentinelPool testSentinel() {

            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            // 最大空闲连接数, 默认8个
            jedisPoolConfig.setMaxIdle(10);
            // 最大连接数, 默认8个
            jedisPoolConfig.setMaxTotal(16);
            //最小空闲连接数, 默认0
            jedisPoolConfig.setMinIdle(8);
            // 获取连接时的最大等待毫秒数,10s(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
            jedisPoolConfig.setMaxWaitMillis(10000);
            //对拿到的connection进行validateObject校验;如果为true,则得到的jedis实例均是可用的;
            jedisPoolConfig.setTestOnBorrow(true);
            jedisPoolConfig.setTestOnReturn(true);
            //Idle时进行连接扫描
            jedisPoolConfig.setTestWhileIdle(true);
            //表示idle object evitor两次扫描之间要sleep的毫秒数
            jedisPoolConfig.setTimeBetweenEvictionRunsMillis(30000);
            //表示idle object evitor每次扫描的最多的对象数
            jedisPoolConfig.setNumTestsPerEvictionRun(10);
            //表示一个对象至少停留在idle状态的最短时间,才能被idle object evitor扫描并驱逐;只有在timeBetweenEvictionRunsMillis大于0时才有意义
            jedisPoolConfig.setMinEvictableIdleTimeMillis(60000);
            // 创建连接池
            Set<String> sentinels = new HashSet<>(Arrays.asList("127.0.0.1:26379","127.0.0.1:26380")); 
            JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels,jedisPoolConfig,"123456");
            return pool;
    }
}

2.redis读写数据

// 作为静态工具方法方式的访问
@Component
@Slf4j
public class RedisUtils{
    private static JedisSentinelPool jedisSentinelPool;
    @Autowired
    public void setRedisTemplate(JedisSentinelPool jedisSentinelPool) {
        RedisUtils.jedisSentinelPool = jedisSentinelPool;
    }
    public static String hSet(String key,String value) {
        String result = jedisSentinelPool.getResource().set(key,value);
        return result;
    }
    public static Object hGet(String key) {
        String o = jedisSentinelPool.getResource().get(key);
        return o;
    }
}


// service 层的访问
@Service
@Transactional
@Slf4j
public class SSOLoginSv {
    @Autowired
    private JedisSentinelPool jedisSentinelPool;
    
    public String getValue(){
        return jedisSentinelPool.getResource().get("test");
    }

    public String setValue(){
        return jedisSentinelPool.getResource().set("test","demo");
    }
}

3.问题

经过一段时间运行发现,项目会时不时报错:报错内容为资源池不够了,主要原因是:
 1.资源没有及时释放;
 2.redis没有配置空闲时间超过某个数值,连接自动关闭。

所以调整的方式如下:
1.在redis中get/set之后进行连接池释放操作: 

     /**
     * 释放jedis资源
     *
     * @param jedis
     */
    public static void returnResource(final Jedis jedis) {
        if (jedis != null) {
            jedisSentinelPool.returnResource(jedis);
        }
    }

    /**
     * Jedis对象出异常的时候,回收Jedis对象资源
     *
     * @param jedis
     */
    public static void returnBrokenResource(final Jedis jedis) {
        if (jedis != null) {
            jedisSentinelPool.returnBrokenResource(jedis);
        }

    }


    public static String setVlaue(String key,String value) {
        Jedis resource = null;
        String result = "";
        try{
            resource = jedisSentinelPool.getResource();
            result = resource.set(key,value);
        }catch (Exception e) {
            returnBrokenResource(resource);
            e.printStackTrace();
        } finally {
            returnResource(resource);
        }
        return result;
    }


    public static Object getValue(String key) {
        Jedis resource = null;
        String o = "";
        try{
            resource = jedisSentinelPool.getResource();
            o = resource.get(key);
        }catch (Exception e) {
            returnBrokenResource(resource);
            e.printStackTrace();
        } finally {
            returnResource(resource);
        }
        return o;
    }

2.在redis配置中设置超时关闭连接机制:
   执行如下命令:

 # 连接redis主机

 redis-cli -h reis主机ip  -p redis服务端口

# 查看redis主机设置多长时间空闲便关闭连接,若是返回0,便是此功能关闭,永不释放

 config get timeout

# 修改超时关闭连接时长,秒为单位

 config set timeout  600

3.完毕

欢迎各位大神有什么错误地方指出

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值