Redis错误使用导致并发上不去

前言

抛出问题

用户发送http请求,并发总是上不去,JMeter100个压测都需要十几秒,再多点会报告redis连接超时

接口说明

接口功能仅为接收参数丢入MQ中,拦截器会去拦截记录请求

优化过程

最小化处理

修改MQ后续业务逻辑,设为sleep1秒

打印处理时间

将执行接口相关代码加入处理时间打印
eg.

long t3=System.currentTimeMillis();     
JSONObject beansObject = JSONObject.parseObject(tokenList.get("beanList"));
long t4=System.currentTimeMillis();

单个处理时间结果

  1. jedisUtil.existKey(key)耗时140ms+
  2. jedisUtil.getKey(key)耗时80ms+

优化existKey方法

将existKey改为getKey方式,避免重复获取value值
优化完,只会执行getKey一次时间
eg.

String arrayString=ipWhiteList.jedisUtil.getFromCache(CommonUtil.getRedisKey(ConstantComm.IP_TABLES_WHITE_KEY));
long t2=System.currentTimeMillis();
System.out.println("获取缓存时间: "+(t2 - t1)+"ms");
//先查缓存
if (arrayString==null) {
    List<String> ipList=ipWhiteList.ipTablesDao.queryIpList(params);
    arrayString=JSON.toJSONString(ipList).toString();
    ipWhiteList.jedisUtil.put2Cache(CommonUtil.getRedisKey(ConstantComm.IP_TABLES_WHITE_KEY), arrayString);
    return ipList;
}else {
    return JSONObject.parseArray(arrayString, String.class);
}

再压测100个并发

程序运行时间: 17689ms
程序运行时间: 17701ms
程序运行时间: 17714ms
程序运行时间: 17730ms
程序运行时间: 17740ms
程序运行时间: 17756ms
程序运行时间: 17763ms
程序运行时间: 17773ms
程序运行时间: 17780ms
程序运行时间: 17789ms
程序运行时间: 17798ms
程序运行时间: 17810ms

发现时间随着并发量变大而变大

优化思路

  1. Redis瓶颈?
  2. Jedis连接瓶颈?

检查是否为Redis瓶颈

查看redis慢查询

https://www.cnblogs.com/huamei2008/p/8850047.html

发现在并发数变大时,redis查询时间会变大,但也仅限于微秒级别,所以排除redis自身问题

检查Jedis连接

这个时候头都大了,按理说单次查询redis时间不至于到80ms,而且随着并发量变大几乎呈指数增长。
话不多说,检查jedis代码

@Configuration
public class JedisClusterConfig {
    @Autowired
    private RedisProperties redisProperties;

    public JedisCluster getJedisCluster(){
        String [] serverArray=redisProperties.getClusterNodes().split(",");
        Set<HostAndPort> nodes=new HashSet<>();

        for (String ipPort:serverArray){
            String [] ipPortPair=ipPort.split(":");
            nodes.add(new HostAndPort(ipPortPair[0].trim(),Integer.valueOf(ipPortPair[1].trim())));

        }
        String redisAuthPass = redisProperties.getRedisAuthPass();
        return  new JedisCluster(nodes,2000, 2000, 6, redisAuthPass, new JedisPoolConfig());
    }

}
@Component
public class JedisUtil {

	@Autowired
	private JedisClusterConfig jedisClusterConfig;
	/*public static JedisUtil testUtils;
    
    @PostConstruct
    public void init() {    
        testUtils = this;
    } */
	/**
     * 放入缓存
     * 
     * @param cacheKey key
     * @param value
     * @return
     */
    public void put2Cache(String cacheKey, String value) throws Exception {
        jedisClusterConfig.getJedisCluster().set(cacheKey, value);
    }
...
}

仔细一看发现代码有点怪,获取redis值的方法竟然不是静态方法
每次都要使用autowired重新生成bean,而且JedisClusterConfig 竟然也没有将链接静态化

调整静态方法

@Configuration
public class JedisClusterConfig {
    
    private static RedisProperties redisProperties;
    
    private static JedisCluster jedisCluster = null;
    
    @Autowired
    private RedisProperties redisProperties2;
 
    @PostConstruct
    public void init() {
        redisProperties = redisProperties2;
        if (jedisCluster==null) {
            try {
                jedisCluster = reloadJedisCluster();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 获取JedisCluster对象
     * 
     * @return
     * @throws Exception
     */
    public static JedisCluster getCluster() throws Exception {
        if (jedisCluster == null) {
            synchronized (JedisClusterConfig.class) {
                jedisCluster = reloadJedisCluster();
            }
            return jedisCluster;
        } else {
            return jedisCluster;
        }
    }
    
//    public static JedisCluster getJedisCluster(){
//        String [] serverArray=redisProperties.getClusterNodes().split(",");
//        Set<HostAndPort> nodes=new HashSet<>();
//
//        for (String ipPort:serverArray){
//            String [] ipPortPair=ipPort.split(":");
//            nodes.add(new HostAndPort(ipPortPair[0].trim(),Integer.valueOf(ipPortPair[1].trim())));
//
//        }
//        String redisAuthPass = redisProperties.getRedisAuthPass();
//        return  new JedisCluster(nodes,2000, 2000, 6, redisAuthPass, new JedisPoolConfig());
//    }
    
    private static JedisCluster reloadJedisCluster() throws Exception {
        System.out.println("初始化实体");
        JedisCluster cluster = null;
        String redisAuthPass = redisProperties.getRedisAuthPass();
        String[] addrs = redisProperties.getClusterNodes().split(",");
        Set<HostAndPort> nodes=new HashSet<>();
        for (String ipPort:addrs){
            String [] ipPortPair=ipPort.split(":");
            nodes.add(new HostAndPort(ipPortPair[0].trim(),Integer.valueOf(ipPortPair[1].trim())));
        }
        cluster = new JedisCluster(nodes, 2000, 2000, 6, redisAuthPass, new JedisPoolConfig());
        return cluster;
    }
}
@Component
public class JedisUtil {

	/*public static JedisUtil testUtils;
    
    @PostConstruct
    public void init() {    
        testUtils = this;
    } */
	/**
     * 放入缓存
     * 
     * @param cacheKey key
     * @param value
     * @return
     */
    public void put2Cache(String cacheKey, String value) throws Exception {
        JedisClusterConfig.getCluster().set(cacheKey, value);
    }
}    

再压测 问题解决

发现时间稳定在4-8ms之间,并发上去之后依然不变

问题思考

最后发现并不是redis的锅,也不是jedis的锅,redis完全可以适应高并发场景(本来就为此而生)
那么问题来了,是因为初始化bean占用内存空间导致???
请各位大神指点一二

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值