Просмотр конфигурации параметров JedispoolConfig из исходного кода

Redis
Просмотр конфигурации параметров JedispoolConfig из исходного кода

будь позитивным человеком

Пишите, исправляйте ошибки, улучшайте себя

У меня рай, ориентированный на программирование, и цветут весенние цветы!

Привет,JedisPoolConfig

использовать в javaJedisкак связьRedis的工具。 в настоящее время используетJedisТакже можно настроитьJedisPoolпул соединений,JedisPoolБольшинство параметров конфигурации определяютсяJedisPoolConfigприсваивается соответствующему пункту. В этой статье кратко описываются несколько часто используемых конфигураций, а затем передается исходный код (версияjedis-3.1.0) позволяет понять принципы настройки этих параметров.

Давайте сначала разберемся с некоторыми идеями и преимуществами объединения ((пул объектов, пул соединений с базой данных, пул потоков и т. д.)). легко столкнутьсяJedisPoolConfigпонимание конфигурации.

Основная идея объединения:

1. Вы можете создавать некоторые объекты при инициализации, а не получать их напрямую из пула, когда вам нужно их использовать, что улучшает скорость отклика;

2. Используемые объекты не уничтожаются, а сохраняются.Когда объект понадобится в следующий раз, его можно вынуть и использовать повторно, чтобы уменьшить накладные расходы, вызванные частым созданием объекта;

3. Созданные объекты единообразно хранятся, управляются и обслуживаются.

Резюме преимуществ объединения:

1. Улучшить скорость отклика

2. Сокращение потребления ресурсов

3. Простота управления и обслуживания

JedisPoolConfigИнструкции по настройке

Диаграмма классов и анализ исходного кода

Во-первых, посмотрите на диаграмму классов:

UTOOLS1571543704493.png

  • BaseGenericObjectPool: инкапсулирует общедоступные параметры конфигурации.
private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS;
	// DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L
    private long minEvictableIdleTimeMillis =
            DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;

	// DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L
 	private long timeBetweenEvictionRunsMillis =
            DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;

	// DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3
    private int numTestsPerEvictionRun =
            DEFAULT_NUM_TESTS_PER_EVICTION_RUN;

	// DEFAULT_TEST_ON_CREATE = false
    private boolean testOnCreate = DEFAULT_TEST_ON_CREATE;
	// DEFAULT_TEST_ON_BORROW = false
    private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;
	// DEFAULT_TEST_ON_RETURN = false
    private boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
	// DEFAULT_TEST_WHILE_IDLE = false
    private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE;
	//...
}
  • GenericObjectPoolConfig:наследоватьBaseGenericObjectPool, внутренний код очень простой, инкапсулированныйGenericObjectPoolКонфигурация. в основномmaxTotal,maxIdle,minIdle. Этот класс не является потокобезопасным, он используется только для предоставления свойств, используемых при создании пула. создание синглтонаJedisPoolиспользоватьJedisPoolConfigНеобходимо обратить внимание на вопросы безопасности потоков, ниже будет демонстрация создания синглтона.JedisPool.
public class GenericObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {

    /**
     * The default value for the {@code maxTotal} configuration attribute.
     * @see GenericObjectPool#getMaxTotal()
     */
    public static final int DEFAULT_MAX_TOTAL = 8;
    // ...

	// DEFAULT_MAX_TOTAL = 8
    private int maxTotal = DEFAULT_MAX_TOTAL;
	// DEFAULT_MAX_IDLE = 8
    private int maxIdle = DEFAULT_MAX_IDLE;
	// DEFAULT_MIN_IDLE = 0
    private int minIdle = DEFAULT_MIN_IDLE;
    // ...
}
  • JedisPoolConfigУнаследовал вышеперечисленные превосходные гены, а затем сбросил значение нескольких других наборов свойств.

Для удобства Jedis предоставляетJedisPoolConfig, который наследуетGenericObjectPoolConfigНекоторые предусмотрены на простой обнаружении.

public class JedisPoolConfig extends GenericObjectPoolConfig {
  public JedisPoolConfig() {
    // defaults to make your life with connection pool easier :)
    setTestWhileIdle(true);
    setMinEvictableIdleTimeMillis(60000);
    setTimeBetweenEvictionRunsMillis(30000);
    setNumTestsPerEvictionRun(-1);
  }
}

Разбор параметров конфигурации

