RedisCluster报链接池数量过多链接不上的问题解决

今天生产突然出现数据库链接数过多,链接池链接不上的问题

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");
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用 RedisCluster 的连接可以提高应用程序访问 RedisCluster 的效率和性能,可以减少连接的开销,避免频繁的重连,以及减轻 RedisCluster 服务器的负载。 下面是一个使用 RedisCluster 连接的示例代码: ```python from rediscluster import RedisCluster from redis.connection import ConnectionPool startup_nodes = [{"host": "127.0.0.1", "port": "7000"}] pool = ConnectionPool.from_url("redis://127.0.0.1:7000", max_connections=50) redis_cluster = RedisCluster(startup_nodes=startup_nodes, connection_pool=pool) # 使用连接执行 RedisCluster 命令 result = redis_cluster.get("foo") print(result) ``` 在上面的代码中,我们先创建了一个 RedisCluster 的连接,然后将其作为参数传递给 RedisCluster 的构造函数,以便在创建 RedisCluster 实例时使用该连接。 `max_connections` 参数指定连接中的最大连接数。当连接请求超过这个数时,会等待其他连接释放资源后再进行连接。该参数可以根据实际情况进行调整。 在使用 RedisCluster 进行数据操作时,我们可以通过 `redis_cluster` 对象来执行 RedisCluster 命令,RedisCluster 内部会自动从连接中获取连接,并在命令执行完毕后将连接放回连接中。 需要注意的是,只有在多个线程或协程同时访问同一个 RedisCluster 实例时才需要使用连接。如果只有单个线程或协程访问 RedisCluster,不需要使用连接,直接使用 RedisCluster 的实例即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MonkeyKing.sun

对你有帮助的话,可以打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值