JedisPoolは、Jedisクライアントの接続プールです。 Redisのパフォーマンスとリソース使用率を向上させるために、JedisPoolパラメーターを適切に設定できます。 このトピックでは、JedisPoolとそのリソースプールパラメーターの使用方法について説明し、JedisPoolを最適化するための推奨設定を提供します。
JedisPoolを使う
この例ではJedis 2.9.0が使用されます。 次のサンプルコードは、Mavenの依存関係を示しています。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
Jedis は、Apache Commons-pool2 を使用してリソースプールを管理します。 JedisPoolを定義するときは、リソースプールのGenericObjectPoolConfigパラメーターに注意することを推奨します。 次のサンプルコードは、このパラメーターの使用方法を示しています。
GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig();
jedisPoolConfig.setMaxTotal(...);
jedisPoolConfig.setMaxIdle(...);
jedisPoolConfig.setMinIdle(...);
jedisPoolConfig.setMaxWaitMillis(...);
...
次の例は、JedisPoolを初期化する方法を示しています。
redisHost specifies the IP address of the instance. redisPort specifies the port of the instance. redisPassword specifies the password of the instance. The timeout parameter specifies the connection timeout and the read/write timeout.
JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort, timeout, redisPassword);
// Run the following commands:
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
// Specific commands
jedis.executeCommand()
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
//In JedisPool mode, the Jedis resource is returned to the resource pool.
if (jedis != null)
jedis.close();
}
パラメーター
Jedis 接続は、接続プール内の JedisPool によって管理されるリソースです。 JedisPoolは、スレッドセーフな接続プールです。 すべてのリソースを管理可能な範囲内に保つことができます。 GenericObjectPoolConfigパラメーターを適切な値に設定すると、Redisのパフォーマンスを向上させ、リソース消費を削減できます。 次の2つの表は、重要なパラメーターと推奨設定を示しています。
表 1. リソース設定とリソース使用量に関するパラメーター
パラメーター | 説明 | デフォルト値 | 推奨設定 |
maxTotal | プール内の最大接続数。 | 8 | 詳細については、「推奨設定」をご参照ください。 |
maxIdle | プール内のアイドル接続の最大数。 | 8 | 詳細については、「推奨設定」をご参照ください。 |
minIdle | プール内のアイドル接続の最小数。 | 0 | 詳細については、「推奨設定」をご参照ください。 |
blockWhenExhausted | リソースプールが使い果たされたときにクライアントが待機する必要があるかどうかを指定します。 このパラメーターがtrueに設定されている場合のみ、maxWaitMillisパラメーターが有効になります。 | true | デフォルト値を使用することを推奨します。 |
maxWaitMillis | 接続が利用できないときにクライアントが待機する必要がある最大ミリ秒数。 | -1 (接続がタイムアウトしないことを示します) 。 | デフォルト値を使用しないことを推奨します。 |
testOnBorrow | 接続をプールから借用する前に、PINGコマンドを使用して接続を検証するかどうかを指定します。 無効な接続がプールから削除されます。 | false | ワークロードが重い場合は、このパラメーターをfalseに設定することを推奨します。 これにより、pingテストのオーバーヘッドを減らすことができます。 |
testOnReturn | 接続がプールに返される前に、PINGコマンドを使用して接続を検証するかどうかを指定します。 無効な接続がプールから削除されます。 | false | ワークロードが重い場合は、このパラメーターをfalseに設定することを推奨します。 これにより、pingテストのオーバーヘッドを減らすことができます。 |
jmxEnabled | Java Management Extensions (JMX) モニタリングを有効にするかどうかを指定します。 | true | JMXモニタリングを有効にすることを推奨します。 アプリケーションの機能も有効にする必要があることに注意してください。 |
アイドル状態のJedisオブジェクトの検出は、4つのパラメータの組み合わせによって制御されます。
表 2. アイドルリソース検出に関するパラメータ
パラメーター | 説明 | デフォルト値 | 推奨設定 |
testWhileIdle | アイドルリソース監視のプロセス中にPINGコマンドを実行して接続を検証するかどうかを指定します。 無効な接続が削除されます。 | false | true |
timeBetweenEvictionRunsMillis | アイドルリソース検出のサイクル。 単位:ミリ秒。 | -1 (アイドルリソースの検出が無効になっていることを示します) 。 | このパラメーターを適切な値に設定することを推奨します。 JedisPoolConfigでデフォルト設定を使用することもできます。 |
minEvictableIdleTimeMillis | リソースプール内のリソースの最小アイドル時間。 単位:ミリ秒。 上限に達すると、アイドルリソースは追い出される。 | 1,800,000 (30分) | デフォルト値はほとんどの場合に適しています。 ビジネス要件に基づいて、JeidsPoolConfigで設定を使用することもできます。 |
numTestsPerEvictionRun | 各サイクル内で検出されるリソースの数。 | 3 | アプリケーション接続に基づいて値を変更できます。 値-1は、システムがすべての接続でアイドルリソースをチェックすることを指定します。 |
Jedisは、アイドルリソースの検出にGenericObjectPoolConfigのいくつかの設定を使用するJedisPoolConfigを提供します。
public class JedisPoolConfig extends GenericObjectPoolConfig {
public JedisPoolConfig() {
setTestWhileIdle(true);
setMinEvictableIdleTimeMillis(60000);
setTimeBetweenEvictionRunsMillis(30000);
setNumTestsPerEvictionRun(-1);
}
}
すべてのデフォルト値は、org.apache.com mons.pool2.impl.BaseObjectPoolConfigで表示できます。
推奨設定
maxTotal:接続の最大数。
maxTotalに適切な値を設定するには、次の要素に注意してください。
ビジネス要件に基づいて予想される同時接続。
コマンドを実行するためにクライアントが消費する時間。
Redis リソースの制限。 たとえば、maxTotalの値にノード (ECSインスタンス) の数を掛けた場合、結果の値はRedisでサポートされている最大接続数よりも小さくなければなりません。 ApsaraDB for Redisコンソールの [インスタンス情報] ページで最大接続数を確認できます。
接続の作成と解放に消費されるリソースの量。 要求に対して作成および解放される接続の数が多い場合、接続を作成および解放するために実行されるプロセスは悪影響を受けます。
たとえば、コマンドを実行するために消費される平均時間、またはリソースを借りたり戻したり、ネットワークオーバーヘッドでJedisコマンドを実行するために必要な平均時間は、約1 msです。 接続の1秒あたりのクエリ数 (QPS) は約1,000です。これは、1秒を1ミリ秒で割って計算されます。 個々のRedisインスタンスの予想されるQPSは50,000です (QPSの総数をRedisシャードの数で割ったもの) 。 理論的に必要なリソースプールのサイズ (maxTotal) は50で、50,000を1,000で割って計算されます。
ただし、これは理論値にすぎません。 予想外の需要を考慮するために、いくつかの追加のリソースを予約することも不可欠です。 したがって、maxTotalを計算された見積もりよりも大きい値に設定することを推奨します。 ただし、maxTotalパラメーターの値が大きすぎると、接続によって大量のクライアントおよびサーバーリソースが消費されます。 高いQPSを持つRedisサーバーの場合、多数のコマンドがブロックされると、大きなリソースプールでも問題は解決できません。
maxIdleとminIdle
maxIdleは、ワークロードに必要な実際の最大接続数を示します。 maxTotalは、余剰としてアイドル接続の数を含む。 maxIdleの値が高負荷のシステムで小さい場合、要求を処理するために新しいJedis
接続が作成されます。 minIdleは、プールに保持する必要がある確立された接続の最小数を示します。
接続プールは、maxTotalの値がmaxIdleの値に等しい場合に、最高のパフォーマンスを実現します。 このように、パフォーマンスは接続プールのスケーリングによって影響を受けません。 ユーザートラフィックが変動する場合は、maxIdleパラメーターとminIdleパラメーターを同じ値に設定することを推奨します。 同時接続の数が少ない場合、またはmaxIdleの値が大きすぎる場合、接続リソースが無駄になります。
実際の合計QPSとRedisがサービスを提供するクライアントの数に基づいて、各ノードで使用される接続プールのサイズを評価できます。
モニタリングデータに基づいて適切な値を取得
実際のシナリオでは、より信頼できる方法は、モニタリングデータに基づいて最適値を取得しようとすることです。 JMXモニタリングまたは他のモニタリングツールを使用して、適切な値を見つけることができます。
よくある質問
リソースが不足しています。
次の場合、リソースプールからリソースを取得できません。
タイムアウト:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool ... Caused by: java.util.NoSuchElementException: Timeout waiting for idle object at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)
blockWhenExhaustedパラメーターをfalseに設定すると、borrowMaxWaitMillisで指定された時間は使用されず、アイドル接続が利用可能になるまで、borrowObject呼び出しによって接続がブロックされます。
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool ... Caused by: java.util.NoSuchElementException: Pool exhausted at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:464)
この例外は、限られたプールサイズによって引き起こされない可能性があります。 詳細については、「推奨設定」をご参照ください。 この問題を解決するには、ネットワーク、リソースプールのパラメーター、リソースプールモニタリング (JMXモニタリング) サービス、コード (たとえば、jedis.close()
が実行されないため) 、低速クエリ、およびドメインネームシステム (DNS) を確認することを推奨します。
JedisPoolのプリロード
小さいタイムアウト値を指定した場合、プロジェクトは開始後にタイムアウトする可能性があります。 JedisPoolがリソースの最大数とアイドルリソースの最小数を定義している場合、JedisPoolは接続プールにJedis接続を作成しません。 プールにアイドル接続が存在しない場合、新しいJedis
接続が作成されます。 この接続は、接続が使用された後にプールに解放される。 ただし、接続を作成して接続を繰り返し解放するプロセスには、長い時間がかかる場合があります。 したがって、JedisPoolを定義した後、JedisPoolに最小のアイドル接続数をプリロードすることを推奨します。 次の例は、JedisPoolをプリロードする方法を示しています。
List<Jedis> minIdleJedisList = new ArrayList<Jedis>(jedisPoolConfig.getMinIdle());
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {
Jedis jedis = null;
try {
jedis = pool.getResource();
minIdleJedisList.add(jedis);
jedis.ping();
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
}
}
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {
Jedis jedis = null;
try {
jedis = minIdleJedisList.get(i);
jedis.close();
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
}
}
その他のエラーについては、「一般的なエラーとトラブルシューティング」をご参照ください。