JedisPoolConfigЕсть много параметров, которые можно настроить в пуле соединений, и реализация пула соединений зависит от apache.commons-pool2. В приведенном выше исходном коде также приблизительно перечислены некоторые параметры конфигурации, которые подробно описаны ниже.

Пул понимается как фабрика, а экземпляры в пуле — как рабочие., как показано на рисунке ниже, чтобы упростить понимание многих параметров в пуле.

UTOOLS1571546063571.png

Соединения Jedis — это ресурсы, которыми управляет JedisPool в пуле соединений. JedisPool гарантирует, что ресурсы находятся в контролируемом диапазоне, и гарантируется безопасность потоков. использовать разумныйGenericObjectPoolConfigКонфигурация может улучшить производительность службы Redis и уменьшить накладные расходы ресурсов. Следующие две таблицы описывают некоторые важные параметры и предоставляют предложения для их настройки.

параметр инструкция По умолчанию предположение
maxTotal Максимальное количество соединений в пуле ресурсов 8 видетьПредложение по настройке ключевых параметров
maxIdle Максимальное количество простоях соединений, разрешенных пулом ресурса 8 видетьПредложение по настройке ключевых параметров
minIdle Минимальное количество незанятых подключений, гарантированное пулом ресурсов 0 видетьПредложение по настройке ключевых параметров
blockWhenExhausted Должен ли вызывающий объект ждать, когда пул ресурсов будет исчерпан. Только если значение истинно, следующееmaxWaitMillisвступит в силу. true Рекомендуется значение по умолчанию.
maxWaitMillis Максимальное время ожидания (в миллисекундах), которое вызывающая сторона может ожидать, когда соединение с пулом ресурсов будет исчерпано. -1 (что означает отсутствие тайм-аута) Значение по умолчанию не рекомендуется.
testOnBorrow Следует ли выполнять проверку правильности соединения (ping) при заимствовании соединения из пула ресурсов. Обнаруженные недействительные соединения будут удалены. false Рекомендуется установить для него значение false, когда бизнес-объем большой, чтобы уменьшить накладные расходы на один пинг.
testOnReturn Следует ли проверить проверку достоверности подключения (PING) при возврате соединений в пул ресурсов. Неверные обнаруженные соединения будут удалены. false Рекомендуется установить для него значение false, когда бизнес-объем большой, чтобы уменьшить накладные расходы на один пинг.
jmxEnabled Включить ли мониторинг JMX true Его рекомендуется открыть, обратите внимание, что само приложение тоже нужно открыть.

Обнаружение объектов Idle Jedis осуществляется комбинацией следующих четырех параметров:testWhileIdleявляется переключателем этой функции.

название инструкция По умолчанию предположение
testWhileIdle Включить ли обнаружение простаивающих ресурсов. false true
timeBetweenEvictionRunsMillis Период обнаружения простоя ресурса (в миллисекундах) -1 (не обнаруживать) Рекомендуется установить цикл, и цикл может быть выбран самостоятельно.Вы также можете использовать значение по умолчанию или использовать следующиеJedisPoolConfigконфигурация в .
minEvictableIdleTimeMillis Бесплатные ресурсы будут удалены минимальными ресурсами простоя в ресурсе пула (в миллисекундах), достигает этого значения. 180 000 (т.е. 30 минут) Вы можете решить в соответствии с вашим бизнесом, как правило, достаточно значения по умолчанию, вы также можете рассмотреть возможность использования следующихJeidsPoolConfigконфигурация в .
numTestsPerEvictionRun При обнаружении простаивающих ресурсов количество ресурсов, которые необходимо обнаруживать каждый раз. 3 Его можно точно настроить в соответствии с количеством подключений к его собственным приложениям.Если установлено значение -1, он должен выполнять мониторинг простоя для всех подключений.

инструкциядопустимыйorg.apache.commons.pool2.impl.BaseObjectPoolConfigчтобы увидеть все значения по умолчанию.

Предложение по настройке ключевых параметров

maxTotal(максимальное количество подключений)

хочу установить разумныйmaxTotal(Максимальное количество подключений) Необходимо учитывать множество факторов, таких как:

  • Параллелизм Redis, ожидаемый бизнесом;
  • Время, когда клиент выполняет команду;
  • Ресурсы Redis, такие как узлы (например, количество приложений и т. д.) * maxTotal не может превышать максимальное количество подключений Redis;
  • Накладные расходы на ресурсы, например, хотя вы хотите контролировать простаивающие соединения, вы не хотите создавать ненужные накладные расходы из-за частого освобождения и создания соединений в пуле соединений.

