redis管道技术
Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。这样的处理流程是:
– 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。
– 服务端处理命令,并将结果返回给客户端。
Redis管道(pipeline)技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。管道技术最显著的优势是提高了redis服务的性能,省去了产生多个请求消耗的时间和资源。
java使用redisson客户端实现管道技术批量执行命令
redisson是一个优秀的开源redis java客户端组件,redisson也提供了批量执行命令的功能RBatch,官方文档可参考:
https://github.com/redisson/redisson/wiki/10.-%E9%A2%9D%E5%A4%96%E5%8A%9F%E8%83%BD#103-%E5%91%BD%E4%BB%A4%E7%9A%84%E6%89%B9%E9%87%8F%E6%89%A7%E8%A1%8C
使用redisson批量执行操作,非常简单,参照官方文档执行即可,在我们的项目中,我们对redisson的RBatch进行了简单的封装,如下的Batch类(这是一个内部类,redisson是在其文件中定义的)的部分代码:
/**
* redisson批量执行
*
*/
public static class Batch{
/**redisson批量*/
private RBatch batch;
/**批量操作选项*/
private BatchOptions options = BatchOptions.defaults();
private Batch(){
batch = redisson.createBatch(options);
}
/**
* 构造方法
* @param skipResult 是否忽略执行结果
* @param timeout 执行命令超时时间,单位毫秒
*/
private Batch(boolean skipResult, long timeout){
if(skipResult){
options.skipResult();
}
options.responseTimeout(timeout, TimeUnit.MILLISECONDS);
batch = redisson.createBatch(options);
}
/**
* 默认静态构造
* @return
*/
public static Batch of(){
return new Batch();
}
/**
* 静态构造
*@param skipResult 是否忽略执行结果
* @param timeout 执行命令超时时间,单位毫秒
* @return
*/
public static Batch of(boolean skipResult, long timeout){
return new Batch(skipResult, timeout);
}
/**
* 存入redis
* @param key
* @param value
* @return
*/
public <V> Batch set(String key, V value){
RBucketAsync<V> bucket = batch.getBucket(key);
bucket.setAsync(value);
return this;
}
/**
* 删除key,针对redis的String数据结构操作
* @param key
* @return
*/
public <V> Batch del(String key){
RBucketAsync<V> bucket = batch.getBucket(key);
bucket.deleteAsync();
return this;
}
/**
* 缓存中添加元素,设置过期时间,如expiryTime不满足要求则使用默认时间
*
* @param key
* @param element
* @param expiryTime
*/
public <T> Batch addToSet(String key, T element, Date expiryTime) {
RSetCacheAsync<T> set = batch.getSetCache(key);
Date now = new Date();
long expiry = expiryTime.getTime() - now.getTime();
expiry = expiry > 0 ? expiry : DEFAULT_CACHE_MILLISECONDS;
set.addAsync(element, expiry, TimeUnit.MILLISECONDS);
return this;
}
/**
* 从集合中移除元素
*
* @param key
* @param element
*/
public <T> Batch removeFromSet(String key, T element) {
RSetCacheAsync<T> set = batch.getSetCache(key);
set.removeAsync(element);
return this;
}
/**
* 清除整个集合
*
* @param key
*/
public <T> Batch clearSet(String key) {
RSetCacheAsync<T> set = batch.getSetCache(key);
set.deleteAsync();
return this;
}
/**
* 执行
* @return
*/
public BatchResult<?> execute(){
return batch.execute();
}
}
使用redisson批量操作,需要注意一些选项,可参考BatchOptions,一般情况下我们只关心这批命令是否是原子操作、是否关心返回结果、执行时间等。具体的参数选项,可以参考:
批量操作选项类
org.redisson.api.BatchOptions
事务/原子性执行模式
org.redisson.api.BatchOptions.ExecutionMode
使用上面的类测试一下批量操作:
@Test
public void batchTest() throws InterruptedException{
Batch batch = Batch.of(false, 3000);
Date date = new Date();
batch.addToSet("TEST_SET_KEY", 1, new Date(date.getTime() + 10000));
batch.set("TEST_STRING_KEY", "test");
BatchResult result = batch.execute();
System.out.println(JSON.toJSONString(result));
System.out.println(JSON.toJSONString(CacheUtil.getSet("TEST_SET_KEY")));
System.out.println(JSON.toJSONString(CacheUtil.get("TEST_STRING_KEY")));
Thread.sleep(11000);
System.out.println(JSON.toJSONString(CacheUtil.getSet("TEST_SET_KEY")));
System.out.println(JSON.toJSONString(CacheUtil.get("TEST_STRING_KEY")));
}
执行结果如下:
[true,null]
[1]
{"TEST_STRING_KEY":"test"}
[]
{"TEST_STRING_KEY":"test"}
使用redisson的批量执行的确非常简单,也能提高不少性能,这就是redis管道技术的优势。