RedisCluster使用pipeline批量读取数据

Redis(单机&集群)Pipeline工具类 笔者语录: 我只想让一切变得简单。 提示: 本文会先给出测试代码及测试效果(使用示例),然后再贴工具类代码。 性能对比(简单)测试(含使用示例): 测试单机redis使用进行普通操作与pipeline操作: 测试代码 测试结果 测试集群redis使用进行普通操作与pipeline操作value: 测试代码 测试结果 测试集群redis使用进行普通操作与pipeline操作hash: 测试代码 测试结果 Pipeline工具类: 相关(核心)依赖: &l 阅读详情

 

Vi_NSN 2017-12-03 21:38:40  7351  已收藏 1
展开
 因为公司的Redis是Cluster的,一共有三台主机,有个需求是同时读取三千条数据,因为是Cluster,所以没办法直接使用mget。
 目前在网上找到的方法有两种,一种是写入时处理,一种是读取时处理。
 先说一下RedisCluster针对每条数据的写入的方法。RedisCluster一共有16384个slot(槽位),cluster每一个节点分管一部分slot。当有数据写入时,当用户put或者是get一个数据的时候,首先会查找这个数据对应的槽位是多少,然后查找对应的节点,然后才把数据放入这个节点。查找这个数据对应的槽位的方法就是对数据的key取模,即 CRC16(key) mod 16384,得到的结果就是写入数据存放的slot位置。
 但是当要对rediscluster进行mget批量读取的时候,因为是有不同的节点,每个节点管理一部分slot,将导致对存放在不同slot上的数据读取失败。
 如果还想要使用批量读取应该怎么办呢?目前了解到的解决方法有两种,一种是使用hash_tag模式读写。简单说就是使用”{}”来将要hash的key的部分包裹起来,rediscluster写入数据时只会对key中被”{}”包裹部分进行哈希取模计算slot位置。即存入时使用 “a{123}”和”b{123}”是在同一个slot上。这样就可以批量读取存放在同一个slot上的数据。
 第二种方法是在批量读取时,先计算所有数据的存放节点。具体做法是,我们已经知道了rediscluster对数据哈希取模的算法,可以先计算数据存放的slot位置,然后我们又可以很容易知道每个节点分管的slot段。这样,我们就可以通过key来计算出数据存放在哪个节点上。然后根据不同的节点将数据分成多批。对不同批的数据进行分批pipeline处理。

