maven
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.5.0</version>
</dependency>
1、单机:
public class RedisUtils {
private static Logger logger = LoggerFactory.getLogger(RedisUtils.class);
private JedisPool pool = null;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(2000);
config.setMaxIdle(200);
config.setMaxWaitMillis(1000 * 3);
config.setTestOnBorrow(true);
config.setTestOnReturn(true);
config.setTestWhileIdle(true);
config.setTimeBetweenEvictionRunsMillis(1000 * 120);
pool = new JedisPool(config, host, Integer.valueOf(port),1000 * 60,pwd);
}
public static String get(String key) {
String value = null;
Jedis jedis = null;
try {
jedis = pool.getResource();
value = jedis.get(key);
} catch (Exception e) {
logger.error("RedisUtils.get first fail, key=" + key, e);
try {
value = jedis.get(key);
} catch (Exception e1) {
success = false;
logger.error("RedisUtils.get second fail, key=" + key, e1);
}
} finally {
recycleJedis(pool, jedis, success);
}
return value;
}
...
private static void recycleJedis(JedisPool pool, Jedis jedis, boolean success) {
if (success) {
try {
pool.returnResource(jedis);
} catch (Exception e) {}
} else {
try {
pool.returnBrokenResource(jedis);
} catch (Exception e) {}
}
}
}
2、cluster版:
public class RedisUtils {
private static Logger logger = LoggerFactory.getLogger(RedisUtils.class);
private static JedisCluster cluster = null;
static {
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 最大连接数
poolConfig.setMaxTotal(300);
// 最大空闲数
poolConfig.setMaxIdle(30);
// 最大允许等待时间,如果超过这个时间还未获取到连接,则会报JedisException异常:
// Could not get a resource from the pool
poolConfig.setMaxWaitMillis(1000);
Set<HostAndPort> nodes = new LinkedHashSet<HostAndPort>();
nodes.add(new HostAndPort("130.349.57.218", 1738));
nodes.add(new HostAndPort("130.349.57.221", 1738));
nodes.add(new HostAndPort("130.349.57.209", 1738));
nodes.add(new HostAndPort("130.349.57.187", 1738));
nodes.add(new HostAndPort("130.349.57.220", 1738));
nodes.add(new HostAndPort("130.349.57.201", 1738));
nodes.add(new HostAndPort("130.349.57.202", 1738));
nodes.add(new HostAndPort("130.349.57.203", 1738));
cluster = new JedisCluster(nodes, poolConfig);
}
public static String get(String key) {
String value = null;
try {
value = cluster.get(key);
} catch (Exception e) {
logger.error("RedisUtils.get fail, key={}",key, e);
}
return value;
}
public static void closeCluster() {
try {
cluster.close();
} catch (IOException e) {
logger.error("close cluster is error...",e);
}
}
public static void main(String...strings) {
System.out.println(RedisUtils.get("o_1548664656920213070643316836998AADCE0D3C73902FBCCC1475D"));
}
}
注:使用cluster版本时,不需要JedisCluster.close(),否则会报如下错误
redis.clients.jedis.exceptions.JedisNoReachableClusterNodeException: No reachable node in cluster
at redis.clients.jedis.JedisSlotBasedConnectionHandler.getConnection(JedisSlotBasedConnectionHandler.java:57)
at redis.clients.jedis.JedisSlotBasedConnectionHandler.getConnectionFromSlot(JedisSlotBasedConnectionHandler.java:74)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:116)
at redis.clients.jedis.JedisClusterCommand.run(JedisClusterCommand.java:31)
at redis.clients.jedis.JedisCluster.get(JedisCluster.java:124)
at cn.tbnb1.service.redis.RedisCacheService.get(RedisCacheService.java:55)
at cn.tbnb1.seckil.controller.SeckillController.resultQuery(SeckillController.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
原因:我们使用的是redis3.0的集群,用jedis的JedisCluster.close()方法造成的集群连接关闭的情况。 jedisCluster内部使用了池化技术,每次使用完毕都会自动释放Jedis因此不需要关闭。如果调用close方法后再调用jedisCluster的api进行操作时就会出现如上错误。
3、sentinel版本:
public class RedisSentinelClient {
private static JedisSentinelPool pool = null;
private static String redisHosts = "127.0.0.1:26378;127.0.0.1:26379;127.0.0.1:26380";
private static String redisMaster = "";//master name
private static String password = "";//密码,可选
private static final int MAX_IDLE = 200;//最大空闲数
private static final int MAX_TOTAL = 400;//最大连接数
private static final int MIN_IDLE = 200;//最小空闲数
static {
//redis 连接池配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(MAX_IDLE);
poolConfig.setMaxTotal(MAX_TOTAL);
poolConfig.setMinIdle(MIN_IDLE);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
Set<String> hosts = new HashSet<String>(Arrays.asList(redisHosts.split(";")));
if (StringUtils.isBlank(password)) {
pool = new JedisSentinelPool(redisMaster, hosts, poolConfig);
} else {
pool = new JedisSentinelPool(redisMaster, hosts, poolConfig, password);
}
}
public String get(String key) throws JedisConnectionException {
Jedis jedis = pool.getResource();
try {
return jedis.get(key);
} catch (JedisConnectionException e) {
throw e;
} finally {
jedis.close();
}
}
}
在生产环境中一定要配置GenericObjectPoolConfig中的 maxIdle、maxTotal、minIdle.因为里面默认值太低了,如果生产环境中流量比较大的话,就会出现等待redis的连接的情况。为了更好的使用redis 连接池,建议采用 JedisPoolConfig来替代GenericObjectPoolConfig。JedisPoolConfig里面有一些默认的参数。
当然,jedis中还包括了sharding功能(redis cluster未出现之前,多采用这种sharding方式组件集群,内部原理是通过一致性hash实现),具体使用见:
https://blog.csdn.net/liuxiao723846/article/details/86744772