今天生产突然出现数据库链接数过多,链接池链接不上的问题
1、查看redis的连接数的详情
使用命令查询发现大量来自181的redis使用的链接没有被释放掉。
netstat -anp | grep ESTABLISHED
netstat -anp | grep ESTABLISHED | wc -l
2、查看redis链接的代码
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.neusoft.www.score.javabean.bean.CheckInRecordBean;
import com.neusoft.www.util.SystemConfig;
import net.sf.json.JSONObject;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
public class RedisUtil {
private Logger logger = Logger.getLogger(RedisUtil.class);
public static JedisCluster jedis;
public void initRedisConfig(){
try {
String minIdle = SystemConfig.getProperty("redis.minIdle");
String maxIdle = SystemConfig.getProperty("redis.maxIdle");
String maxTotal = SystemConfig.getProperty("redis.maxTotal");
String maxWaitMillis = SystemConfig.getProperty("redis.maxWaitMillis");
String timeout = SystemConfig.getProperty("redis.timeout");
String testOnBorrow = SystemConfig.getProperty("redis.testOnBorrow");
String clusterNodes = SystemConfig.getProperty("redis.cluster.nodes");
String maxRedirects = SystemConfig.getProperty("redis.cluster.max-redirects");
// 添加集群的服务节点Set集合
Set<HostAndPort> hostAndPortsSet = new HashSet<HostAndPort>();
String[] ipArry = clusterNodes.split(",");
for (String ip : ipArry) {
// 添加节点
hostAndPortsSet.add(new HostAndPort(ip.split(":")[0],Integer.parseInt(ip.split(":")[1])));
}
// Jedis连接池配置
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大空闲连接数, 默认8个
jedisPoolConfig.setMaxIdle(Integer.parseInt(maxIdle));
// 最大连接数, 默认8个
jedisPoolConfig.setMaxTotal(Integer.parseInt(maxTotal));
//最小空闲连接数, 默认0
jedisPoolConfig.setMinIdle(Integer.parseInt(minIdle));
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
jedisPoolConfig.setMaxWaitMillis(Integer.parseInt(maxWaitMillis)); // 设置2秒
//对拿到的connection进行validateObject校验
jedisPoolConfig.setTestOnBorrow(Boolean.parseBoolean(testOnBorrow));
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(Integer.parseInt(timeout));
jedis = new JedisCluster(hostAndPortsSet, jedisPoolConfig);
logger.info("=====配置完毕连接Redis集群..."+clusterNodes);
} catch (Exception e) {
logger.info("====initRedisConfig exception:" + e.getMessage());
}
}
}
分析原因有可能是因为链接对象没有被释放的原因
3、更换新的链接池的方法
package com.pay.common.config;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @program: spring-boot-pay-master
* @description: LpPoolFactory
* @author: sunyuhua
* @create: 2021-08-26 21:53
**/
public class LpPoolFactory implements PooledObjectFactory<JedisCluster> {
/**
* 功能描述:激活资源对象
*
* 什么时候会调用此方法
* 1:从资源池中获取资源的时候
* 2:资源回收线程,回收资源的时候,根据配置的 testWhileIdle 参数,
* 判断 是否执行 factory.activateObject()方法,true 执行,false 不执行
* @param arg0
*/
public void activateObject(PooledObject<JedisCluster> arg0) throws Exception {
System.out.println("activate Object");
}
/**
* 链接被销毁的时候调用本对象
* @param arg0
* @throws Exception
*/
public void destroyObject(PooledObject<JedisCluster> arg0) throws Exception {
System.out.println("destroy Object");
JedisCluster JedisCluster = arg0.getObject();
JedisCluster = null;
}
/**
* 链接池被创建的时候调用本对象
* @return
* @throws Exception
*/
public PooledObject<JedisCluster> makeObject() throws Exception {
System.out.println("make Object");
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 最大连接数
poolConfig.setMaxTotal(300);
// 最大空闲数
poolConfig.setMaxIdle(10);
// 最大允许等待时间,如果超过这个时间还未获取到连接,则会报JedisException异常:
// Could not get a resource from the pool
poolConfig.setMaxWaitMillis(1000);
Set<HostAndPort> nodes = new LinkedHashSet<HostAndPort>();
nodes.add(new HostAndPort("192.168.88.140", 7000));
nodes.add(new HostAndPort("192.168.88.140", 7001));
nodes.add(new HostAndPort("192.168.88.140", 7002));
nodes.add(new HostAndPort("192.168.88.140", 7003));
nodes.add(new HostAndPort("192.168.88.140", 7004));
nodes.add(new HostAndPort("192.168.88.140", 7005));
JedisCluster JedisCluster = new JedisCluster(nodes, poolConfig);
return new DefaultPooledObject<JedisCluster>(JedisCluster);
}
/**
* 功能描述:钝化资源对象
*
* 什么时候会调用此方法
* 1:将资源返还给资源池时,调用此方法。
*/
public void passivateObject(PooledObject<JedisCluster> arg0) throws Exception {
System.out.println("passivate Object");
}
/**
* 功能描述:判断资源对象是否有效,有效返回 true,无效返回 false
*
* 什么时候会调用此方法
* 1:从资源池中获取资源的时候,参数 testOnBorrow 或者 testOnCreate 中有一个 配置 为 true 时,则调用 factory.validateObject() 方法
* 2:将资源返还给资源池的时候,参数 testOnReturn,配置为 true 时,调用此方法
* 3:资源回收线程,回收资源的时候,参数 testWhileIdle,配置为 true 时,调用此方法
*/
public boolean validateObject(PooledObject<JedisCluster> arg0) {
System.out.println("validate Object");
return true;
}
}
package com.pay.common.config;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.JedisCluster;
/**
* @program: spring-boot-pay-master
* @description: RedisClusterPool
* @author: sunyuhua
* @create: 2021-08-26 21:52
**/
public class RedisClusterPool {
public static GenericObjectPool<JedisCluster> objectPool=null;
static {
//工厂
LpPoolFactory factory = new LpPoolFactory();
//资源池配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
//设置最大实例总数
poolConfig.setMaxTotal(500);
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
poolConfig.setMinIdle(1);
poolConfig.setMaxIdle(1);
//表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;
poolConfig.setMaxWaitMillis(1000);
// 在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的;
poolConfig.setTestOnBorrow(true);
// 在还会给pool时,是否提前进行validate操作
poolConfig.setTestOnReturn(true);
//如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;
poolConfig.setTestWhileIdle(true);
//表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;
poolConfig.setMinEvictableIdleTimeMillis(6000);
//表示idle object evitor两次扫描之间要sleep的毫秒数
poolConfig.setTimeBetweenEvictionRunsMillis(30000);
//在minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。如果为-1,evicted不会根据idle time驱逐任何对象。如果minEvictableIdleTimeMillis>0,则此项设置无意义,且只有在timeBetweenEvictionRunsMillis大于0时才有意义
// poolConfig.setSoftMinEvictableIdleTimeMillis();
//创建资源池
objectPool = new GenericObjectPool<JedisCluster>(factory,poolConfig);
}
@SuppressWarnings("finally")
public static JedisCluster getJedisCluster(){
JedisCluster jedisCluster=null;
try {
jedisCluster = objectPool.borrowObject();
} catch (Exception e) {
e.printStackTrace();
}finally{
return jedisCluster;
}
}
public static void closeJedisCluster(JedisCluster jedisCluster ){
if(jedisCluster!=null){
objectPool.returnObject(jedisCluster);
}
}
}
调用方法修改为
RedisClusterPool.getJedisCluster().incr("XXXXXXX");