核心代码如下:


    /**
     * JedisPool和Keys的映射关系
     */
    private Map<JedisPool, ArrayList<String>> jedisPoolKeysMap;


    /**
     * 批量查询数据
     *
     * @param keys
     * @return
     */
    public Map<String, Object> getBatch(String... keys) {

        // 返回的结果,包括正确的keys的value的集合;和不存在的keys的集合
        Map<String, Object> result = new HashMap<>(16);

        // 正确的keys的value的集合
        Map<String, Map<String, Double>> existResult = new HashMap<>(16);

        // 错误的key的集合
        Set<String> errorKeys = new HashSet<>(16);

        // JedisPool和Keys的映射关系
        jedisPoolKeysMap = new HashMap<JedisPool, ArrayList<String>>();

        for (String key : keys) {
            JedisPool jedisPool = getJedisByKey(key);
            if (jedisPool == null){
                continue;
            }
            if (!jedisPoolKeysMap.keySet().contains(jedisPool)) {
                ArrayList<String> keysList = new ArrayList<>();
                keysList.add(key);
                jedisPoolKeysMap.put(jedisPool, keysList);
            } else {
                ArrayList<String> keysList = jedisPoolKeysMap.get(jedisPool);
                keysList.add(key);
            }
        }

        for (JedisPool jedisPool : jedisPoolKeysMap.keySet()) {
            Jedis jedis = jedisPool.getResource();

            Pipeline pipeline = jedis.pipelined();
            try {
                if (pipeline != null) {
                    pipeline.clear();

                    ArrayList<String> keysList = jedisPoolKeysMap.get(jedisPool);
                    for (String key : keysList) {
                        pipeline.get(key);
                    }
                    List<Object> results = pipeline.syncAndReturnAll();

                    for (int index = 0; index < results.size(); index++) {
                        if (results.get(index) == null) {
                            errorKeys.add(keysList.get(index));
                        } else {
                            existResult.put(keysList.get(index), stringToMap(results.get(index).toString()));
                        }
                    }
                }
                returnResource(jedis);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        result.put("error", errorKeys);
        result.put("exist", existResult);
        return result;
    }


    /**
     * 通过key来获取对应的jedisPool对象
     *
     * @param key
     * @return
     */
    public JedisPool getJedisByKey(String key) {
        int slot = JedisClusterCRC16.getSlot(key);
        Map.Entry<Long, String> entry;
        entry = getSlotHostMap().lowerEntry(Long.valueOf(slot + 1));

        if(entry == null){
            logger.error("entry为空!!!!! key为:" + key + ",slot为:" + slot);
            return null;
        }
        return historyCtrJedisClusterBatchUtil.getNodeMap().get(entry.getValue());
    }

    /**
     * 返还到连接池
     *
     * @param jedis
     */
    public static void returnResource(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

    /**
     * 节点映射关系
     */
    private Map<String, JedisPool> nodeMap;

    /**
     * slot和host之间的映射
     */
    private TreeMap<Long, String> slotHostMap;


    /**
     * 初始化JedisNodeMap
     */
    private void initJedisNodeMap() {
        try {
            nodeMap = historyCtrJedisClusterFactory.getClusterNodes();
            String anyHost = nodeMap.keySet().iterator().next();
            initSlotHostMap(anyHost);
        } catch (JedisClusterException e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * 获取slot和host之间的对应关系
     *
     * @param anyHostAndPortStr
     * @return
     */
    private void initSlotHostMap(String anyHostAndPortStr) {
        TreeMap<Long, String> tree = new TreeMap<Long, String>();
        String parts[] = anyHostAndPortStr.split(":");
        HostAndPort anyHostAndPort = new HostAndPort(parts[0], Integer.parseInt(parts[1]));
        try {
            Jedis jedis = new Jedis(anyHostAndPort.getHost(), anyHostAndPort.getPort());
            List<Object> list = jedis.clusterSlots();
            for (Object object : list) {
                List<Object> list1 = (List<Object>) object;
                List<Object> master = (List<Object>) list1.get(2);
                String hostAndPort = new String((byte[]) master.get(0)) + ":" + master.get(1);
                tree.put((Long) list1.get(0), hostAndPort);
                tree.put((Long) list1.get(1), hostAndPort);
            }
            jedis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        slotHostMap = tree;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        initJedisNodeMap();
    }

这是从我项目文件里直接复制出来的,有部分是冗余的,核心部分是getBatch、initJedisNodeMap、getJedisByKey、initSlotHostMap 这几个方法,其中getBatch是主入口
————————————————
版权声明:本文为优快云博主「Vi_NSN」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/Vi_NSN/article/details/78704587

redis实践及思考 导语:当面临存储选型时是选择关系型还是非关系型数据库?如果选择了非关系型的redis,redis常用数据类型占用内存大小如何估算的?redis的性能瓶颈又在哪里?背景前段... 阅读详情

相关推荐

【信息科学与工程学】计算机科学与自动化—第十五篇 云计算 11 算法篇02

但若第一个应用需求40GB/s,第二个10GB/s,总需求50GB/s>40GB/s,第一个得32GB/s,第二个得8GB/s,不公平。但若分区负载不均(分区1-2各有100任务/s,分区3-4各有50任务/s),A负责1-2(200/s),B负责3-4(100/s),仍均衡。任务 τi​ 的计算需求 Wi​(CPU周期),在频率 f 下执行时间 Ti​=Wi​/f,能耗 Ei​=Pdyn​⋅Ti​=Ceff​⋅V2⋅f⋅(Wi​/f)=Ceff​⋅V2⋅Wi​。若 Mneed​>Mi​,需使用远程显存。

weixin_49199313的博客 110

RedisCluster如何高效率地批量插入数据

RedisCluster如何高效率地批量插入数据

Funky_oaNiu的博客 2763

在Redis集群中使用pipeline批量插入的实现方法

主要介绍了在Redis集群中使用pipeline批量插入的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在Redis集群模式下使用pipeline进行批量操作

在Redis集群模式下使用pipeline进行批量操作

淡定一生2333的博客 4285

Unity 开发Apple Vision Pro物体识别追踪ObjectTracking

当您在 visionOS 应用中实现对象跟踪时,您可以将现实世界中的物体无缝集成到人们的周围环境中,以增强他们的沉浸式体验。通过跟踪一个或多个物体的 3D 位置和方向,您的应用可以使用虚拟内容增强它们。您可以使用对象跟踪来提供与人周围环境中的对象的虚拟交互,例如:引导某人使用某件物品的功能、阅读其历史或了解其在周围环境中的行为。使用虚拟手册帮助人们解决家居用品和电器的问题。

Cool-浩 1186

DCDC系列(一): COT DCDC基本原理

电流环DCDC属于双环控制模式,根据电流检测的位置,分为峰值电流环控制模式、谷值电流环控制模式和平均电流环控制模式,主要由输出电压反馈环和电流环两个环路来实现控制,其瞬态响应比电压环更好,且有自动限流的功能,但仍需要斜坡补偿网络,且对噪声敏感。Stage3: 在下管NMOS打开阶段,由于后级负载此时间段内消耗的电量较少,所以VFB还未低至Vref,所以此阶段中,上管PMOS和下管NMOS均处于关断状态,此时的电感电流为0mA,此阶段测的VSW上的电压就是Cout上的电压VREG;

weixin_40073649的博客 3948

Redis实践

换句话说,服务器吞吐量大了,可能就会导致qps急剧下降(网卡大量收发数据和redis内部协议解析,redis命令排队堆积,从而导致的缓慢),而想要qps高,服务器吞吐量可能就要降下来,无法很好的利用带宽。需求最终是完成了,可是转念一想,现在都是集群版的redis,pipeline批量请求的key可能分布在不同的机器上,但pipeline请求最终可能只被一台redis server处理,那不就是会读取数据失败吗?这个需求qps很小,所以网卡也不是瓶颈了,想要把需求优化到1s以内,减少I/O的次数是关键。

gong1122333的博客 816

Windows10开机无限蓝屏(SrtTrail.txt)

这个问题已经有很多的大佬发过解决办法了,这里仅仅作为自己日后方便查找所写文章 无法开机——自动修复失败,报SrtTrail.txt文件错误,且陷入无限蓝屏的循环 事故 故事的起因是这样的: 开开心心的组装电脑,花了几天时间来配置,然后发现USB3.0的接口太少,于是在某宝上搞到一张pcie转7口USB3.0的转接卡,往电脑上一插 插电,开机,电流轻松跑上去 然后,它和原来的磁盘阵列卡冲突,跳过阵列卡自检直接进入系统,boom,就导致了这场悲剧 解决方法 在蓝屏的界面找到:疑难解答->通过命令提示符 使

Holo__的博客 3万+

Python 异步 redis:redis-py

具有自动完成和语法突显的 Redis 命令行工具Redis 提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些 command 可以在 Linux 终端使用。在编程时,比如使用 Redis 的 python 包,这些命令都有对应的方法。下面将Redis提供的命令做一总结。1、连接操作相关的命令quit:关闭连接(connection)auth:简单密码认证2、对value操作的命令exists(key): 确认一个key是否存在del(key): 删除一个key。

freeking101的博客 8144

SAP项目结算核心:结果分析码配置与KKA2/CJ88排错实战

结果分析码(RA Key)是SAP CO模块中实现项目收入确认与成本分摊的核心机制,其本质是一套融合时间逻辑、价值计算与责任归属的动态规则引擎。它并非简单映射会计科目,而是驱动KKA2和CJ88执行项目实际结算的关键算法,直接影响毛利真实性与财务合规性。在EPC、工程服务及多阶段合同场景下,错误选用RA01等默认配置极易导致收入虚增、税务风险与管理失真。本文结合sap ko88 增强与sap mdvp主数据校验等高频实践痛点,系统解析时间确定方法、值确定方法与结果分析类型三大维度,并提供五层穿透式排查链路,

weixin_34355559的博客 343

昆仑通态屏幕制作(连载1)---接触篇

写在开始 背景:最近出了做QT、LORA和4G,还做了一个屏幕。以前做了一个迪文的串口屏幕,发现网上的教程很多,所以连载就不更新了,并且迪文屏幕的设置什么的比较简单,应该从网上都能找到对应的教程。而现在用的昆仑通态的屏幕属于嵌入式屏幕,至于为啥叫嵌入式,也不是很明白,反正就是需要用这个屏幕,嵌入式不嵌入式不重要了。重要的是能用,并且能实现串口屏幕不能实现的功能。所以选定昆仑通态的一款屏幕。 文章语言:我比较习惯用比较糙的语言介绍做的东西,有时候不太准备,但是为了方便理解,还请大家谅解。用...

weixin_45426095的博客 6738

爬虫教程( 4 ) --- scrapy-redis、集群、curl-cffi、scrapy-stealth、aio-scrapy、omnicrawl-core、反检测(反爬)浏览器

分布式爬虫 scrapy-redis、集群

freeking101的博客 6827

因果推断三种分析框架

因果推断所涉及的三种分析框架:反事实框架CF、潜在结果模型POF和结构因果模型SCM潜在结果模型POF使用数学和可计算的语言对因果理论进行阐述,是一种将假设、命题和结论清晰化表达的计算模型,其在原因和结果变量已知的前提下定量分析原因变量对结果变量的因果效应,并对缺失的潜在结果进行补齐,使观察性研究的效果接近试验性研究. 结构因果模型SCM则是一种基于图论的因果推断方法,它将事件分 为观察、干预和反事实三个层级,并通过 do 运算将干预和反事实层级的因果关系都降维成可以通过统计学手段解决的问题.目前因果推断的

qq_46044325的博客 1829

python之redis 发布订阅、集群连接、Redis 集群Docker版常用命令、集群的创建、删除、重启、常用运维命令等等

redis 发布订阅 redis 发布订阅,消息发布后,如果订阅者没有启动,错过即错过。不会再数据库中持久化 redis_publisher.py # -*- coding: utf-8 -*- import time from redis import StrictRedis, ConnectionPool class testGetRedis(): def __init__(self): pool = ConnectionPool(host='1.116.231.146',

风华浪浪的博客 187

虚拟机VMware Horizon Client与主机之间建立共享文件夹

因经常需要在虚拟机和主机之间传递一些日常文件,所以建立共享文件夹。 虚拟机中安装的系统为win10,主机中的系统为win10。 步骤: 第一步:先在虚拟机win10中新建文件夹(我重命名为“共享文件夹”),然后右键属性->共享->共享 进去之后点击自己的账户名 然后点共享。操作完成后,再返回属性界面就能看到该文件夹已经共享而且出现了共享链接,记下此链接。 第二步:回到主机桌面->此电脑->最上面计算机->添加一个网络位置- 点击下一步 然后自定义网络位置,下一步,如下图

AnChenliang_1002的博客 1万+

基于Mask-RCNN网络的书架图书书脊分割和检测(含代码)

图书馆的书架上的图书书脊分割/检测对于图书书名等信息的识别具有重要意义,因此,该博客基于Mask-RCNN网络实现了图书书脊的分割和检测,有利于进一步利用ocr文字识别技术实现图书书名等信息的入库。如下图所示,为书架原始数据和分割/检测后的结果。(本文已训练模型,无需训练)

qq_44619530的博客 2026

业务不停机、数据零丢失:Redis / RabbitMQ / Elasticsearch 三大核心中间件升级改造集群无缝平滑迁移

前言:在现代微服务架构演进的过程中,系统往往会面临从“单机架构”向“高可用集群架构”升级的痛点。前阵子一位同行私信我,说他接手了一套核心业务系统,Redis、RabbitMQ、Elasticsearch 均部署在单节点上。随着业务量突增,系统面临极高的高可用与性能风险,迫切需要升级到集群模式。

weixin_66855479的博客 594

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

如何使用JedisCluster 实现 Pipeline快速写数据?

jediscluster 实现 pipeline、大量数据快速写redis

u012573226的专栏 2205

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Redis JedisCluster 中使用PipeLine

Redis、Java

caokai1992的专栏 5685

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

redis cluster使用pipeline

redis cluster使用pipeline为什么cluster无法使用pipeline基于redisCluster整合pipeline设计思路代码实现 为什么cluster无法使用pipeline 主要是因为redis-cluster的hash分片。具体的redis命令,会根据key计算出一个槽位(slot),然后根据槽位去特定的节点redis上执行操作。那么pipeline中每个单独的操作,...

aisu_yan的博客 1087

RedisCluster-Pipeline操作,提升10倍以上响应速度2021-03-15

文章目录 什么是pipeLine 为什么使用pipeLine ? 为什么RedisCluster无法使用pipeline? 如何基于JedisCluster扩展pipeline? 性能对比(提升10倍以上): 本文中的代码来自我正在写的分布式缓存框架(主要解决缓存使用中的各种痛点:缓存穿透\redis-cluster pipeline\注解使用等等)。后续内部推广使用后、成熟后会开源回馈大家。 什么是pipeLine 为什么使用pipeLine ? 管道(pipeline)将客户端 client 与服务.

u011250186的博客 496

RedisCluster-Pipeline操作,提升10倍以上响应速度

本文中的代码来自我正在写的分布式缓存框架(主要解决缓存使用中的各种痛点:缓存穿透\redis-cluster pipeline\注解使用等等)。 什么是pipeLine 为什么使用pipeLine ? 管道(pipeline)将客户端 client 与服务器端的交互明确划分为单向的发送请求(Send Request)和接收响应(Receive Response):用户可以将多个操作连续发给服务...

张硕的博客 1万+

一文教你Redis Cluster批量操作的所有姿势(附代码实操)

Redis Cluster 批量操作Key 技巧,用多种方式提供了批量操作的思路,各位可以根据自己的业务量级来选择合适的方法。

weixin_45563088的博客 2092

JedisPool单节点及Cluster通道单条/批量插入,读

@Autowired private JedisPool jedisPool; /** *一、 单节点通道批量插入 */    Jedis jedis = jedisPool.getResource();  Pipeline jcp = jedis.pipelined();        Map map = new HashMap();    for (int i = 0

飞奔的小土豆@1024 1543

redis cluster如何自定义使用pipeline

在多年的SparkStreaming的大数据流处理开发中,除了Kafka,Redis是用的最多的组件。目前生产有多个redis集群,最大的32节点的集群的key已经达到40亿个,峰值2000万的QPS。离线更新的维表数据,用于增加流数据的维度信息应用实时更新的状态数据不管是哪种应用场景,最后在SparkStreaming中都需要与Redis进行交互,来完成get、set操作假如SparkStreaming中RDD的时间间隔为1min,那么这个窗口的数据在1min内计算完成才算是"不延迟"。

CatchLight的博客 1097
上一篇: Redis中PipeLine使用(二)---批量get与批量set
下一篇: Redis使用pipeLine批量获取数据加快接口响应速度 
王树民
博客等级 码龄10年 912粉丝 560原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值