Jedis jedis = new Jedis("127.0.0.1",6379);
Pipeline pipeline = jedis.pipelined();
for(int i = 0;i<1000;i++){
String content = i + "";
pipeline.set(content,content);
}
pipeline.sync();

  

Jedis jedis = new Jedis("127.0.0.1",6379);
Pipeline pipeline = jedis.pipelined();
Map<String, Response> responses = new LinkedHashMap<String, Response>();
        for(int i = 0;i<1000;i++){
String content = i + "";
Response<String> response = pipeline.get(content);
responses.put(content,response);
}
pipeline.sync();
for(String key:responses.keySet()){
System.out.println("key:"+key + ",value:" + responses.get(key).get());
}

  二、集群

1、方式一

import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisClusterInfoCache;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.util.JedisClusterCRC16; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* @Auther: lyl
* @Date: 2019/10/23 17:06
* @Description:
*/
public class BatchUtil {
public static Map<String, String> mget(JedisCluster jc, String... keys){
Map<String, String> resMap = new HashMap<>();
if(keys == null || keys.length == 0){
return resMap;
}
//如果只有一条,直接使用get即可
if(keys.length == 1){
resMap.put(keys[0], jc.get(keys[0]));
return resMap;
} //JedisCluster继承了BinaryJedisCluster
//BinaryJedisCluster的JedisClusterConnectionHandler属性
//里面有JedisClusterInfoCache,根据这一条继承链,可以获取到JedisClusterInfoCache
//从而获取slot和JedisPool直接的映射
MetaObject metaObject = SystemMetaObject.forObject(jc);
JedisClusterInfoCache cache = (JedisClusterInfoCache) metaObject.getValue("connectionHandler.cache");
//保存地址+端口和命令的映射
Map<JedisPool, List<String>> jedisPoolMap = new HashMap<>();
List<String> keyList = null;
JedisPool currentJedisPool = null;
Pipeline currentPipeline = null; for(String key : keys){
//计算哈希槽
int crc = JedisClusterCRC16.getSlot(key);
//通过哈希槽获取节点的连接
currentJedisPool = cache.getSlotPool(crc);
//由于JedisPool作为value保存在JedisClusterInfoCache中的一个map对象中,每个节点的
//JedisPool在map的初始化阶段就是确定的和唯一的,所以获取到的每个节点的JedisPool都是一样
//的,可以作为map的key
if(jedisPoolMap.containsKey(currentJedisPool)){
jedisPoolMap.get(currentJedisPool).add(key);
}else{
keyList = new ArrayList<>();
keyList.add(key);
jedisPoolMap.put(currentJedisPool, keyList);
}
} //保存结果
List<Object> res = new ArrayList<>();
//执行
for(Map.Entry<JedisPool, List<String>> entry : jedisPoolMap.entrySet()){
try {
currentJedisPool = entry.getKey();
keyList = entry.getValue();
//获取pipeline
currentPipeline = currentJedisPool.getResource().pipelined();
for(String key : keyList){
currentPipeline.get(key);
}
//从pipeline中获取结果
res = currentPipeline.syncAndReturnAll();
currentPipeline.close();
for(int i=0; i<keyList.size(); i++){
resMap.put(keyList.get(i), res.get(i)==null ? null : res.get(i).toString());
}
} catch (Exception e) {
e.printStackTrace();
return new HashMap<>();
}
}
return resMap;
}
}

  2、方式二

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import redis.clients.jedis.BinaryJedisCluster;
import redis.clients.jedis.Client;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisClusterConnectionHandler;
import redis.clients.jedis.JedisClusterInfoCache;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisSlotBasedConnectionHandler;
import redis.clients.jedis.PipelineBase;
import redis.clients.jedis.exceptions.JedisMovedDataException;
import redis.clients.jedis.exceptions.JedisRedirectionException;
import redis.clients.util.JedisClusterCRC16;
import redis.clients.util.SafeEncoder;
/**
* @Auther: lyl
* @Date: 2019/10/23 16:12
* @Description:
*/
public class JedisClusterPipeline extends PipelineBase implements Closeable {
private static final Logger LOGGER = LoggerFactory.getLogger(JedisClusterPipeline.class); // 部分字段没有对应的获取方法,只能采用反射来做
// 你也可以去继承JedisCluster和JedisSlotBasedConnectionHandler来提供访问接口
private static final Field FIELD_CONNECTION_HANDLER;
private static final Field FIELD_CACHE;
static {
FIELD_CONNECTION_HANDLER = getField(BinaryJedisCluster.class, "connectionHandler");
FIELD_CACHE = getField(JedisClusterConnectionHandler.class, "cache");
} private JedisSlotBasedConnectionHandler connectionHandler;
private JedisClusterInfoCache clusterInfoCache;
private Queue<Client> clients = new LinkedList<Client>(); // 根据顺序存储每个命令对应的Client
private Map<JedisPool, Jedis> jedisMap = new HashMap<>(); // 用于缓存连接
private boolean hasDataInBuf = false; // 是否有数据在缓存区 /**
* 根据jedisCluster实例生成对应的JedisClusterPipeline
* @param
* @return
*/
public static JedisClusterPipeline pipelined(JedisCluster jedisCluster) {
JedisClusterPipeline pipeline = new JedisClusterPipeline();
pipeline.setJedisCluster(jedisCluster);
return pipeline;
} public JedisClusterPipeline() {
} public void setJedisCluster(JedisCluster jedis) {
connectionHandler = getValue(jedis, FIELD_CONNECTION_HANDLER);
clusterInfoCache = getValue(connectionHandler, FIELD_CACHE);
} /**
* 刷新集群信息,当集群信息发生变更时调用
* @param
* @return
*/
public void refreshCluster() {
connectionHandler.renewSlotCache();
} /**
* 同步读取所有数据. 与syncAndReturnAll()相比,sync()只是没有对数据做反序列化
*/
public void sync() {
innerSync(null);
} /**
* 同步读取所有数据 并按命令顺序返回一个列表
*
* @return 按照命令的顺序返回所有的数据
*/
public List<Object> syncAndReturnAll() {
List<Object> responseList = new ArrayList<Object>(); innerSync(responseList); return responseList;
} private void innerSync(List<Object> formatted) {
HashSet<Client> clientSet = new HashSet<Client>(); try {
for (Client client : clients) {
// 在sync()调用时其实是不需要解析结果数据的,但是如果不调用get方法,发生了JedisMovedDataException这样的错误应用是不知道的,因此需要调用get()来触发错误。
// 其实如果Response的data属性可以直接获取,可以省掉解析数据的时间,然而它并没有提供对应方法,要获取data属性就得用反射,不想再反射了,所以就这样了
Object data = generateResponse(client.getOne()).get();
if (null != formatted) {
formatted.add(data);
} // size相同说明所有的client都已经添加,就不用再调用add方法了
if (clientSet.size() != jedisMap.size()) {
clientSet.add(client);
}
}
} catch (JedisRedirectionException jre) {
if (jre instanceof JedisMovedDataException) {
// if MOVED redirection occurred, rebuilds cluster's slot cache,
// recommended by Redis cluster specification
refreshCluster();
} throw jre;
} finally {
if (clientSet.size() != jedisMap.size()) {
// 所有还没有执行过的client要保证执行(flush),防止放回连接池后后面的命令被污染
for (Jedis jedis : jedisMap.values()) {
if (clientSet.contains(jedis.getClient())) {
continue;
} flushCachedData(jedis);
}
} hasDataInBuf = false;
close();
}
} @Override
public void close() {
clean(); clients.clear(); for (Jedis jedis : jedisMap.values()) {
if (hasDataInBuf) {
flushCachedData(jedis);
} jedis.close();
} jedisMap.clear(); hasDataInBuf = false;
} private void flushCachedData(Jedis jedis) {
try {
jedis.getClient().getAll();
} catch (RuntimeException ex) {
}
} @Override
protected Client getClient(String key) {
byte[] bKey = SafeEncoder.encode(key); return getClient(bKey);
} @Override
protected Client getClient(byte[] key) {
Jedis jedis = getJedis(JedisClusterCRC16.getSlot(key)); Client client = jedis.getClient();
clients.add(client); return client;
} private Jedis getJedis(int slot) {
JedisPool pool = clusterInfoCache.getSlotPool(slot); // 根据pool从缓存中获取Jedis
Jedis jedis = jedisMap.get(pool);
if (null == jedis) {
jedis = pool.getResource();
jedisMap.put(pool, jedis);
} hasDataInBuf = true;
return jedis;
} private static Field getField(Class<?> cls, String fieldName) {
try {
Field field = cls.getDeclaredField(fieldName);
field.setAccessible(true); return field;
} catch (NoSuchFieldException | SecurityException e) {
throw new RuntimeException("cannot find or access field '" + fieldName + "' from " + cls.getName(), e);
}
} @SuppressWarnings({"unchecked" })
private static <T> T getValue(Object obj, Field field) {
try {
return (T)field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException e) {
LOGGER.error("get value fail", e); throw new RuntimeException(e);
}
} public static void main(String[] args) throws IOException {
Set<HostAndPort> nodes = new HashSet<HostAndPort>();
nodes.add(new HostAndPort("127.0.0.1", 7000));
nodes.add(new HostAndPort("127.0.0.1", 7001));
nodes.add(new HostAndPort("127.0.0.1", 7002));
JedisCluster jc = new JedisCluster(nodes); long s = System.currentTimeMillis(); JedisClusterPipeline jcp = JedisClusterPipeline.pipelined(jc);
jcp.refreshCluster();
List<Object> batchResult = null;
try {
// batch write
for (int i = 0; i < 100; i++) {
jcp.set("k" + i, "v1" + i);
}
jcp.sync(); // batch read
for (int i = 0; i < 10000; i++) {
jcp.get("k" + i);
}
batchResult = jcp.syncAndReturnAll();
} finally {
jcp.close();
} // output time
long t = System.currentTimeMillis() - s;
System.out.println(t); System.out.println(batchResult.size()); // 实际业务代码中,close要在finally中调,这里之所以没这么写,是因为懒
jc.close();
}
}

  