Предполагая, что время команды, то есть заимствование | возврат ресурса плюс команда выполнения Jedis (включая сетевое время), среднее время составляет около 1 мс, количество запросов в секунду для соединения составляет около 1000, а ожидаемое количество запросов в секунду для бизнеса составляет 50000, тогда теоретически необходимые ресурсы Размер пула 50000 / 1000 = 50.

Но на самом деле это только теоретическое значение, кроме того, некоторые ресурсы должны быть зарезервированы, поэтомуmaxTotalможет быть больше теоретического значения. Это значение не является максимально возможным.С одной стороны, слишком много соединений будут занимать ресурсы клиента и сервера.С другой стороны, для сервера с высоким QPS, такого как Redis, если блокируется большая команда, даже установка большого пул ресурсов не поможет.

maxIdle и minIdle

maxIdleПо сути, это максимальное количество подключений, необходимое бизнесу.maxTotalзаключается в том, чтобы дать запас, поэтомуmaxIdleНе устанавливайте его слишком маленьким, иначе будетnew Jedis(новое соединение) накладные расходы, в то время какminIdleОн предназначен для управления обнаружением простаивающих ресурсов.

Лучшая производительность пула соединенийmaxTotal=maxIdle, что позволяет избежать помех производительности, вызванных масштабированием пула соединений. Но если параллелизм невелик илиmaxTotalУстановка слишком высокого значения приведет к ненужной трате ресурсов соединения.

Вы можете оценить размер пула соединений, используемого каждым узлом в целом, на основе фактического общего числа запросов в секунду и размера клиента, вызывающего Redis.

Используйте мониторинг для получения разумного значения

На практике более надежным методом является попытка получить оптимальное значение параметра посредством мониторинга. Вы можете рассмотреть возможность мониторинга с помощью JMX и других методов, чтобы найти разумное значение.

Приведенная выше конфигурация параметров:Оптимизация пула ресурсов JedisPool

СоздайтеJedisPoolкод

// volatile 修饰
private static volatile JedisPool jedisPool = null;

private JedisPoolUtils(){
}

public static JedisPool getJedisPoolInstance() {
    // 使用双重检查创建单例
    if(null == jedisPool) {
        synchronized (JedisPoolUtils.class) {
            if(null == jedisPool) {
                JedisPoolConfig poolConfig = new JedisPoolConfig();
                poolConfig.setMaxTotal(10);
                poolConfig.setMaxIdle(10);
                poolConfig.setMinIdle(2);
                poolConfig.setMaxWaitMillis(30*1000);
                poolConfig.setTestOnBorrow(true);
                poolConfig.setTestOnReturn(true);
                poolConfig.setTimeBetweenEvictionRunsMillis(10*1000);
                poolConfig.setMinEvictableIdleTimeMillis(30*1000);
                poolConfig.setNumTestsPerEvictionRun(-1);
                jedisPool = new JedisPool(poolConfig,"localhost",6379);
            }
        }
    }
    return jedisPool;
}

Грубый анализ процесса создания и выпуска экземпляра

UTOOLS1571556369669.png

Анализ исходного кода в соответствии с процессом

создать процесс

использоватьpool.getResource()Создайте экземпляр Jedis.

//org.apache.commons.pool2.impl.GenericObjectPool#borrowObject(long)
public T borrowObject(final long borrowMaxWaitMillis) throws Exception {

    final boolean blockWhenExhausted = getBlockWhenExhausted();

    PooledObject<T> p = null;
    boolean create;
    final long waitTime = System.currentTimeMillis();

    while (p == null) {
        create = false;
        // 从空闲队列中获取
        p = idleObjects.pollFirst();
        if (p == null) {
            // 创建实例
            p = create();
            if (p != null) {
                create = true;
            }
        }
        // 吃资源是否耗尽
        if (blockWhenExhausted) {
            if (p == null) {
                // 等待时间小于0
                if (borrowMaxWaitMillis < 0) {
                    p = idleObjects.takeFirst();
                } else {
                    p = idleObjects.pollFirst(borrowMaxWaitMillis,
                                              TimeUnit.MILLISECONDS);
                }
            }
            if (p == null) {
                throw new NoSuchElementException(
                    "Timeout waiting for idle object");
            }
        } else {
            if (p == null) {
                throw new NoSuchElementException("Pool exhausted");
            }
        }
        if (!p.allocate()) {
            p = null;
        }

        if (p != null) {
            try {
                // 重新初始化要由池返回的实例。
                factory.activateObject(p);
            } catch (final Exception e) {

            }
        }
    }
    updateStatsBorrow(p, System.currentTimeMillis() - waitTime);

    return p.getObject();
}    

