redis的集群搭建非常简单,我使用的是redis 4.0.10在centos 7.2 上搭建的,按照配置文件搭建就可以,并且前面的博客收藏了集群搭建的链接。
搭建完以后就是项目中整合redis集群,这里有个小推荐,使用jedis整合redis集群非常简单,下面是整合的步骤:
一、单机版和集群版的redis整合
1)首先在pom.xml中导入jar包
<!-- redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
说明:这里导入的jar包是2.9的jedis,由于我使用的是4.0.10版本,版本比较新,所以至少要使用2.9或以上版本,不然启动的过程中会报错,抛出的异常是 java.lang.NumberFormatException: 6004@16004 类似这样的异常。
2)单机版的配置文件 需要写在 application.properties 如下
#Redis Pool ============================================================================================================
jedis.pool.host=127.0.0.1
jedis.pool.port=6379
jedis.pool.timeout=30000
jedis.pool.password=password123
jedis.pool.dbIndex=0
jedis.pool.maxTotal=300
jedis.pool.maxIdle=10
jedis.pool.maxWaitMillis=30000
3) 集群版的配置文件需要在 resources 下新建一个文件 redis.properties,内容如下
#redis cluster
xyy.redis.pool.nodes=192.168.3.141:6000,192.168.3.141:6001,192.168.3.141:6002,192.168.3.143:6003,192.168.3.143:6004,192.168.3.143:6005,192.168.3.144:6006,192.168.3.144:6007,192.168.3.144:6008
xyy.redis.pool.timeout=3000
xyy.redis.pool.soTimeout=1500
xyy.redis.pool.maxAttempts=5
xyy.redis.pool.password=password23
4)实现单机版的jedis连接 redis 代码
package com.qzt.common.redis;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.qzt.util.PubFunc;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Slf4j
@Configuration
public class RedisConfiguration {
@Primary
@Bean(name="jedisPool")
public JedisPool jedisPool(@Qualifier("jedisPoolConfig") JedisPoolConfig config,
@Value("${jedis.pool.host}")String host,
@Value("${jedis.pool.port}")int port,
@Value("${jedis.pool.timeout}")int timeout,
@Value("${jedis.pool.password}")String passowrd,
@Value("${jedis.pool.dbIndex}")int dbIndex){
log.info("init redis pool -------------->host:{},port:{},dbIndex",host,port,dbIndex);
if(PubFunc.isNull(passowrd)){
passowrd = null;
}
return new JedisPool(config,host,port,timeout,passowrd,dbIndex);
}
@Primary
@Bean(name="jedisPoolConfig")
public JedisPoolConfig jedisPoolConfig(@Value("${jedis.pool.maxTotal}")int maxTotal,
@Value("${jedis.pool.maxIdle}")int maxIdle,
@Value("${jedis.pool.maxWaitMillis}")int maxWaitMillis){
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
config.setMaxWaitMillis(maxWaitMillis);
return config;
}
}
5)实现集群版的jedis连接 redis 代码,需要写两个类来实现 一个 RedisProperties.java ,一个JedisClusterConfig.java
RedisProperties.java 类内容如下:
package com.qzt.common.redis;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* redis集群配置文件
* @ClassName: RedisProperties
* @author suziqing
*/
@Data
@Component
@ConfigurationProperties(prefix = "xyy.redis.pool")
@PropertySource("classpath:redis.properties")
public class RedisProperties {
/** redis集群节点 */
private String nodes;
/** 连接超时时间 */
private int timeout;
/** 重连次数 */
private int maxAttempts;
private String password;
//读取数据超时时间
private int soTimeout;
public RedisProperties() {
}
public RedisProperties(String nodes, int timeout, int maxAttempts, String password, int soTimeout) {
this.nodes = nodes;
this.timeout = timeout;
this.maxAttempts = maxAttempts;
this.password = password;
this.soTimeout = soTimeout;
}
}
JedisClusterConfig.java 代码如下:
package com.qzt.common.redis;
import java.util.HashSet;
/**
* 生成JedisCluster对象
* @ClassName: JedisClusterConfig
* @author suziqing
* @date 2018年7月10日18:07:04
*/
@Slf4j
@Configuration
public class JedisClusterConfig {
@Autowired
private RedisProperties redisProperties;
/**
* 注意:
* 这里返回的JedisCluster是单例的,并且可以直接注入到其他类中去使用
* @return
*/
@Bean
public JedisCluster getJedisCluster() {
log.info("---------getJedisCluster-----");
String[] serverArray = redisProperties.getNodes().split(",");//获取服务器数组(这里要相信自己的输入,所以没有考虑空指针问题)
Set<HostAndPort> nodes = new HashSet<HostAndPort>();
log.info("---------getTimeout-----"+redisProperties.getTimeout()+"------getMaxAttempts-----"+redisProperties.getMaxAttempts());
try{
for (String ipPort : serverArray) {
String[] ipPortPair = ipPort.split(":");
log.info("----ipPortPair[0]----------"+ipPortPair[0]+"----ipPortPair[1]----------"+ipPortPair[1]);
nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim())));
}
}catch (Exception e){
log.info("-------------exception--------222----------");
}
// soTime 读取数据超时间
return new JedisCluster(nodes, redisProperties.getTimeout(), redisProperties.getSoTimeout(), redisProperties.getMaxAttempts(), redisProperties.getPassword(), new GenericObjectPoolConfig());
}
}
6)集成单机版和集群版的工具类
package com.qzt.manager;
import java.io.IOException;
@Slf4j
@Component
public class JedisManager {
@Autowired
public JedisPool jedisPool;
public static JedisManager jedisManager;
@Autowired
private JedisClusterConfig jedisClusterConfig;
@PostConstruct
public void init() {
jedisManager = this;
if (PubPara.isCloud){//平台端就使用 集群版配置
jedisManager.jedisClusterConfig = this.jedisClusterConfig;
}else{//设备端就是用单机版
jedisManager.jedisPool = this.jedisPool;
}
}
public static void set(String key, String value) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
log.info("-------jedisClusterConfig---------"+jedisManager.jedisClusterConfig);
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
jedisCluster.set(key, value);
}else{
log.info("-------jedis---333333333------"+jedisManager.jedisClusterConfig);
jedis = jedisManager.jedisPool.getResource();
jedis.set(key, value);
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
//这里不需要关闭,我们使用的是redis3.0的集群,
// 用jedis的JedisCluster.close()方法造成的集群连接关闭的情况。
// jedisCluster内部使用了池化技术,
// 每次使用完毕都会自动释放Jedis因此不需要关闭。如果调用close方法后再调用jedisCluster的api进行操作时就会出现如上错误
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static String get(String key) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
return jedisCluster.get(key);
}else{
jedis = jedisManager.jedisPool.getResource();
return jedis.get(key);
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
return null;
}
public static void del(String key) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
if (jedisCluster.exists(key)) {
jedisCluster.del(key);
}
}else{
jedis = jedisManager.jedisPool.getResource();
if (jedis.exists(key)){
jedis.del(key);
}
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static void hdel(String key,List<String> fields) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
if (jedisCluster.exists(key)) {
for(String field:fields){
jedisCluster.hdel(key, field);
}
}
}else{
jedis = jedisManager.jedisPool.getResource();
if (jedis.exists(key)){
for (String field : fields){
jedis.hdel(key, field);
}
}
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static void hdelOne(String key,String fields) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
if (jedisCluster.exists(key)) {
jedisCluster.hdel(key, fields);
}
}
else{
jedis = jedisManager.jedisPool.getResource();
if (jedis.exists(key)){
jedis.hdel(key, fields);
}
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static void hmset(String key, Map<String, String> map) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
if (jedisCluster.exists(key)) {
jedisCluster.del(key);
}
jedisCluster.hmset(key, map);
}else{
jedis = jedisManager.jedisPool.getResource();
if (jedis.exists(key)){
jedis.del(key);
}
jedis.hmset(key, map);
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static Map<String, String> hmget(String key) {
Map<String, String> map = new HashMap<String, String>();
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
if (jedisCluster.exists(key)) {
Set<String> keys = jedisCluster.hkeys(key);
for (String k : keys) {
map.put(k, jedisCluster.hmget(key, k).get(0));
}
}
}else{
jedis = jedisManager.jedisPool.getResource();
if (jedis.exists(key)){
Set<String> keys = jedis.hkeys(key);
for (String k : keys){
map.put(k, jedis.hmget(key, k).get(0));
}
}
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
return map;
}
public static Map<String, String> hmget(String key,String name) {
Map<String, String> map = new HashMap<String, String>();
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
if (jedisCluster.exists(key)) {
Set<String> keys = jedisCluster.hkeys(key);
for (String k : keys) {
if(k.contains(name)){
map.put(k, jedisCluster.hmget(key, k).get(0));
}
}
}
}else{
jedis = jedisManager.jedisPool.getResource();
if (jedis.exists(key)){
Set<String> keys = jedis.hkeys(key);
for (String k : keys){
if (k.contains(name)){
map.put(k, jedis.hmget(key, k).get(0));
}
}
}
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
return map;
}
public static boolean exists(String key) {
boolean flag = false;
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
flag = jedisCluster.exists(key);
}else{
jedis = jedisManager.jedisPool.getResource();
flag = jedis.exists(key);
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
return flag;
}
public static boolean hexists(String key,String field) {
boolean flag = false;
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
flag = jedisCluster.hexists(key, field);
}else{
jedis = jedisManager.jedisPool.getResource();
flag = jedis.hexists(key, field);
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
return flag;
}
public static void hmsetNoDel(String key, Map<String, String> map) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
jedisCluster.hmset(key, map);
}else{
jedis = jedisManager.jedisPool.getResource();
jedis.hmset(key, map);
}
} catch (Exception e) {
log.info("jedis error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static void subscribe(RedisMsgPubSubListener listener,
String redisChat) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
/**
* 注意:subscribe是一个阻塞的方法,在取消订阅该频道前,会一直阻塞在这,只有当取消了订阅才会执行下面的other code,
* 参考上面代码,我在onMessage里面收到消息后,调用了this.unsubscribe();
* 来取消订阅,这样才会执行后面的other code redisChat 频道名称
*/
jedisCluster.subscribe(listener, redisChat);
// 如果没有取消订阅,方法将一直堵塞在此处不会向下执行
// to do others
}else{
jedis = jedisManager.jedisPool.getResource();
jedis.subscribe(listener, redisChat);
}
} catch (Exception e) {
log.error("bbbbbbbbbbberror:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static void sendToC(String redisChat, String value) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
jedisCluster.publish(redisChat, value);
}else{
jedis = jedisManager.jedisPool.getResource();
jedis.publish(redisChat, value);
}
} catch (Exception e) {
log.error("error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static void hset(String key, String field, String value) {
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
jedisCluster.hset(key, field, value);
}else{
jedis = jedisManager.jedisPool.getResource();
jedis.hset(key, field, value);
}
} catch (Exception e) {
log.error("error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
}
public static String hget(String key, String field) {
String result = "";
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
result = jedisCluster.hget(key, field);
}else{
jedis = jedisManager.jedisPool.getResource();
result = jedis.hget(key, field);
}
} catch (Exception e) {
log.error("error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
return result;
}
public static long lpush(String key, String field) {
long count = 0;
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
count = jedisCluster.lpush(key, field);
}else{
jedis = jedisManager.jedisPool.getResource();
count = jedis.lpush(key, field);
}
} catch (Exception e) {
log.error("error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
return count;
}
public static List<String> lrange(String key, long start, long end) {
List<String> result = null;
JedisCluster jedisCluster = null;
Jedis jedis = null;
try {
if (PubPara.isCloud){
jedisCluster = jedisManager.jedisClusterConfig.getJedisCluster();
result = jedisCluster.lrange(key, start, end);
}else{
jedis = jedisManager.jedisPool.getResource();
result = jedis.lrange(key, start, end);
}
} catch (Exception e) {
log.error("error:", e);
} finally {
if (!PubPara.isCloud){
jedis.close();
}
}
return result;
}
}
7)测试类测试 在一个controller中写如下代码进行测试
@RequestMapping("/jedis/test")
public void testLicense(){
JedisCluster jedisCluster = jedisClusterConfig.getJedisCluster();
// String className = jedisCluster.get("class");
// log.info("班级="+className);
// String age = jedisCluster.get("age");
// log.info("年龄="+age);
// jedisCluster.set("yanzhenma","87878");
// String yanzhenma = jedisCluster.get("yanzhenma");
// log.info("验证码="+yanzhenma);
// List<String> list = jedisCluster.lrange("list", 0, -1);
// for (String string : list){
// log.info("-------result------"+string);
// }
//
JedisManager.set("feiyi", "kunhua");
String string = JedisManager.get("feiyi");
log.info("---------string---------"+string);
JedisManager.hset("qwe", "www", "eee");
String hget = JedisManager.hget("qwe", "www");
log.info("----hget-------"+hget);
}
注:在整合的过程中遇到一些问题:
1)第一个就是启动不了的问题,老是报 数字转化异常 ,日志打印出来都是数字没有问题得,上网找了以后明白了是jedis版本过低导致的,将jedis改为 2.9 就可以了
2)第二个问题就是使用集群版的时候 我写了这么一句: jedisCluster.close(); 导致使用使用jedis操作redis的时候报错,抛出JedisNoReachableClusterNodeException异常(No reachable node in cluster) ,通过网上查询明白jedisCluster内部使用了池化技术, 每次使用完毕都会自动释放Jedis因此不需要关闭。如果调用close方法后再调用jedisCluster的api进行操作时就会出现如上错误。
3)第三个就是我们需要将单机版和集群版在一个项目中都还可以使用,通过配置文件来控制使用集群版还是单机版。为了这个需求就有了上面工具类中的判断是否为平台端的代码。
4)前面说了推荐使用jedis 来连接redis,好处就是连接方便简单,最后测试证明单机版和集群版都可以在一套代码中实现