redis管道pipeline的更多相关文章

  1. Redis 管道pipeline

    Redis是一个cs模式的tcp server,使用和http类似的请求响应协议. 一个client可以通过一个socket连接发起多个请求命令. 每个请求命令发出后client通常会阻塞并等待red ...

  2. redis管道技术

    1.redis管道pipeline解决的问题: 由于redis通信是通过tcp协议基础,并且是堵塞的处理方式,在第一个请求没有执行并返回前,无法处理第二个请求.所以事件浪费在了网络传输和堵塞请求中. ...

  3. redis使用管道pipeline提升批量操作性能(php演示)

    Redis是一个TCP服务器,支持请求/响应协议. 在Redis中,请求通过以下步骤完成: 客户端向服务器发送查询,并从套接字读取,通常以阻塞的方式,用于服务器响应. 服务器处理命令并将响应发送回客户 ...

  4. 分布式缓存Redis之Pipeline(管道)

    Redis的pipeline(管道)功能在命令行中没有,但redis是支持pipeline的,而且在各个语言版的client中都有相应的实现. 由于网络开销延迟,就算redis server端有很强的 ...

  5. 【redis】pipeline - 管道模型

    redis-pipeline 2020-02-10: 因为我把github相关的wiki删了,所以导致破图...待解决.(讲真github-wiki跟project是2个url,真的不好用) 因为用的 ...

  6. Redis管道功能

    Redis管道,Redis存储用户浏览数据 当频繁的存储获取Redis数据库中的数据时,可以使用Redis的pipeline(管道)功能,将多个相互没有依赖关系的读写操作,如:下一步执行的Redis操 ...

  7. Redis管道理解

    Redis管道理解 简介 管道并不是Redis本身提供的功能,通常是客户端提供的功能: 管道就是打包多条无关命令批量执行,以减少多个命令分别执行消耗的网络交互时间(TCP网络交互),可以显著提升Red ...

  8. redis学习(六)redis管道

    redis管道 1.redis管道介绍 redis采用的是CS架构,客户端与服务器端通过tcp协议进行连接通信,因此无论是发出请求还是接收响应,都必须经过网络传输.在tcp连接过程中,客户端和服务器端 ...

  9. 缓存数据库-redis(管道)

    一:Redis 管道技术 Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务.这意味着通常情况下一个请求会遵循以下步骤: 客户端向服务端发送一个查询请求,并监听Socket返回,通常 ...

