Jedis getResource()花了很多时间

时间:2015-05-21 09:39:36

标签: redis jedis jvisualvm spring-data-redis

我正在尝试使用sentinal redis从redis获取/设置密钥。我试图用大约2000个并发请求来强调测试我的设置。

我使用sentinel将一个密钥放在redis上,然后我从redis执行了1000个并发的get请求。

但底层的jedis使用我的sentinel阻止对getResource()的调用(池大小为500),我实现的总体平均响应时间约为500 ms,但我的目标是大约10 ms。

我在这里附上jvisualvm快照的样本

redis.clients.jedis.JedisSentinelPool.getResource() 98.02227    4.0845232601E7 ms   4779
redis.clients.jedis.BinaryJedis.get()   1.6894469   703981.381 ms   141
org.apache.catalina.core.ApplicationFilterChain.doFilter()  0.12820946  53424.035 ms    6875
org.springframework.core.serializer.support.DeserializingConverter.convert()    0.046286926 19287.457 ms    4
redis.clients.jedis.JedisSentinelPool.returnResource()  0.04444578  18520.263 ms    4
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept()   0.035538    14808.45 ms 11430

是否有人可以帮助进一步调试此问题?

1 个答案:

答案 0 :(得分:1)

来自Jedis来源(2.6.2)的getResource()的JedisSentinelPool实现:

@Override
public Jedis getResource() {
    while (true) {
      Jedis jedis = super.getResource();
      jedis.setDataSource(this);

      // get a reference because it can change concurrently
      final HostAndPort master = currentHostMaster;
      final HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), jedis.getClient()
          .getPort());

      if (master.equals(connection)) {
        // connected to the correct master
        return jedis;
      } else {
        returnBrokenResource(jedis);
      }
    }
}

注意while(true)returnBrokenResource(jedis),这意味着它试图从确实连接到正确主服务器的池中随机获取jedis资源,如果它不是好主服务器则重试。这是一个肮脏的支票,也是一个阻止电话。

super.getResource()调用是指实际基于Apache Commons Pool(2.0)的JedisPool传统实现。它从池中获取对象做了很多工作,我认为它甚至可以修复失败的连接。在您的池中存在大量争用,可能在压力测试中,从池中获取资源可能需要花费大量时间,只是为了看到它没有连接到正确的主服务器,所以最终调用它再次,增加争用,减缓获取资源等...

您应该检查池中的所有jedis实例,看看是否存在很多“不好”的情况。连接。

也许你应该放弃使用公共池进行压力测试(只创建手动连接到正确节点的Jedis实例,然后很好地关闭它们),或者设置多个实例池以降低查看"脏的成本#34;未经检查的jedis资源。

对于500个jedis实例池,您无法模拟1000个并发查询,至少需要1000个。