背景
在将redis切换到redis cluster中,也遇到一些问题,借此机会和大家分享一下。
1.spring-data-redis与ibatis冲突
使用spring-data-redis操作redis cluster的话,必须将spring版本升级至4.x以上。
如果老项目中使用了ibatis的话,只能用spring3.x ,无法兼容redis cluster。有两个方法解决:
1)使用mybatis替换ibatis,升级spring至4.x版本
2)使用JedisCluster
封装RedisCluster
2.基于JedisCluster进行简单封装
因为看到JedisCluster的配置比较复杂,因此对其进行简单的封装,代码如下:
package com.utils;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by Administrator on 2017/9/26.
*/
public class RedisClusterManager {
private int threadSize=10;
private int maxTotal=500;
private int maxIdle=100;
private int maxWaitMillis=3000;
private int timeout=1000;
private String redisNodes;
ExecutorService executorService;
JedisCluster jedisCluster;
public void asyncSet(String key,String value){
executorService.execute(new RunOnce(Type.SET,key,value,jedisCluster));
}
public void asyncSetExpire(String key,String value,int expire){
executorService.execute(new RunOnce(Type.SET,key,value,expire,jedisCluster));
}
public void asyncDel(String key){
executorService.execute(new RunOnce(Type.DEL,key,jedisCluster));
}
public void asyncHmset(String key,Map<String,String> hmset){
executorService.execute(new RunOnce(Type.HMSET,key,hmset,jedisCluster));
}
public void asyncHmsetExpire(String key,Map<String,String> hmset,int expire){
executorService.execute(new RunOnce(Type.HMSET,key,hmset,expire,jedisCluster));
}
public String get(String key){
return jedisCluster.get(key);
}
public Map<String,String> hgetAll(String key){
return jedisCluster.hgetAll(key);
}
public Boolean exists(String key){
return jedisCluster.exists(key);
}
public void set(String key,String value){
jedisCluster.set(key,value);
}
public void setExpire(String key,String value,int expire){
jedisCluster.set(key,value);
jedisCluster.expire(key,expire);
}
public Long del(String key){
return jedisCluster.del(key);
}
public void hmset(String key,Map<String,String> hmset){
jedisCluster.hmset(key,hmset);
}
public void hmsetExpire(String key,Map<String,String> hmset,int expire){
jedisCluster.hmset(key,hmset);
jedisCluster.expire(key,expire);
}
public List<String> hmget(String key,String[] propertys){
return jedisCluster.hmget(key,propertys);
}
public void init(){
if(null == redisNodes||"".equals(redisNodes.trim())) throw new RuntimeException("shardNodes is empty");
String[] addresses = redisNodes.split(",");
if(null == addresses||addresses.length==0) throw new RuntimeException("ip or port is empty");
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
for(String address: addresses){
String[] addr = address.split(":");
jedisClusterNodes.add(new HostAndPort(addr[0],Integer.valueOf(addr[1])));
}
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMaxWaitMillis(maxWaitMillis);
jedisCluster = new JedisCluster(jedisClusterNodes,timeout,poolConfig);
executorService = Executors.newFixedThreadPool(threadSize);
}
public void destory(){
executorService.shutdownNow();
try {
jedisCluster.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class RunOnce implements Runnable{
Type type;
String key;
String value;
Map<String,String> hmset;
int expire=-1;
JedisCluster jedisCluster;
public RunOnce(Type type, String key, JedisCluster jedisCluster) {
this.type = type;
this.key = key;
this.jedisCluster = jedisCluster;
}
public RunOnce(Type type, String key, String value, int expire, JedisCluster jedisCluster) {
this.type = type;
this.key = key;
this.value = value;
this.expire = expire;
this.jedisCluster = jedisCluster;
}
public RunOnce(Type type, String key, Map<String, String> hmset, JedisCluster jedisCluster) {
this.type = type;
this.key = key;
this.hmset = hmset;
this.jedisCluster = jedisCluster;
}
public RunOnce(Type type, String key, String value, JedisCluster jedisCluster) {
this.type = type;
this.key = key;
this.value = value;
this.jedisCluster = jedisCluster;
}
public RunOnce(Type type, String key, Map<String, String> hmset, int expire, JedisCluster jedisCluster) {
this.type = type;
this.key = key;
this.hmset = hmset;
this.expire = expire;
this.jedisCluster = jedisCluster;
}
@Override
public void run() {
if(Type.SET.equals(type)){
jedisCluster.set(key,value);
if(expire!=-1) jedisCluster.expire(key,expire);
}else if(Type.DEL.equals(type)){
jedisCluster.del(key);
}else if(Type.HMSET.equals(type)){
jedisCluster.hmset(key,hmset);
if(expire!=-1) jedisCluster.expire(key,expire);
}
}
}
enum Type {
SET,DEL,HMSET;
}
public void setThreadSize(int threadSize) {
this.threadSize = threadSize;
}
public void setRedisNodes(String redisNodes) {
this.redisNodes = redisNodes;
}
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public void setMaxWaitMillis(int maxWaitMillis) {
this.maxWaitMillis = maxWaitMillis;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}
1)实现功能
封装了set,expire,del,hmset,get,hgetAll,exists,hmget方法,并提供异步支持
2)spring配置
<bean id="redisClusterManager" class="com.utils.RedisClusterManager" init-method="init" destroy-method="destory">
<property name="redisNodes" value="redis-cluster0.service.baihe:6379,redis-cluster1.service.baihe:6379,........" />
<property name="threadSize" value="50" /> <!-- 可省略,默认是10 -->
<property name="maxTotal" value="500"/> <!-- 可省略,默认是500 -->
<property name="maxIdle" value="100"/> <!-- 可省略,默认是100 -->
<property name="maxWaitMillis" value="3000"/> <!-- 可省略,默认是3000 -->
<property name="timeout" value="1000" /> <!-- 可省略,默认是1000 -->
</bean>
3)代码使用
import com.utils.RedisClusterManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
/**
* Created by Administrator on 2017/9/26.
*/
public class RedisClusterManagerJunit {
RedisClusterManager manager;
@Before
public void init(){
manager = new RedisClusterManager();
manager.setRedisNodes("" +
"redis-cluster0.service.baihe:6379," +
"redis-cluster1.service.baihe:6379," +
"redis-cluster2.service.baihe:6379," +
"redis-cluster3.service.baihe:6379," +
"redis-cluster4.service.baihe:6379," +
"redis-cluster5.service.baihe:6379," +
"redis-cluster6.service.baihe:6379," +
"redis-cluster7.service.baihe:6379," +
"redis-cluster8.service.baihe:6379," +
"redis-cluster9.service.baihe:6379");
manager.init();
}
@After
public void destory(){
manager.destory();
}
@Test
public void set() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(100000);
for(int i=0;i<100000;i++){
manager.set("test"+i,"1");
latch.countDown();
}
latch.await();
}
@Test
public void get() throws InterruptedException {
for(int i=0;i<100000;i++){
System.out.println(manager.get("test"+i));
}
}
@Test
public void exists(){
for(int i=0;i<100000;i++){
System.out.println(manager.exists("test"+i));
}
}
@Test
public void del(){
for(int i=0;i<100000;i++){
manager.del("test"+i);
System.out.println("test"+i);
}
}
}