在方法之间传递jedis实例是不好的做法?

时间:2016-11-21 14:26:14

标签: java redis jedis apache-commons-pool

我指的是这个SO question,我在这个基准测试中做了几个补充。主要问题是随着服务器负载的增加,我的apis变慢了。我正在使用jedis池配置。

// get a new instance
    public synchronized Jedis getJedi() {
    try {
        return jedisPool.getResource();
    } catch (Exception e) {
        log.fatal("REDIS CONN ERR:", e);
        return null;
    }
    }

// intialize at start
    public void initialize() {
    if (jedisPool == null) {
        IniUtils cp = PropertyReader.getConnPoolIni();

        String host = cp.get(REDIS, REDIS_HOST);
        int port = Integer.parseInt(cp.get(REDIS, REDIS_PORT));
        String password = cp.get(REDIS, REDIS_PASSWORD);
        int timeout = Integer.parseInt(cp.get(REDIS, REDIS_TIMEOUT));

        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(Integer.parseInt(cp.get(REDIS, REDIS_MAX_TOTAL_CONNECTIONS)));
        poolConfig.setMaxIdle(Integer.parseInt(cp.get(REDIS, REDIS_MAX_IDLE)));
        poolConfig.setMinIdle(Integer.parseInt(cp.get(REDIS, REDIS_MIN_IDLE)));
        poolConfig.setMaxWaitMillis(Long.parseLong(cp.get(REDIS, REDIS_MAX_WAIT_TIME_MILLIS)));

        poolConfig.setTestOnBorrow(true);
        poolConfig.setTestOnReturn(true);
        poolConfig.setTestWhileIdle(true);

        if (password != null && !password.trim().isEmpty()) {
        jedisPool = new JedisPool(poolConfig, host, port, timeout, password);
        } else {
        jedisPool = new JedisPool(poolConfig, host, port, timeout);
        }

        test();

      }
    }

    @Override
    public void destroy() {
      if (jedisPool.isClosed() == false)
          jedisPool.destroy();
    }

    private void test() {
      try (Jedis test = getJedi()) {
        log.info("Testing Redis:" + test.ping());
      }
    }

在使用时,我在try-with-resources中获取Jedis实例并对其进行处理。我使用非常少的流水线操作,并且有对Redis的各种调用,因此每次进行方法调用时,都会创建一个新的jedis实例。

根据共享的问题,我的实施将导致非常缓慢的结果。因此,我可以将Jedis实例传递给方法,并根据业务逻辑使用管道。 像这样的东西 -

  public void push5(int n) {
    try (Jedis jedi = redisFactory.getJedi()) {
        pushWithResource(n, jedi, 0);
    }
  }

  public void pushWithResourceAndPipe(int n, Jedis jedi, int k) {
    if (k >= n)
        return;
    Pipeline pipeline = jedi.pipelined();
    map.put("id", "" + i);
    map.put("name", "lyj" + i);
    pipeline.hmset("m" + i, map);
    ++i;
    pushWithResourceAndPipe(n, jedi, ++k);
    pipeline.sync();
  }

    public void pushWithResource(int n, Jedis jedi, int k) {
    if (k >= n)
        return;
    map.put("id", "" + i);
    map.put("name", "lyj" + i);
    jedi.hmset("m" + i, map);
    ++i;
    pushWithResource(n, jedi, ++k);
  }

有没有办法改善api通话? 你能推荐一些在服务器端使用jedis的项目,这样我就能更好地理解如何有效地使用jedis。

Redis / Jedis配置

Jedis版本:2.8.1  Redis版本:2.8.4  Java版本:1.8

1 个答案:

答案 0 :(得分:1)

  1. getJedi不需要'同步',因为JedisPool是线程安全的。
  2. 如果您的逻辑可以容忍从setTestOnBorrow添加延迟,则可以禁用其他内容(setTestOnReturn,setTestWhileIdle)。如果您的逻辑可以容忍重试,则禁用setTestOnBorrow应该会有所帮助。 (因为它总是对每次借用进行乒乓检查)
  3. 你的pushWithResourceAndPipe有错误:你正在为每个递归调用创建管道实例,这可能比pushWithResource“慢”。我认为您打算将所有请求添加到一个管道并进行同步,然后您需要传递管道实例并从调用者调用同步。