SpringBoot系列教程之Redis集群环境配置

之前介绍的几篇redis的博文都是基于单机的redis基础上进行演示说明的,然而在实际的生产环境中,使用redis集群的可能性应该是大于单机版的redis的,那么集群的redis如何操作呢?它的配置和单机的有什么区别,又有什么需要注意的呢?

本篇将主要介绍SpringBoot项目整合redis集群,并针对这个过程中出现的问题进行说明,并给出相应的解决方案

I. 环境相关

首先需要安装redis集群环境,可以参考博文:redis-集群搭建手册

然后初始化springboot项目,对应的pom结构如下

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.7</version>
    <relativePath/> <!-- lookup parent from update -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories

需要注意的是,我们引入了两个包,一个是必要的 spring-boot-starter-data-redis,官方封装的一个操作redis的start工具,借助它我们可以很方便的直接使用RedisTemplate来操作redis

另外一个是commonos-pool2这个包,主要是当我们配置了redis的连接池的时候,需要用到它,否则会抛一个Class Not Found 的异常

II. 环境整合及采坑

这里我将redis集群搭建在局域网内的一台centos机器上,从后面的配置文件也可以看出(为什么这么处理?主要是为了引出后面一个问题)

1. application.yml

首我们先按照默认的配置方式,来获取我们的 RedisTemplate, 以实现最快的接入redis集群

spring:
  redis:
    password:
    cluster:
      nodes: 192.168.0.203:7000,192.168.0.203:7001,192.168.0.203:7002
      max-redirects: 3
    lettuce:
      pool:
        max-idle: 16
        max-active: 32
        min-idle: 8

我们搭建的redis集群,没有做主备(否则需要6个实例),为了省事,也没有设置密码(生产环境下,这是严格禁止的)

2. 使用测试

因为我们采用默认的配置,因此可以直接获取RedisTemplate的bean对象,来操作redis集群

@SpringBootApplication
public class Application {

    public Application(RedisTemplate redisTemplate) {
        redisTemplate.opsForValue().set("spring-r-cluster-1", 123);
        redisTemplate.opsForValue().set("spring-r-cluster-2", 456);
        redisTemplate.opsForValue().set("spring-r-cluster-3", 789);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

a. 拒绝连接

上面执行之后,报的第一个错误是连接拒绝,而我在redis集群所在的机器(203)上是可以连接成功的,但是本机连接报错

出现上面的问题,一般有两个原因,一个是防火墙导致端口不能外部访问,一个是redis的配置

防火墙的确认方式

  • 判断防火墙是否开启: firewall-cmd --state 如果提示not running 表示未开启
  • 查看防火墙规则: firewall-cmd --list-all

然后可以根据实际场景,添加端口

# 永久开启7000端口的公共访问权限
sudo firewall-cmd --zone=public --add-port=7000/tcp --permanent
sudo firewall-cmd --reload

当然在内网的测试环境下,可以直接关闭防火墙

//Disable firewall
systemctl disable firewalld
systemctl stop firewalld
systemctl status firewalld

//Enable firewall
systemctl enable firewalld
systemctl start firewalld
systemctl status firewalld

redis配置

如果确认不是防火墙问题,那么多半是redis的配置需要修改一下了,在redis.conf中,有一行bind 127.0.0.1配置默认开启,表示只允许本机访问,其他机器无权访问

解决办法就是修改一下这个配置,并重启

bind 0.0.0.0

b. Unable to connect to 127.0.0.1:7001

执行前面的测试用例时,发现会抛一个奇怪的异常如下

关键堆栈信息如下

Caused by: org.springframework.data.redis.RedisSystemException: Redis exception; nested exception is io.lettuce.core.RedisException: io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:7001
    at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:74) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:257) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.convertLettuceAccessException(LettuceStringCommands.java:718) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.set(LettuceStringCommands.java:143) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.connection.DefaultedRedisConnection.set(DefaultedRedisConnection.java:231) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.core.DefaultValueOperations$3.inRedis(DefaultValueOperations.java:202) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:59) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:95) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:198) ~[spring-data-redis-2.0.9.RELEASE.jar:2.0.9.RELEASE]
    at com.git.hui.boot.redis.cluster.Application.<init>(Application.java:14) [classes/:na]
    at com.git.hui.boot.redis.cluster.Application$$EnhancerBySpringCGLIB$$ac0c03ba.<init>(<generated>) ~[classes/:na]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_171]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_171]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_171]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_171]
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:170) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    ... 19 common frames omitted
Caused by: io.lettuce.core.RedisException: io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:7001
    at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:125) ~[lettuce-core-5.0.4.RELEASE.jar:na]
    at io.lettuce.core.cluster.ClusterFutureSyncInvocationHandler.handleInvocation(ClusterFutureSyncInvocationHandler.java:118) ~[lettuce-core-5.0.4.RELEASE.jar:na]
    at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80) ~[lettuce-core-5.0.4.RELEASE.jar:na]
    at com.sun.proxy.$Proxy44.set(Unknown Source) ~[na:na]
    at org.springframework.data.red