процесс выпуска

После версии Jedis 3.0pool.returnResource()Устарело, вместо этого используется официальный переписанный метод закрытия Jedis; официальная рекомендация состоит в том, чтобы использовать закрытый метод redis.clients.jedis#Jedis для утилизации ресурсов.Официальный код выглядит следующим образом:

 @Override
  public void close() {
    if (dataSource != null) {
      JedisPoolAbstract pool = this.dataSource;
      this.dataSource = null;
      if (client.isBroken()) {
        pool.returnBrokenResource(this);
      } else {
        pool.returnResource(this);
      }
    } else {
      super.close();
    }
  }

В основном здесь:pool.returnResource(this);

//org.apache.commons.pool2.impl.GenericObjectPool#returnObject
public void returnObject(final T obj) {
    // 获取要释放的实例对象
    final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));

    if (p == null) {
        if (!isAbandonedConfig()) {
            throw new IllegalStateException(
                "Returned object not currently part of this pool");
        }
        return; // Object was abandoned and removed
    }
	// 将对象标记为返回池的状态。
    markReturningState(p);

    final long activeTime = p.getActiveTimeMillis();
	
    // 这里就和上面配置的参数有关系,释放的时候是否做连接有效性检测(ping)
    if (getTestOnReturn() && !factory.validateObject(p)) {
        try {
            destroy(p);
        } catch (final Exception e) {
            swallowException(e);
        }
        try {
            ensureIdle(1, false);
        } catch (final Exception e) {
            swallowException(e);
        }
        updateStatsReturn(activeTime);
        return;
    }
	
	// 检查空闲对象,如果最大空闲对象数小于当前idleObjects大小,则销毁
    final int maxIdleSave = getMaxIdle();
    if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
        try {
            destroy(p);
        } catch (final Exception e) {
            swallowException(e);
        }
    } else {
        // 否则加入到空闲队列中,空闲队列是一个双端队列
        // getLifo 也和配置的参数有关,默认True
        if (getLifo()) {
            // last in first out,加到队头
            idleObjects.addFirst(p);
        } else {
            // first in first out ,加到队尾
            idleObjects.addLast(p);
        }
    }
    updateStatsReturn(activeTime);
}

Вышеупомянутое создание и выпуск удаляют некоторый код, конкретный полный код находится вGenericObjectPoolв классе.

Вывод, сожаление на некоторое время

После прочтения этой статьи должно быть примерно правильноJedisPoolConfigПри определенном понимании внутри можно указать некоторые параметры конфигурации, а можно выполнить базовую настройку параметров, а также процесс создания и освобождения ресурсов экземпляра.

Если вы благодарны заинтересованным партнерам, вы можете скачать исходный код Jedis для чтения и изучения.JedisPoolConfigКонфигурация других пулов фреймворков тоже похожа, и можно делать выводы из одного случая! Реки и озера не за горами, в будущем будет период!

Если вам нужны ресурсы, связанные с Reids, вы можете отсканировать приведенный ниже QR-код, который содержит ресурсы, связанные с Redis!

Примечания: Из-за моих ограниченных возможностей, если в тексте есть какие-либо ошибки, пожалуйста, поправьте меня.


Спасибо за чтение, если вы найдете этот пост в блоге полезным, пожалуйста, поставьте лайк, чтобы его увидело больше людей! Желаю тебе счастливого дня!


Технологический рай Java-программирования: Публичный аккаунт для обмена знаниями в области программирования. Следуйте за старыми водителями, чтобы освоить технические знания о галантерейных товарах, каждый день добивайтесь небольшого прогресса, и пусть маленькие накопления принесут большие перемены!

Сканируйте внимание, фоновый ответ【Читы】, получите заветную галантерею!99.9%Такие партнеры

image.png | center| 747x519

© Фейюнь, которая с каждым днем ​​становится все лучше