騰訊雲上的配置
在安全組上打開相關的端口即可
"來源" 就是你的目標服務器的ip(也可以是0.0.0.0/0) 協議端口可以用范圍的寫法 TCP:6379-6389
然后需將redis運行使用的配置文件redis.conf默認bind 127.0.0.1(只允許本地訪問)注釋掉(或者改為0.0.0.0)
# bind 127.0.0.1
protected-mode no 從yes改為no
redis連接單機和集群
依賴 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis依賴commons-pool 這個依賴一定要添加 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
</dependency>
redis參數的配置文件
redis.properties
#啟動集群
#redis.cluster=true
########################### reids單機配置 ##############################
#Matser的ip地址
redis.host=49.235.196.22
#端口號
redis.port=6380
#如果有密碼
#redis.password=
#客戶端超時時間單位是毫秒 默認是2000
redis.timeout=5000
########################### jedis單機與集群的公共配置 ##############################
#最大空閑數
redis.maxIdle=300
#連接池的最大數據庫連接數。設為0表示無限制,如果是jedis 2.4以后用redis.maxTotal
#redis.maxActive=600
#控制一個pool可分配多少個jedis實例,用來替換上面的redis.maxActive,如果是jedis 2.4以后用該屬性
redis.maxTotal=1000
#最大建立連接等待時間。如果超過此時間將接到異常。設為-1表示無限制。
redis.maxWaitMillis=1000
#連接的最小空閑時間 默認1800000毫秒(30分鍾)
redis.minEvictableIdleTimeMillis=300000
#每次釋放連接的最大數目,默認3
redis.numTestsPerEvictionRun=1024
#逐出掃描的時間間隔(毫秒) 如果為負數,則不運行逐出線程, 默認-1
redis.timeBetweenEvictionRunsMillis=30000
#是否在從池中取出連接前進行檢驗,如果檢驗失敗,則從池中去除連接並嘗試取出另一個
redis.testOnBorrow=true
#在空閑時檢查有效性, 默認false
redis.testWhileIdle=true
########################### redis集群配置 ##############################
redis.clusterNodes=49.235.196.22:7001,49.235.196.22:7002,49.235.196.22:7003,49.235.196.22:7004,49.235.196.22:7005,49.235.196.22:7006
redis.maxRedirects=3
#哨兵模式
#redis.sentinel.host1=192.168.177.128
#redis.sentinel.port1=26379
#redis.sentinel.host2=172.20.1.231
#redis.sentinel.port2=26379
application.yml
redis:
cluster:
true
三個Redis的配置類,RedisConfig:集群和單機的公共部分,SinglenRedisConfig單機特有的配置,ClusterRedisConfig集群特有的配置
package per.qiao.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
/**
* Create by IntelliJ Idea 2018.2
*
* @author: qyp
* Date: 2019-09-29 17:15
*/
@Getter
@Setter
public abstract class RedisConfig {
/**
* 最大空閑數
*/
public Integer maxIdle;
/**
* 控制一個pool可分配多少個jedis實例
*/
public Integer maxTotal;
/**
* 最大建立連接等待時間。如果超過此時間將接到異常。設為-1表示無限制。
*/
public Integer maxWaitMillis;
/**
* 連接的最小空閑時間 默認1800000毫秒(30分鍾)
*/
public Integer minEvictableIdleTimeMillis;
/**
* 每次釋放連接的最大數目,默認3
*/
public Integer numTestsPerEvictionRun;
/**
* 逐出掃描的時間間隔(毫秒) 如果為負數,則不運行逐出線程, 默認-1
*/
public long timeBetweenEvictionRunsMillis;
/**
* 是否在從池中取出連接前進行檢驗,如果檢驗失敗,則從池中去除連接並嘗試取出另一個
*/
public boolean testOnBorrow;
/**
* 在空閑時檢查有效性, 默認false
*/
public boolean testWhileIdle;
/**
* JedisPoolConfig 連接池
*
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大空閑數
jedisPoolConfig.setMaxIdle(maxIdle);
// 連接池的最大數據庫連接數
jedisPoolConfig.setMaxTotal(maxTotal);
// 最大建立連接等待時間
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
// 逐出連接的最小空閑時間 默認1800000毫秒(30分鍾)
jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// 每次逐出檢查時 逐出的最大數目 如果為負數就是 : 1/abs(n), 默認3
jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
// 逐出掃描的時間間隔(毫秒) 如果為負數,則不運行逐出線程, 默認-1
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// 是否在從池中取出連接前進行檢驗,如果檢驗失敗,則從池中去除連接並嘗試取出另一個
jedisPoolConfig.setTestOnBorrow(testOnBorrow);
// 在空閑時檢查有效性, 默認false
jedisPoolConfig.setTestWhileIdle(testWhileIdle);
return jedisPoolConfig;
}
/**
* 單機構建JedisConnectionFactory對象
* @param jedisPoolConfig
* @return
*/
public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
return null;
}
/**
* 集群redis構建JedisConnectionFactory對象
* @param jedisPoolConfig
* @param redisClusterConfiguration
* @return
*/
public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisClusterConfiguration redisClusterConfiguration) {
return null;
}
/**
* 實例化 RedisTemplate 對象
*
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
return redisTemplate;
}
/**
* 設置數據存入 redis 的序列化方式,並開啟事務
*
* @param redisTemplate
* @param factory
*/
public void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
//如果不配置Serializer,那么存儲的時候缺省使用String,如果用User類型存儲,那么會提示錯誤User can't cast to String!
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// 開啟事務
//redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(factory);
}
}
SinglenRedisConfig.java
package per.qiao.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig;
/**
* PropertySource加載文件到當前類上下文的 Environment 中
*/
@Configuration
@PropertySource("classpath:redis.properties")
@ConfigurationProperties(prefix = "redis")
@ConditionalOnMissingBean(ClusterRedisConfig.class)
@Getter
@Setter
public class SinglenRedisConfig extends RedisConfig {
/**
* host,port,timeout
* 這三個是單機屬性
*/
private String host;
private Integer port;
private Integer timeout;
/**
* 單機版配置
*
* @param @param jedisPoolConfig
* @param @return
* @return JedisConnectionFactory
* @throws
* @Title: JedisConnectionFactory
* @autor lpl
* @date 2018年2月24日
*/
@Bean
public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
//連接池
redisConnectionFactory.setPoolConfig(jedisPoolConfig);
//IP地址
redisConnectionFactory.setHostName(host);
//端口號
redisConnectionFactory.setPort(port);
//如果Redis設置有密碼
//JedisConnectionFactory.setPassword(password);
//客戶端超時時間單位是毫秒
redisConnectionFactory.setTimeout(timeout);
return redisConnectionFactory;
}
}
ClusterRedisConfig.java
package per.qiao.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author qiao
*/
@Configuration
@PropertySource("classpath:redis.properties")
//@EnableConfigurationProperties(ClusterRedisConfig.class)
@ConfigurationProperties(prefix = "redis")
//@ConditionalOnExpression("#{'true'.equals(environment['redis.cluster'])}")
//@ConditionalOnExpression("'${redis.cluster}'=='true'")
@ConditionalOnExpression("${redis.cluster}")
@Getter
@Setter
public class ClusterRedisConfig extends RedisConfig {
/**
* clusterNodes,mmaxRedirectsac
* 這兩個是集群屬性
*/
private List<String> clusterNodes;
private Integer maxRedirects;
/**
* Redis集群的配置
*
* @return RedisClusterConfiguration
* @throws
* @autor lpl
* @date 2017年12月22日
*/
@Bean
public RedisClusterConfiguration redisClusterConfiguration() {
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
Set<RedisNode> nodes = clusterNodes.stream().map(ipPort -> {
String[] ipAndPort = ipPort.split(":");
return new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1]));
}).collect(Collectors.toSet());
redisClusterConfiguration.setClusterNodes(nodes);
redisClusterConfiguration.setMaxRedirects(maxRedirects);
return redisClusterConfiguration;
}
/**
* 配置工廠
*
* @param @param jedisPoolConfig
* @param @return
* @return JedisConnectionFactory
* @throws
* @Title: JedisConnectionFactory
* @autor lpl
* @date 2017年12月22日
*/
@Bean
public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisClusterConfiguration redisClusterConfiguration) {
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
return redisConnectionFactory;
}
}
測試
@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisTest {
@Autowired
RedisUtil redisUtil;
@Test
public void test() {
//redisUtil.del("abc");
redisUtil.set("abc", "1234567");
System.out.println("================");
Object myKey = redisUtil.get("abc");
System.out.println(myKey);
}
}
遺留問題
問題1:在集群配置上出了個問題ClusterRedisConfig
問題一、使用@PropertySource("classpath:redis.properties")加載配置文件,然后使用@ConditionalOnExpression獲取不到配置文件中的值
使用@PropertySource("classpath:redis.properties")加載指定的屬性文件,然后使用@ConfigurationProperties(prefix = "redis")指定前綴,最后使用@ConditionalOnExpression("${redis.cluster}")判斷是否加載當前類
但是這個判斷不能按照設想進行控制。
1. 當我將屬性redis.cluster放到redis.properties中時,獲取不到值,拋there is still more data in the expression in 'lcurly({)'錯誤
2. 當我把屬性redis.cluster放到application.yml文件中時,是可以成功的。
猜想:yml文件最先加載,@ConditionalOnExpression又比@PropertySource先加載,所以拿不到數據
問題2:在使用lettuce連接redis時,項目總是報集群的連接超時,但是項目可以正常使用
這是使用lettuce(生菜)連接的yml配置文件
spring:
redis:
database: 1
# host:
# port:
# password:
cluster:
nodes:
- 49.235.196.22:7001
- 49.235.196.22:7002
- 49.235.196.22:7003
- 49.235.196.22:7004
- 49.235.196.22:7005
- 49.235.196.22:7006
lettuce:
pool:
# 連接池最大連接數 默認8 ,負數表示沒有限制
max-active: 8
# 連接池中的最大空閑連接 默認8
max-idle: 8
# 連接池中的最小空閑連接 默認0
min-idle: 0
# 連接池最大阻塞等待時間(使用負值表示沒有限制) 默認-1
max-wait: -1s
host: 49.235.196.22
port: 7001
#timeout: 30000s
這是配置類
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig2 {
/**
* springboot2.x 使用LettuceConnectionFactory 代替 RedisConnectionFactory
* application.yml配置基本信息后,springboot2.x RedisAutoConfiguration能夠自動裝配
* LettuceConnectionFactory 和 RedisConnectionFactory 及其 RedisTemplate
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}