通过断点可以看到,集群中的节点ip/端口是准确的,但是异常提示出来个无法连接127.0.0.1:7001,出现这个问题的原因,主要是我们在创建redis集群的时候,设置集群节点使用如下面的命令

redis/src/redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002

通过上面这种方式创建的redis集群,并没有什么问题,但是在springbot的整合中,通过redis集群获取到的节点信息就是127.0.0.1:7000... 然后导致上面的问题,因此一个解决办法是在创建集群的时候,指定下ip

首先数据和配置,然后重新建立集群关系

# 删除数据配置
rm xxx/data/*

redis/src/redis-cli  --cluster create 192.168.0.203:7000 192.168.0.203:7001 192.168.0.203:7002

然后再次测试ok

3. jedis配置

前面的配置默认会使用letttuce作为redis的桥接工具,如果我们底层想使用jedis,可以怎么操作?

首先在pom依赖中添加jedis依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

yml文件中的配置基本上不改都ok,在实际的项目中,对连接池稍微改了一下,不影响阅读,这里不贴出

接下来是定义RedisConnectionFactoy来替换默认的

下面的配置和以前的一篇博文 181101-SpringBoot高级篇Redis之Jedis配置 基本差不多,需要注意的是我们使用RedisClusterConfiguration替换了RedisStandaloneConfiguration

@Configuration
public class RedisAutoConfig {

    @Bean
    public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPool,
            RedisClusterConfiguration jedisConfig) {
        JedisConnectionFactory factory = new JedisConnectionFactory(jedisConfig, jedisPool);
        factory.afterPropertiesSet();
        return factory;
    }

    @Configuration
    public static class JedisConf {
        @Value("${spring.redis.cluster.nodes:127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002}")
        private String nodes;
        @Value("${spring.redis.cluster.max-redirects:3}")
        private Integer maxRedirects;
        @Value("${spring.redis.password:}")
        private String password;
        @Value("${spring.redis.database:0}")
        private Integer database;

        @Value("${spring.redis.jedis.pool.max-active:8}")
        private Integer maxActive;
        @Value("${spring.redis.jedis.pool.max-idle:8}")
        private Integer maxIdle;
        @Value("${spring.redis.jedis.pool.max-wait:-1}")
        private Long maxWait;
        @Value("${spring.redis.jedis.pool.min-idle:0}")
        private Integer minIdle;

        @Bean
        public JedisPoolConfig jedisPool() {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            jedisPoolConfig.setMaxIdle(maxIdle);
            jedisPoolConfig.setMaxWaitMillis(maxWait);
            jedisPoolConfig.setMaxTotal(maxActive);
            jedisPoolConfig.setMinIdle(minIdle);
            return jedisPoolConfig;
        }

        @Bean
        public RedisClusterConfiguration jedisConfig() {
            RedisClusterConfiguration config = new RedisClusterConfiguration();

            String[] sub = nodes.split(",");
            List<RedisNode> nodeList = new ArrayList<>(sub.length);
            String[] tmp;
            for (String s : sub) {
                tmp = s.split(":");
                // fixme 先不考虑异常配置的case
                nodeList.add(new RedisNode(tmp[0], Integer.valueOf(tmp[1])));
            }

            config.setClusterNodes(nodeList);
            config.setMaxRedirects(maxRedirects);
            config.setPassword(RedisPassword.of(password));
            return config;
        }
    }
}

然后其他的依旧,此时RedisTemplate的底层连接就变成了Jedis

III. 其他

0. 项目&相关博文

关联博文

1. 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

原文地址:https://www.cnblogs.com/yihuihui/p/11604501.html

时间: 2024-11-06 15:52:52

SpringBoot系列教程之Redis集群环境配置的相关文章

SpringBoot初始教程之Redis集中式Session管理

1.介绍 有关Session的管理方式这里就不再进行讨论,目前无非就是三种单机Session(基于单机内存,无法部署多台机器).基于Cookie(安全性差).基于全局的统一Session管理(redis.mysql)等多种方式 针对于像淘宝这种超大型网站来说Session如何管理的就无从得知了.但是可以通过yy的方式想象一下,这种大型架构都需要部署多台认证Server,但是一般来说集中式Session无法存储那么多的Session 那么就可以通过UID分片的形式来存储,不同UID分布在不同的Se

redis集群环境的搭建和错误分析

redis集群环境的搭建和错误分析 redis集群时,出现的几个异常问题

Redis 集群环境添加节点失败问题

最近在给公司网管系统Redis集群环境添加节点时候遇到一个问题,提示新增的Node不为空: [[email protected] src]# ./redis-trib.rb add-node --slave --master-id4f6424e47a2275d2b7696bfbf8588e8c4c3a5b95 172.168.63.202:7001172.168.63.202:7000 ...... [OK] All nodes agree about slotsconfiguration. >

Redis集群环境搭建(实验)

环境信息: 集群中至少有奇数个主节点,所以至少三个主节点, 每个节点至少一个备份节点,所以共6个节点(master和slave各3个) 节点信息: (我这里准备了3台主机,每台主机运行一个master和一个slave) 节点1:192.168.2.100:6379     master 节点2:192.168.2.100:6380     slave 节点3:192.168.2.200:6379     master 节点4:192.168.2.200:6380     slave 节点5:19

redis集群部署配置

Redis集群部署配置 测试环境:服务器系统为centos6.5,redis版本为3.2.2,使用一台机器,模拟6个redis实例来创建redis集群,其中3主3从 分别建立redis的安装目录,并复制redis.conf到安装目录下. 2.修改每个目录下的redis.conf配置文件 port 7000   #端口 daemonize yes cluster-enabled yes   #开启集群模式 cluster-config-file nodes-7000.conf  #集群配置文件 c

shell 脚本实战笔记(6)--集群环境配置检测

1). 背景: 集群部署的时候, 需要一致的配置和环境设置. 对于虚拟机集群, 可以借助镜像拷贝, 复制和还原集群机器. 对与物理机集群而言, 则不一样, 如果机器一多, 多人去操作和配置, 对于成熟精干的团队还好, 对于不熟悉环境的小团队, 由于水平的参差不齐, 往往会导致不一致的环境. 因此无论如何, 写脚本进行自动化的配置和环境校验总是最佳实践. 2). 假设应用场景:*) 系统环境: 安装CDH5, 集群规模为16台机器, 每台机器16CPU, 内存16G, 2块SATA盘共500G,

Redis集群的配置

[转]Redis集群的配置 一:memcache 和 Redis 对比总结 [memecache 特点] 1:速度最快(没有自测,但网上有详细的测试用例) 2:支持水平扩展,可以任意添加节点 [redis 特点] 1:速度没有memcache快 2:支持M/S的主从备份 3:可以支持多数据库 4:操作指令很丰富 4:支持异步数据持久化(以文件保存) 总结: 1:如果是简单的数据缓存建议使用MEMCACHE. 2:如果要对单一操作的数据量非常的大则使用MEMCACHE 3: 如果想做性能很好的缓存

1.22 redis集群介绍21.23/21.24 redis集群搭建配置21.25 redis集群

21.22 redis集群介绍多个redis节点网络互联,数据共享所有的节点都是一主一从(可以是多个从),其中从不提供服务,仅作为备用不支持同时处理多个键(如mset/mget),因为redis需要把键均匀分布在各个节点上,并发量很高的情况下同时创建键值会降低性能并导致不可预测的行为.支持在线增加.删除节点客户端可以连任何一个主节点进行读写 21.23/21.24 redis集群搭建配置场景设置:两台机器,分别开启三个Redis服务(端口)A机器上三个端口7000,7002,7004,全部为主B

redis集群介绍、redis集群搭建配置、redis集群操作

一:redis集群介绍 多个redis节点网络互联,数据共享所有的节点都是一主一从(可以是多个从),其中从不提供服务,仅作为备用不支持同时处理多个键(如mset/mget),因为redis需要把键均匀分布在各个节点上,并发量很高的情况下同时创建键值会降低性能并导致不可预测的行为.支持在线增加.删除节点客户端可以连任何一个主节点进行读写 二:redis集群搭建配置 场景设置:两台机器,分别开启三个Redis服务(端口)A机器上三个端口7000,7002,7004,全部为主B机器上三个端口7001,