RedisTemplate使用PipeLineのまとめ
最近1つの統計項目をして、データ量はとても大きくて、前にscanコマンドを使ってredisの中で指定したkeyに対してスキャンを行って、一回に100条、実行が安定して、効率が低くて、同時にtcpが接続を閉じるtime-waitの成長率はかなり速くて、性能に対して極めて大きい浪費をもたらして同時に実行時間も遅くて、その上データ量が更に増大して他のサービスに影響する可能性があります.tcp接続数を減らすためにredisのscanをpipeLine操作に変更します.
一、なぜPipelineを使うのですか.
Redisは、C/Sモードに基づくリクエスト/レスポンスプロトコルを採用したTCPサーバである. パフォーマンスの問題1:redisクライアントは複数のリクエストを送信し、後のリクエストは前のリクエストの処理が完了するまで待たなければならない.また、各リクエストには往復時間RRT(Round Trip Time)が存在し、redisのパフォーマンスが極めて高くても、データ量が十分に大きい場合、パフォーマンスに大きな影響を与え、他の予期せぬ状況を引き起こす可能性がある. パフォーマンスの問題2:パフォーマンスの問題1、私たちはscanコマンドを通じて解決することができて、どのようにcountを設定するかはまた1つの問題で、設定がよくなくて、同じように大量の要求が存在して、1 w(最大値を推薦します)に設定しても、スキャンのデータ量が大きすぎると、この問題は同じように避けられません.各リクエストは3回の握手、4回の手を振っており、大量の接続を処理すると、処理が完了すると手を振るとtime-waitが大量に発生し、サーバが他のサービスを提供する場合、他のサービスに影響を与える可能性があります.
Pipelineを使用すると、上記の問題を解決できます.二、どうやってPipelineを使うの?
本論文ではRedisTemplate呼び出しexecute,connectionが使用するredisオリジナルの動作を用い,ここではkeysにおける集合データの長さを計算するためにzCountを簡単に用いた.取得結果はresultで、ここでPipelineを使用するにはConnection.openPipeline()を呼び出す必要があります.Connection.closePipeline()の戻り値がListであることは実行後の結果であり,かなり簡単である.
このリストは匿名クラスの内部に置かれており、データ処理にあまり友好的ではなく、コードがかなり苦しく見えますが、取り出して使いたいのか可変ではありません.戻り値を取得する場合は、次のコードexecutePipelinedを呼び出すことで、必要な結果を返すことができます.次にlistを取得する操作を行います.
ここでは4つの点に注意してください.
1.ここでのconnectはredisオリジナルリンクであるため、connectionの戻り結果は基本的にbyte配列であり、格納するデータが必要な場合はbyte[]配列を逆シーケンス化する必要がある. 2.doInRedisではnullとして返さなければなりませんが、なぜnullとして返されますか?詳細は、内部コードにナビゲートして確認できますが、ここでは説明しません.3.connection.openPipeline()は呼び出すことも呼び出さないこともできますが、connection.closePipeline()は呼び出すことができず、呼び出すと戻り値が得られません.呼び出し時に結果が直接返され、コードが逆シーケンス化されないためです. 4.逆シーケンス化は、次の図に示すように、対応するインスタンス化が可能な逆シーケンス化オブジェクトを入力する必要があります.
プロジェクトのニーズに応じて適切な逆シーケンス化オブジェクトを選択します.たとえば、プロジェクトでkeyはStringRedisSerializerを使用し、値は通常GenerJackson 2 JsonRedisSerializerを使用します.したがって、redisTemplateを初期化するときには、コードは以下のようにして、シーケンス化されたインスタンス化オブジェクトをredisTemplateに入れ、使用するときに直接redis.getKeySerializer()またはredis.getValue Serializer()を使用することができ、1つのオブジェクトをインスタンス化する必要がなく、浪費と冗長性をもたらすことができます.
このようなドロップダウン方式により、強制変換を行わずに、私たちが望んでいる対象を直接得ることができます.
List List = redisTemplate.executePipelined(new RedisCallback() { @Nullable @Override public User doInRedis(RedisConnection connection) throws DataAccessException { connection.openPipeline(); for (int i = 0; i < 1000000; i++) { String key = "123"+ i; connection.zCount(key.getBytes(), 0,Integer.MAX_VALUE); } return null; } }, myRedisComponent.getRedisTemplate().getValueSerializer());
一、なぜPipelineを使うのですか.
Redisは、C/Sモードに基づくリクエスト/レスポンスプロトコルを採用したTCPサーバである. パフォーマンスの問題1:redisクライアントは複数のリクエストを送信し、後のリクエストは前のリクエストの処理が完了するまで待たなければならない.また、各リクエストには往復時間RRT(Round Trip Time)が存在し、redisのパフォーマンスが極めて高くても、データ量が十分に大きい場合、パフォーマンスに大きな影響を与え、他の予期せぬ状況を引き起こす可能性がある. パフォーマンスの問題2:パフォーマンスの問題1、私たちはscanコマンドを通じて解決することができて、どのようにcountを設定するかはまた1つの問題で、設定がよくなくて、同じように大量の要求が存在して、1 w(最大値を推薦します)に設定しても、スキャンのデータ量が大きすぎると、この問題は同じように避けられません.各リクエストは3回の握手、4回の手を振っており、大量の接続を処理すると、処理が完了すると手を振るとtime-waitが大量に発生し、サーバが他のサービスを提供する場合、他のサービスに影響を与える可能性があります.
Pipelineを使用すると、上記の問題を解決できます.二、どうやってPipelineを使うの?
本論文ではRedisTemplate呼び出しexecute,connectionが使用するredisオリジナルの動作を用い,ここではkeysにおける集合データの長さを計算するためにzCountを簡単に用いた.取得結果はresultで、ここでPipelineを使用するにはConnection.openPipeline()を呼び出す必要があります.Connection.closePipeline()の戻り値がListであることは実行後の結果であり,かなり簡単である.
redisTemplate.execute(new RedisCallback() {
@Nullable
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
for (int i = 0; i < 1000000; i++) {
String key = "123" + i;
connection.zCount(key.getBytes(), 0,Integer.MAX_VALUE);
}
List
このリストは匿名クラスの内部に置かれており、データ処理にあまり友好的ではなく、コードがかなり苦しく見えますが、取り出して使いたいのか可変ではありません.戻り値を取得する場合は、次のコードexecutePipelinedを呼び出すことで、必要な結果を返すことができます.次にlistを取得する操作を行います.
List List = redisTemplate.executePipelined(new RedisCallback() {
@Nullable
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
for (int i = 0; i < 1000000; i++) {
String key = "123" + i;
connection.zCount(key.getBytes(), 0,Integer.MAX_VALUE);
}
return null;
}
});
ここでは4つの点に注意してください.
1.ここでのconnectはredisオリジナルリンクであるため、connectionの戻り結果は基本的にbyte配列であり、格納するデータが必要な場合はbyte[]配列を逆シーケンス化する必要がある. 2.doInRedisではnullとして返さなければなりませんが、なぜnullとして返されますか?詳細は、内部コードにナビゲートして確認できますが、ここでは説明しません.3.connection.openPipeline()は呼び出すことも呼び出さないこともできますが、connection.closePipeline()は呼び出すことができず、呼び出すと戻り値が得られません.呼び出し時に結果が直接返され、コードが逆シーケンス化されないためです. 4.逆シーケンス化は、次の図に示すように、対応するインスタンス化が可能な逆シーケンス化オブジェクトを入力する必要があります.
プロジェクトのニーズに応じて適切な逆シーケンス化オブジェクトを選択します.たとえば、プロジェクトでkeyはStringRedisSerializerを使用し、値は通常GenerJackson 2 JsonRedisSerializerを使用します.したがって、redisTemplateを初期化するときには、コードは以下のようにして、シーケンス化されたインスタンス化オブジェクトをredisTemplateに入れ、使用するときに直接redis.getKeySerializer()またはredis.getValue Serializer()を使用することができ、1つのオブジェクトをインスタンス化する必要がなく、浪費と冗長性をもたらすことができます.
public class MyRedisUtil {
private RedisTemplate redisTemplate;
@Autowired
public void setRedisTemplate(RedisTemplate redisTemplate) {
RedisSerializer keySerializer = new StringRedisSerializer();
RedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
redisTemplate.setKeySerializer(keySerializer);
redisTemplate.setValueSerializer(valueSerializer);
this.redisTemplate = redisTemplate;
}
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
}
このようなドロップダウン方式により、強制変換を行わずに、私たちが望んでいる対象を直接得ることができます.
List List = redisTemplate.executePipelined(new RedisCallback() { @Nullable @Override public User doInRedis(RedisConnection connection) throws DataAccessException { connection.openPipeline(); for (int i = 0; i < 1000000; i++) { String key = "123"+ i; connection.zCount(key.getBytes(), 0,Integer.MAX_VALUE); } return null; } }, myRedisComponent.getRedisTemplate().getValueSerializer());