一. 背景
一次Redis集群故障,Redis集群中的某个节点宕机了,项目中配置的Redis连接池,没有将不可用的连接从连接池中移除,从而导致程序从连接池中拿到了一个不可用的连接,导致系统功能不可用,从而引发了生产故障。
二. SpringBoot项目中使用
创建一个SpringBoot项目,然后在项目中引入依赖:
SpringBoot2.0以上,默认使用lettuce
作为连接Redis的客户端,如果我们要使用默认的lettuce
客户端,需要引入commons-pool2
依赖。
xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
本文,我们使用spring-boot-starter-data-redis
和jedis
来实现Redis的集群高可用配置,具体配置步骤如下:
- 在项目的pom文件中引入依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.8.0</version>
</dependency>
因为我们使用Jedis客户端,所以将spring-boot-starter-data-redis
中的lettuce
依赖去掉。
- 在
yml
文件或者properties
文件中添加Redis信息,本文使用yml
文件,所以信息如下:
yaml
spring:
redis:
cluster:
nodes: 192.168.1.2:6379,192.168.1.3:6379,192.168.1.4:6379
max-redirects: 3
redis:
timeout: 10000 # 客户端超时时间(单位是毫秒,默认是2000)
maxIdle: 300 # 最大空闲数
maxTotal: 1000 # 控制一个pool可分配多少个jedis实例,用来替换redis.maxActive,如果是jedis 2.4以后用该属性
maxWaitMillis: 1000 # 最大建立连接等待时间,如果超过此时间将连接到异常,-1表示无限制
minEvictableIdleTimeMillis: 300000 # 连接的最小空闲时间 默认1800000毫秒(30分钟)
numTestsPerEvictionRun: 1024 # 每次释放连接的最大数目,默认3
timeBetweenEvictionRunsMillis: 30000 # 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
testOnBorrow: true # 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
testWhileIdle: true # 在空闲时检查有效性, 默认false
password: Test@Pass@Cluster
- 创建Redis集群的配置类,在SpringBoot项目中,我们使用注解
@Configuration
加载配置类,配置类如下:
kotlin
@Configuration
public class RedisTemplateConfiguration {
@Value("${spring.redis.cluster.nodes}")
private String clusterNodes;
@Value("${spring.redis.cluster.max-redirects}")
private int maxRedirects;
@Value("${redis.password}")
private String password;
@Value("${redis.timeout}")
private int timeout;
@Value("${redis.maxIdle}")
private int maxIdle;
@Value("${redis.maxTotal}")
private int maxTotal;
@Value("${redis.maxWaitMillis}")
private int maxWaitMillis;
@Value("${redis.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${redis.numTestsPerEvictionRun}")
private int numTestsPerEvictionRun;
@Value("${redis.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${redis.testOnBorrow}")
private boolean testOnBorrow;
@Value("${redis.testWhileIdle}")
private boolean testWhileIdle;
/**
* <p>Jedis连接池配置</p>
* @return {@link JedisPoolConfig}
*/
@Bean
public JedisPoolConfig getJedisPoolConfig() {
final JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大空闲数
jedisPoolConfig.setMaxIdle(maxIdle);
// 连接池最大连接数
jedisPoolConfig.setMaxTotal(maxTotal);
// 最大建立连接等待时间
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
// 逐出连接的最小空闲时间,默认1800000毫秒(30分钟)
jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// 每次逐出检查时 逐出的最大数目
jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
// 逐出扫描的时间间隔
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
jedisPoolConfig.setTestOnBorrow(testOnBorrow);
jedisPoolConfig.setTestOnReturn(testOnBorrow);
// 在空闲时检查有效性, 默认false
jedisPoolConfig.setTestWhileIdle(testWhileIdle);
return jedisPoolConfig;
}
/**
* <p>Redis集群配置</p>
* @return {@link RedisClusterConfiguration}
*/
@Bean
public RedisClusterConfiguration redisClusterConfiguration() {
final RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
final String[] nodes = StringUtils.split(clusterNodes, ",");
final Set<RedisNode> nodeSet = new HashSet<>();
for (final String node : nodes) {
final String[] clusterNode = StringUtils.split(node, ":");
nodeSet.add(new RedisNode(clusterNode[0], Integer.parseInt(clusterNode[1])));
}
redisClusterConfiguration.setClusterNodes(nodeSet);
redisClusterConfiguration.setMaxRedirects(maxRedirects);
redisClusterConfiguration.setPassword(RedisPassword.of(password));
return redisClusterConfiguration;
}
/**
* <p>redis集群模式</p>
* @return {@link JedisConnectionFactory}
*/
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
final JedisConnectionFactory connectionFactory = new JedisConnectionFactory(redisClusterConfiguration(), getJedisPoolConfig());
connectionFactory.setDatabase(0);
connectionFactory.setTimeout(timeout);
connectionFactory.setUsePool(true);
return connectionFactory;
}
/**
* <p>实例化RedisTemplate</p>
* @return {@link RedisTemplate< String, Object>}
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
initDomainRedisTemplate(redisTemplate);
return redisTemplate;
}
/**
* <p>序列化</p>
* @param redisTemplate
*/
private void initDomainRedisTemplate(final RedisTemplate<String, Object> redisTemplate) {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setEnableTransactionSupport(false);
redisTemplate.setConnectionFactory(jedisConnectionFactory());
}
}
- 除了使用配置类,我们也可以使用xml文件来配置,步骤3和步骤4,可以根据自己项目的实际情况选择,如下是xml的配置方式。
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
">
<!-- redis连接池配置 -->
<bean id="jedisPoolConf" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="maxTotal" value="${redis.maxTotal}"/>
<property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
<property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/>
<property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/>
<property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
<property name="testWhileIdle" value="${redis.testWhileIdle}"/>
</bean>
<!-- redis集群配置 -->
<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<property name="clusterNodes">
<set>
<bean id="cluster1" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host1}"/>
<constructor-arg name="port" value="${cluster.redis.port1}"/>
</bean>
<bean id="cluster2" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host1}"/>
<constructor-arg name="port" value="${cluster.redis.port2}"/>
</bean>
<bean id="cluster3" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host2}"/>
<constructor-arg name="port" value="${cluster.redis.port1}"/>
</bean>
<bean id="cluster4" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host2}"/>
<constructor-arg name="port" value="${cluster.redis.port2}"/>
</bean>
<bean id="cluster5" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host3}"/>
<constructor-arg name="port" value="${cluster.redis.port1}"/>
</bean>
<bean id="cluster6" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host3}"/>
<constructor-arg name="port" value="${cluster.redis.port2}"/>
</bean>
</set>
</property>
<property name="maxRedirects" value="${spring.redis.cluster.max-redirects}"/>
<property name="password" value="${redis.password}"/>
</bean>
<!-- jedis连接工厂配置 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="database" value="0"/>
<property name="timeout" value="${redis.timeout}"/>
<property name="usePool" value="true"/>
<constructor-arg index="0" ref="redisClusterConfiguration"/>
<constructor-arg index="1" ref="jedisPoolConf"/>
</bean>
<!-- RedisTemplate实例化 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="keySerializer" ref="stringRedisSerializer"/>
<property name="valueSerializer" ref="jdkSerializationRedisSerializer"/>
<property name="enableTransactionSupport" value="false"/>
<property name="connectionFactory" ref="jedisConnectionFactory"/>
</bean>
<!-- 序列化 -->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</beans>
当Redis集群某个节点出问题时,通过testOnBorrow
和testOnReturn
属性将不可用的连接从JedisPool
中丢弃,所以这两个属性的值都要设置成true
,从而不影响服务的使用,但是当整个集群不可用时,我们的服务去调用Redis进行操作,也是不可行的。
当Redis集群可用时,会自动将连接添加到连接池中。
通过上面的方式,在我们的项目中配置Redis集群,即使是整个Redis集群不可用时,我们的服务依然可以正常启动,不会因为Redis集群服务不可用,从而导致我们的服务启动失败。
- 使用RedisTemplate类来操作Redis。
typescript
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* <p>操作Redis</p>
* @return {@link String}
*/
public String test() {
redisTemplate.opsForValue().set("name", "test-redis-cluster......");
return String.valueOf(redisTemplate.opsForValue().get("name"));
}
以上便是在SpringBoot项目中配置Redis集群的方式。
三. SSM项目中使用
所谓SSM项目,指的是使用Spring+SpringMVC+Mybatis框架整合的项目,本文将通过如下步骤介绍如何在SSM项目中配置Redis集群。
- 创建一个Maven项目,在Maven项目的pom文件中,引入Spring、SpringMVC、Mybatis、Redis的依赖,本文主要是介绍Redis集群在SSM中的配置,所以Spring、SpringMVC、Mybatis框架整合,就不介绍了。
xml
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jedis.version>2.9.0</jedis.version>
<spring.data.redis>2.0.10.RELEASE</spring.data.redis>
</properties>
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>${spring.data.redis}</version>
</dependency>
</dependencies>
- 在resource目录下创建
application.properties
文件,这个文件中填写Redis的配置信息,信息如下:
ini
redis.pool.maxTotal=2000
redis.pool.maxIdle=300
redis.pool.timeBetweenEvictionRunsMillis=30000
redis.pool.minEvictableIdleTimeMillis=300000
redis.pool.softMinEvictableIdleTimeMillis=1800000
redis.pool.maxWaitMillis=1000
redis.pool.testOnBorrow=true
redis.pool.testOnReturn=false
redis.pool.testWhileIdle=true
redis.pool.numTestsPerEvictionRun=1024
redis.pool.blockWhenExhausted=false
redis.timeout=10000
redis.max.redirects=6
redis.cluster.password=Test@Pass@Cluster
redis.cluster.host1=192.168.1.2
redis.cluster.host2=192.168.1.3
redis.cluster.host3=192.168.1.4
redis.cluster.port1=6279
redis.cluster.port2=6379
- 在resource目录下创建applicationContext-redis.xml文件,文件命名可以根据自己项目的命名规则命名。
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
">
<!-- redis连接池配置 -->
<bean id="jedisPoolConf" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="maxTotal" value="${redis.maxTotal}"/>
<property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
<property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/>
<property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/>
<property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
<property name="testWhileIdle" value="${redis.testWhileIdle}"/>
</bean>
<!-- redis集群配置 -->
<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<property name="clusterNodes">
<set>
<bean id="cluster1" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host1}"/>
<constructor-arg name="port" value="${cluster.redis.port1}"/>
</bean>
<bean id="cluster2" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host1}"/>
<constructor-arg name="port" value="${cluster.redis.port2}"/>
</bean>
<bean id="cluster3" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host2}"/>
<constructor-arg name="port" value="${cluster.redis.port1}"/>
</bean>
<bean id="cluster4" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host2}"/>
<constructor-arg name="port" value="${cluster.redis.port2}"/>
</bean>
<bean id="cluster5" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host3}"/>
<constructor-arg name="port" value="${cluster.redis.port1}"/>
</bean>
<bean id="cluster6" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${cluster.redis.host3}"/>
<constructor-arg name="port" value="${cluster.redis.port2}"/>
</bean>
</set>
</property>
<property name="maxRedirects" value="${spring.redis.cluster.max-redirects}"/>
<property name="password" value="${redis.password}"/>
</bean>
<!-- jedis连接工厂配置 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="database" value="0"/>
<property name="timeout" value="${redis.timeout}"/>
<property name="usePool" value="true"/>
<constructor-arg index="0" ref="redisClusterConfiguration"/>
<constructor-arg index="1" ref="jedisPoolConf"/>
</bean>
<!-- RedisTemplate实例化 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="keySerializer" ref="stringRedisSerializer"/>
<property name="valueSerializer" ref="jdkSerializationRedisSerializer"/>
<property name="enableTransactionSupport" value="false"/>
<property name="connectionFactory" ref="jedisConnectionFactory"/>
</bean>
<!-- 序列化 -->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</beans>
其实这个applicationContext.xml
中的内容,和上面SpringBoot项目中的那个xml文件内容是一致的,唯一的区别是,需要在applicationContext.xml
文件中新增一行代码<context:property-placeholder location="classpath:application.properties"/>
,增加这行代码的目的,是保证我们的xml
文件能够正确的读取到properties
文件中的配置信息。
依然使用testOnBorrow
和testOnReturn
属性将不可用的连接从JedisPool
中丢弃,然后通过JedisConnectionFactory来管理,如果你的Redis集群有密码验证,那么你使用的spring-data-redis
的版本必须是2.0
以上版本,在2.0
以上版本中,RedisClusterConfiguration
才支持密码。
在SSM项目中,spring、spring-data-redis、jedis
版本必须要对应才行,如果版本之间不对应,则会出现一些想不到的问题。
如果我们把密码配置在JedisConnectionFactory
上,在集群模式上也是加载不了的。
- 将创建的
applicationContext.xml
文件添加到web.xml
文件中。
xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
classpath:applicationContext-redis.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
- 使用RedisTemplate来操作Redis。
typescript
@Resource
private RedisTemplate<String, Object> redisTemplate;
public String test() {
final ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
valueOperations.set("test", "This use RedisTemplate ......");
return String.valueOf(valueOperations.get("test"));
}
以上步骤便是SSM项目中配置Redis集群和操作Redis的方式。
四. Jedis单独使用
对于一些比较老的项目,例如spring
的版本在4.2.*以下,只使用Jedis
来配置Redis集群
- 在项目的pom文件中引入jedis的依赖。
xml
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
- 创建application.properties文件。
ini
redis.pool.maxTotal=2000
redis.pool.maxIdle=300
redis.pool.timeBetweenEvictionRunsMillis=30000
redis.pool.minEvictableIdleTimeMillis=300000
redis.pool.softMinEvictableIdleTimeMillis=1800000
redis.pool.maxWaitMillis=1000
redis.pool.testOnBorrow=true
redis.pool.testOnReturn=false
redis.pool.testWhileIdle=true
redis.pool.numTestsPerEvictionRun=1024
redis.pool.blockWhenExhausted=false
redis.timeout=10000
redis.max.redirects=6
redis.cluster.password=Test@Pass@Cluster
redis.cluster.host1=192.168.1.2
redis.cluster.host2=192.168.1.3
redis.cluster.host3=192.168.1.4
redis.cluster.port1=6279
redis.cluster.port2=6379
- 创建Redis集群配置的xml文件。
xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:property-placeholder location="classpath:application.properties"/>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="200"/>
<!-- 连接池中最大空闲数 -->
<property name="maxIdle" value="100"/>
<!-- 连接池中确保最少空闲连接数 -->
<property name="minIdle" value="10"/>
<!-- 当连接池用尽后,调用者是否要等待,只有当为true时 maxWaitMillis 才生效 -->
<property name="blockWhenExhausted" value="true"/>
<property name="maxWaitMillis" value="300000"/>
<!-- 使用前检查连接是否正常,剔除无效连接,在主从切换后可以做到自动重连 -->
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="10000"/>
<property name="minEvictableIdleTimeMillis" value="30000"/>
<property name="jmxEnabled" value="true"/>
</bean>
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg index="0">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.cluster.host1}"/>
<constructor-arg index="1" value="${redis.cluster.port1}"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.cluster.host1}"/>
<constructor-arg index="1" value="${redis.cluster.port2}"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.cluster.host2}"/>
<constructor-arg index="1" value="${redis.cluster.port1}"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.cluster.host2}"/>
<constructor-arg index="1" value="${redis.cluster.port2}"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.cluster.host3}"/>
<constructor-arg index="1" value="${redis.cluster.port1}"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.cluster.host3}"/>
<constructor-arg index="1" value="${redis.cluster.port2}"/>
</bean>
</set>
</constructor-arg>
<constructor-arg index="1" value="${redis.timeout}"/>
<constructor-arg index="2" value="10000"/>
<constructor-arg index="3" value="1000"/>
<constructor-arg index="4" value="${redis.cluster.password}"/>
<constructor-arg index="5" ref="jedisPoolConfig"/>
</bean>
在JedisPoolConfig
中将testOnBorrow
和testOnReturn
属性的值设置成true
,达到的效果与SpringBoot项目和SSM项目是一致的 ,唯一的区别是,当Redis集群不可用时,启动我们的服务会启动失败,因为服务在启动的时候,会去连接Redis服务。
另外,当我们Redis集群的master
没有时,服务也是不可用的。
- 在项目中使用jedisCluster操作Redis
csharp
@Resource
private JedisCluster jedisCluster;
public String test() {
jedisCluster.set("test", "This use JedisCluster............");
return jedisCluster.get("test");
}
以上便是只使用jedis配置Redis集群和操作Redis,弊端是:当Redis集群不可用时,重启服务会重启失败;当Redis集群中master
节点没有时,也会有问题,表示找不到主节点。
五. 总结
- 在SpringBoot项目和SSM项目中使用
spring-*-redis
来管理Redis是最友好的,当Redis集群不可用时,我们重启服务,是可以启动成功的,不会因为Redis集群不可用而导致我们的服务启动失败。 - 在SSM项目中,如果
spring
的版本低于4.2.*以下,同时我们的集群又有密码限制,spring-data-redis
兼容的版本在2.0以下,那么此时不能使用spring-data-redis
来操作Redis了,因为spring-data-redis2.0
以下版本不支持集群配置密码。 - 不使用Spring来管理Redis,只使用
jedis
,使用这种方式,当集群不可用,或者集群中主节点有问题时,会导致我们的服务不能操作Redis,如果服务重启,则会启动失败。 - 经过测试对比,使用
spring-boot-starter-data-redis
来管理Redis的效果是最好的,集群不可用或者集群中某个节点(不管是主节点还是从节点)都不会影响服务重启;只有当整个集群不可用时,服务操作Redis才会失败。 - 在连接池中将
testOnBorrow
和testOnReturn
配置成true
,会有性能影响,但是如果不配置,又不能及时将不可用的连接移除。