精华内容
下载资源
问答
  • Redis MGET性能衰减分析

    万次阅读 2018-03-29 16:19:40
    MGETredis中较为常用的命令,用来批量获取给定key对应的value。因为redis使用基于RESP (REdis Serialization Protocol)协议的rpc接口,而redis本身的数据结构非常高效,因此在日常使用中,IO和协议解析是个不容...

    MGET是redis中较为常用的命令,用来批量获取给定key对应的value。因为redis使用基于RESP (REdis Serialization Protocol)协议的rpc接口,而redis本身的数据结构非常高效,因此在日常使用中,IO和协议解析是个不容忽略的资源消耗。通过mget将多个get请求汇聚成一条命令,可以大大降低网络、rpc协议解析的开销,从而大幅提升缓存效率。mget的定义如下(来自REDIS命令参考):

    MGET key [key ...]
    返回所有(一个或多个)给定 key 的值。
    如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。
    
    返回值:
        一个包含所有给定 key 的值的列表。q
    
    例:
        redis> SET redis redis.com
        OK
        redis> SET mongodb mongodb.org
        OK
        redis> MGET redis mongodb
        1) "redis.com"
        2) "mongodb.org"

    但是,在某些需要一次批量查询大量key的场景下,我们会发现mget并没有想象中的那么完美。

    以电商库存系统(或价格系统)为例,作为原子级的服务,我们经常要面对商品列表页、活动页、购物车、交易等系统的批量查询,一次请求中动辄包含几十甚至上百个sku,此时mget是否还能像我们想象中那般保持极高的吞吐?

    我们先来设计一个实验,探一探mget性能的底。


    1 实验设计

    在本地进行了压测模拟,redis key设计:

    1. key为string类型,固定为八位数字字符串以模拟SKU ID,不足8位者高位填0
    2. value为5位整型数字,模拟商品库存
    3. 实验中将SKU ID设置为1~500000的数字

    单元测试代码设计原则:

    1. 可以方便地调整测试参数
    2. 尽量减少GC对结果的影响,设置合适的堆空间和垃圾回收器

    压测代码做了局部优化以尽量保证结果的准确性,包括:

    • 针对每一轮压测,提前准备好随机的key列表,避免随机生成key列表时大量的内存操作对测试结果造成影响
    • 每一轮压测统计多次mget的平均执行时间
    • 每一轮压测完成后,强制触发fullgc,尽量避免在压测进行中发生gc
    @Test
    public void testRedisMultiGetPerformance() {
        final int[] keyLens = new int[]{1, 2, 3, 4, 5, ..., 10000 };
        for(int keyLen : keyLens){
            noTransactionNoPipelineMultiGetWithSpecifiedKeyList(getPreparedKeys(keyLen));
        }
    }
    // 在mget前准备好随机的key列表
    private List<String[]> getPreparedKeys(int keyLen, int loopTimes) {
        int loopTimes = 1000;
        if(keyLen<10) loopTimes *= 100;
        else if (keyLen<100) loopTimes *= 50;
        else if (keyLen<500) loopTimes *= 10;
        else if (keyLen<1000) loopTimes *= 5;
        return generateKeys(keyLen, i);
    }
    // 生成 times 组不同的 String[] keys ,每组keys长度为 keyLen
    private List<String[]> generateKeys(int keyLen, int times) {
        List<String[]> keysList = new ArrayList<String[]>(times);
        for(int i=0; i<times; i++) {
            String[] keys = new String[keyLen];
            for(int j=0; j<keyLen; j++) {
                keys[j] = String.valueOf(RandomUtils.nextInt(keyCounter.get()));
            }
            keysList.add(keys);
        }
        return keysList;
    }
    // 根据预先生成的key列表通过mget取value并计算和打印平均时间
    public void noTransactionNoPipelineMultiGetWithSpecifiedKeyList(List<String[]> keysList) {
        Jedis jedis = pool.getResource();
        long meanTime = 0;
        try {
            long start = System.currentTimeMillis();
            for (String[] keys: keysList) {
                jedis.mget(keys);
            }
            meanTime += System.currentTimeMillis() - start;
        } catch (Exception e) {
            logger.error("", e);
        }finally {
            jedis.close();
            logger.info("{} | {} | {} | {} | {} | |"
                    , String.format("%5d", keysList.get(0).length)
                    , String.format("%5.3f", meanTime / Float.valueOf(keysList.size()))
                    , String.format("%9.3f", Float.valueOf(keysList.size()) * 1000 / meanTime)
                    , String.format("%5s", 5*keysList.get(0).length)
                    , String.format("%7s", keysList.size()));
            // force gc 降低在压测进行中出现gc的概率
            System.gc();
        }
    }
    

    2 JVM调优

    考虑到redis平均响应时间在0.1ms以内,而一次minor gc一般需要耗时50ms以上,而full gc更可能耗费数秒,因此需要格外注意压测时的jvm内存设置和GC配置。

    经过调试,设置Java启动参数:-Xms3g -Xmx3g -XX:+UseG1GC -XX:MaxNewSize=1g -server -XX:MaxTenuringThreshold=1时,在本实验中可以获得理想的结果。

    通过下面jstat日志可以看出,实验过程中没有出现minor gc,每一轮结束后强制进行一次full gc,full gc触发次数与压测轮数一致。因此测试中统计的时间仅包含了redis响应时间和相关代码执行时间 (在性能越高的场景下,代码执行时间相对影响越大)。

    jinlu$ jstat -gcutil $(jps | grep AppMain | cut -d " " -f 1) 4000
    S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
    0.00 100.00  24.82  20.75  97.13  93.88      9    0.719     0    0.000    0.719
    0.00 100.00   2.42  31.50  97.16  93.88     12    0.746     0    0.000    0.746
    0.00   0.00   1.39  28.67  98.06  94.73     12    0.746     1    1.832    2.579
    0.00   0.00   7.90   0.08  98.12  94.78     12    0.746     2    2.104    2.850
    ...
    0.00   0.00   9.49   0.07  95.66  95.10     13    1.035    33    5.245    6.280
    0.00 100.00  16.90  18.24  95.66  95.10     14    1.375    34    5.307    6.683
    0.00 100.00  42.14  23.35  95.66  95.10     15    1.425    34    5.307    6.733
    

    另外,为了保证结果的可靠性,整个测试期间,通过top对系统性能进行监控,结果如下:

    1. redis CPU占用率很高但未饱和,即没有出现redis性能饱和导致的响应变慢
    2. java进程的CPU占用率维持在30%上下,表明java代码没有遇到瓶颈,时间主要用于等待redis返回mget结果。

    可见压测过程中,redis的CPU占比保持在50%~80%但没有饱和,java进程的cpu保持30%~50%。因此不存在因为CPU导致的响应变慢,结果完全反应在中重度压力下redis对mget的处理能力。压测过程中抓取的top图如下:

    top系统性能

    3 实验结果

    通过针对不同的mgetkey长度进行多轮压测,得到不同的key长度下redis响应能力表如下:

    keyLen耗时msqps%lg(keyLen) keyLen耗时msqps%lg(keyLen)
    10.04025056.3771000.000 180.04920242.91480.71.255 
    20.04025284.4491000.301 200.05518214.93672.71.301 
    30.04024752.47599.80.477 250.05318811.13775.01.398 
    40.04223618.32894.20.602 320.05717525.41270.01.505 
    50.04422696.32290.60.699 400.06315888.14763.41.602 
    60.04223849.27395.20.778 500.06714889.81559.41.699 
    70.04323255.81492.80.845 600.07513276.68753.01.778 
    80.04422888.53391.30.903 800.09110979.35843.81.903 
    90.04522040.99688.00.954 1000.09610405.82741.52.000 
    100.04522065.31388.01.000 2000.1616211.18024.82.301 
    110.04621901.00887.41.041 5000.3482871.91311.52.699 
    120.04621691.97586.61.079 8000.5521812.2517.22.903 
    130.04721105.95184.21.114 10000.6391564.9456.23.000 
    140.04721258.50484.41.146 20001.201832.6393.33.301 
    150.04920300.44781.01.176 50003.140318.4711.23.699 
    160.05020032.05179.91.204 80005.297188.7860.73.903 
    170.04920234.72380.81.230 100006.141162.8400.64.000 

    下面分段进行分析。

    3.1 单次mget的key数目在50以内时

    • 一次操作10个key的性能达到一次操作1个key的88%
    • 一次操作20个key的性能达到一次操作1个key的72%
    • 一次操作50个key的性能达到一次操作1个key的59%
    keyLen<50曲线拟合

    可以看出,此时redis整体响应非常好,包含50个以内的key时,mget既可以保持高qps,又可以大幅提升吞吐量。

    3.2 单次mget的key数目在100以内时

    • 一次操作60个key的性能达到一次操作1个key的53%
    • 一次操作80个key的性能达到一次操作1个key的43%
    • 一次操作100个key的性能大道一次操作1个key的41%
    keyLen<100曲线拟合

    单次操作key数量在100以内时,性能大概能达到redis最大性能的40%以上,考虑到key的吞吐量,这样做是有足够的收益的,但是需要清楚当前场景下单个redis实例的最大吞吐量,必要时需要进行分片以提高系统整体性能。

    3.3 单次mget的key数目在1000以内

    • 一次操作200个key的性能只能达到一次操作1个key的25%,大约是一次处理100个key的60%
    • 一次操作500个key的性能只能达到一次操作1个key的11%,大约是一次处理100个key的28%
    • 一次操作800个key的性能只能达到一次操作1个key的7%,大约是一次处理100个key的17%
    keyLen<1000曲线拟合

    可见,虽然相比较较少的key,单次请求处理更多的key还是有性能上的微弱优势,但是此时性能衰减已经比较严重,此时的redis实例不在是那个动辄每秒几万qps的超人了,可能从性能上来说可以接受,但是我们要清楚此时redis的响应能力,并结合业务场景并考虑是否需要通过其他手段来为redis减负,比如分片、读写分离、多级缓存等。

    3.4 单次mget的key数目在1000以上

    • 性能急剧恶化,即使在高性能服务器上,这样的操作在单redis实例上也只能维持在千上下,此时单次请求的响应时间退化到与key数目成正比。除非你确定需要这么做,否则就要尽量避免如此多的key的批量获取,而应该从业务上、架构上考虑这么做的必要性。
    keyLen>1000曲线拟合

    3.5 请求时间与key数目对数的关系

    对mget的key数目取对数,可以得到如下曲线。

    log10(keyLen) and keyLen<10000

    【注意】 x轴为key的数目对10取对数,即log10(keyLen)

    • 当key数目在10以内时,mget性能下降趋势非常小,性能基本上能达到redis实例的极限
    • 当key数目在10~100之间时,mget性能下降明显,需要考虑redis性能衰减对系统吞吐的影响
    • 当key数目在100以上时,mget性能下降幅度趋缓,此时redis性能已经较差,不建议使用在OLTP系统中,或者需要考虑其他手段来提升性能。







    展开全文
  • Redis学习之mget命令

    千次阅读 2019-12-15 09:34:00
    Redis mget,命令返回所有(一个或多个)给定 key 的值 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 语法 mget key [key ...] 返回值 一个包含所有给定 key 的值的列表 例子 127.0.0.1:...

    mget命令

    Redis mget,命令返回所有(一个或多个)给定 key 的值
    如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil

    语法

    mget key [key ...]
    

    返回值

    一个包含所有给定 key 的值的列表

    例子

    127.0.0.1:6379> set test:key1 'key1'
    OK
    
    127.0.0.1:6379> set test:key2 'key2'
    OK
    
    127.0.0.1:6379> mget test:key1 test:key2 no:exists:key
    1) "key1"
    2) "key2"
    3) (nil)
    
    展开全文
  • redis 批量查询 mget性能问题

    千次阅读 2020-03-05 21:44:02
    Redis MGET性能衰减分析 MGETredis中较为常用的命令,用来批量获取给定key对应的value。因为redis使用基于RESP (REdis Serialization Protocol)协议的rpc接口,而redis本身的数据结构非常高效,因此在日常使用中,...

    https://blog.csdn.net/jinlu_npu/article/details/79744689

    Redis MGET性能衰减分析

    MGET是redis中较为常用的命令,用来批量获取给定key对应的value。因为redis使用基于RESP (REdis Serialization Protocol)协议的rpc接口,而redis本身的数据结构非常高效,因此在日常使用中,IO和协议解析是个不容忽略的资源消耗。通过mget将多个get请求汇聚成一条命令,可以大大降低网络、rpc协议解析的开销,从而大幅提升缓存效率

    当key数目在10以内时,mget性能下降趋势非常小,性能基本上能达到redis实例的极限
    当key数目在10~100之间时,mget性能下降明显,需要考虑redis性能衰减对系统吞吐的影响
    当key数目在100以上时,mget性能下降幅度趋缓,此时redis性能已经较差,不建议使用在OLTP系统中,或者需要考虑其他手段来提升性能。

    mget 优化思路

    https://www.jianshu.com/p/22aa8efaec8f

    展开全文
  • Description Get the values of ... $redis->mGet(array('key1', 'key2', 'key3')); /* array('value1', 'value2', 'value3'); $redis->mGet(array('key0', 'key1', 'key5')); /* array(`FALSE`, 'value2', `FALSE`);

    Description

    Get the values of all the specified keys. If one or more keys dont exist, the array will contain FALSE at the position of the key.

    取得所有指定KEYS的值,如果一个或者更多的KEYS不存在,那么返回的ARRAY中将在相应的KEYS的位置填充FALSE。

    Parameters

    Array: Array containing the list of the keys

    数组:一个KEYS的数组

    Return value

    Array: Array containing the values related to keys in argument

    数组:返回相应的KEYS的值

    Examples

    $redis->set('key1', 'value1');

    $redis->set('key2', 'value2');

    $redis->set('key3', 'value3');

    $redis->mGet(array('key1', 'key2', 'key3')); /* array('value1', 'value2', 'value3');

    $redis->mGet(array('key0', 'key1', 'key5')); /* array(`FALSE`, 'value2', `FALSE`);

    展开全文
  • 背景:近期由于跨机房数据同步问题,准备调研使用redis替换memcache,在调研过程中发现棘手的问题,原有的memcache提供大量批量获取操作(mget)操作,程序最大支持同时获取2000个。而redis最新的3.x版本引入了cluster...
  • mget Benchmark0. BackgroundScripts#!/bin/bashkey="testkey"value="testvalue"int=0while (($int <= 1024)); doecho -e $key$int $valueredis-cli set $key$int $valuelet "int++"done#!/bin/bas...
  • 本文主要测试对比目前 jedis客户端+codis集群和 lettuce客户端+redis集群的性能对比,主要测试业务最多使用的get和mget命令。 PS:redis集群为redis官方提供但并不支持mget功能,但lettuce客户端在业务层帮助实现了...
  • redis mget 获取多个key数据

    千次阅读 2020-06-02 13:15:00
    public function mget(array $keys) { if (MEMCACHE_FLAG == 2) { return null; } if (! $this->connect) { $this->connect (); } $ret = parent::mget ( $keys ); $res = array (); $i = 0; ...
  • <p>this library has mget implementation <a href="https://github.com/go-redis/redis" rel="nofollow noreferrer...<p>How is the default mget() implemented in redis in terms of time complexity ? </div>
  • 使用KEYS和MGET查询您的Redis,以将键/值写入标准输出或文件。 它支持以下格式:文本,json和csv。 安装 从PIP安装: pip install redis-mass-get CLI用法 该项目可用作CLI工具: usage: redis-mass-get [-h] [-q...
  • 前面《Redis的pipeline和mget》中说了,redis的批量操作命令对集群都不友好,因为Redis的官方集群方案是把key通过crc16计算hash映射到16384个桶上,落到哪个桶上就落到哪个机器上。网上的《缓存无底洞问题》讲了几种...
  • redis命令行执行 mget key1,key2,key3 执行失败,会报keys have defferent slots,不能跨分片查询 spring项目引用redis.clients.jedis,也会报错 springboot项目org.springframework.data.redis包,居然可以查到...
  • 目前,这不是一个确定的答案,对于不同集群的实现方式其支持度也是不一样的 原生Redis Cluster 3.* 和 4.*版本集群 3.0 不支持,即使在某些客户端下返回了值,很可能仅仅...支持MGET MSET HMGET HMSET指令 受限MG...
  • redis问题 在最近公司内部使用redis的时候,在部分场景中发现redis经常会间歇性的抖动,具体表现为在短时间内redis rt上涨明显,RedisCommandTimeoutException异常陡增,如下图: 监控面板是按照分钟级别进行...
  • redis 成批get性能提高-mget

    万次阅读 2014-11-27 15:03:17
    redismget 比get 的性能要高出很多,所以应该多使用mget List mobileList = callTestingOrderService.queryCallTestingReadyTest("2014-11-27"); List tt = RedisFacade.getInstance(true).mget(mobileList....
  • MGET命令 命令:mget key1 [key2] [key3...],返回多个key的value,如果key不存在则返回nil 127.0.0.1:6381> flushall OK 127.0.0.1:6381> mget name age 1) (nil) 2) (nil) 127.0.0.1:6381> mset name ...
  • 参考文档 搭建集群:...集群最少为3个节点,所以需要复制3份redis配置文件,每个文件更改下面几个地方: port:端口号 pidfile:/var/run/redis-6379.pid logfile:"/usr/local/var/log/re.
  • Redis集群详解

    万次阅读 多人点赞 2019-05-10 13:56:46
    Redis集群详解 Redis有三种集群模式,分别是: * 主从模式 * Sentinel模式 * Cluster模式 三种集群模式各有特点,关于Redis介绍可以参考这里:NoSQL(二)——Redis Redis官网:https://redis.io/ ,最新版本5.0.4...
  • Python操作Redis之mset和mget

    万次阅读 2015-10-16 21:54:53
    虽然有set和get操作,但是一个一个的操作终究还是麻烦,所以,我们还有mset和mget命令 python在进行mset操作时,只需要传入一个dict即可,进行mget操作,则传入一个list ...import redis import datetime import t
  • Go实战--golang中使用redis(redigo和go-redis/redis)

    万次阅读 多人点赞 2019-07-18 19:33:28
    《Go实战–go语言操作sqlite数据库(The way to go)》今天跟大家分享的是如何在golang中使用redis数据库。何为redis官网: https://redis.io/Redis is an in-memory database open-source software project
  • redis学习地址
  • redis 中pipline,mset, mget使用对比

    万次阅读 2017-08-15 11:22:08
    redis 中pipline,mset, mget使用对比标签(空格分隔): redisredis 中是支持 pipline的,它是管道的概念,也就是多次执行,一次返回。加快了执行的速度。今天来试一下,如何使用管道$redis = new Redis(); $pipe = ...
  • Redis学习(五) - 字符串MSET、MSETNX、MGET命令介绍 MSET MSET key value [key value …] 可用版本: >= 1.0.1 时间复杂度: O(N),其中 N 为被设置的键数量。 同时为多个键key设置值。 演示 如果某个给定键...
  • 支持基于pipeline的mget操作等; 代码地址 https://github.com/gilbertwang1981/redis-cluster-client.git 使用案例 配置文件 jedis-cluster: nodes: 127.0.0.1:7000;127.0.0.1:7001:127.0.0.1:7002 connect-...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,839
精华内容 9,535
关键字:

mgetredis

redis 订阅