随机推荐

  1. vi/vim常用命令总结

    vim是vi的升级模式,完全兼容vi 解决vim打开中文乱码问题 编辑/etc/vim/vimrc配置文件,添加下面的内容: ''' set fileencodings=utf-8,ucs-bom,g ...

  2. git 命令解析

    git 补丁 Git 提供了两种补丁方案:   (1)用 git diff 生成的UNIX标准补丁.diff文件:.diff文件只是记录文件改变的内容,不带有commit记录信息,多个commit可以 ...

  3. uwsgi_response_write_body报错的几种情况

    1.uwsgi_response_write_body_do(): Broken pipe 出现这种情况一般是由于客户端无法等到服务端的回应而关闭了连接,常出现与nginx + uwsgi的情况,当u ...

  4. jenkins 构建时显示git分支插件、显示构建分支插件

    参数化构建分支 1.安装插件:Git Parameter 2.找到我们在Jenkins中建立的工程,勾选“参数化构建过程”,并如下配置 3.在“源码管理”中如下配置 Jenkins构建完显示构建用户和 ...

  5. http与tcp

    一.基本概念 1.TCP连接 手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接.TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别” ...

  6. 关于3.1 jmu-Java-03面向对象基础-01-构造函数与toString (3 分)

    PTA显示Compiler did not create the expected binary 不知所措   package nn;  import java.util.Scanner;       ...

  7. idea+maven3.6.1构建maven工程报PKIX:unable to find valid certification path to requested target

    转载于  https://www.cnblogs.com/xiaoping1993/p/9717649.html 注意可能在idea工具执行java命令提示找不到类,返回类的最上层包路径 然后再执行j ...

  8. strtok的使用

    /* strtok函数的使用 */ #include <stdio.h> #include <stdlib.h> #include <string.h> // 函数 ...

  9. 微信小程序左右联动菜单(即可左联动,也可右联动)

    <!-- 搜索 --> <view class="search"> <input class="search-box" place ...

  10. 修改vue-cli脚手架顶部图标

    1. 将ico图标放到static目录下 2. 在 build/webpack.dev.conf.js 文件修改   new HtmlWebpackPlugin({ ... favicon: './s ...