深度评测丨 GaussDB(for Redis) 大 Key 操作的影响
本文分享自华为云社区《墨天轮评测:GaussDB(for Redis)大Key操作的影响》,作者: 高斯 Redis 官方博客。
在前一篇文章《墨天轮评测:GaussDB(for Redis)稳定性与扩容表现》 中,我们使用多线程压测工具 memtier_benchmark 对华为 GaussDB(for Redis)和原生 Redis 进行了对比压测,发现原生 Redis 容易出现 OOM 故障,且扩容操作会很慢,给运维带来很大压力。反观华为 GaussDB(for Redis)不仅性能稳定,还具备在压测过程中秒级扩容的能力,扩容操作对业务读写无影响。华为 GaussDB(for Redis)支持全量数据落盘,GaussDB 基础组件服务提供底层数据三副本冗余保存,能够保证数据零丢失。如果使用场景既要满足 KV 查询的高性能,又希望数据得到重视能够不丢,则华为 GaussDB(for Redis)是合适的选型。
我们大多在实际生产环境中都遇到过 big key 对 Redis 性能的严重影响。接下来我们通过几个简单的实验,测试下对于大 key 这一“性能杀手”,GaussDB(for Redis)的表现怎样,和原生 Redis 相比在性能上有哪些改进?
1、访问大 key
首先分别在 GaussDB(for Redis)和原生 redis 中创建一个大的 hash 类型的 key。
编辑一个简单的 lua 脚本,向一个 hash key 中插入一千万条数据。
- # vim redis-bigkey.lua
- local result
- for var=1,10000000,1 do
- redis.call('hset',KEYS[1],var,var)
- redis.call('lpush',KEYS[2],var)
- redis.call('sadd',KEYS[3],var)
- end
- return result
向 GaussDB(for Redis)【192.168.0.226:8635】中插入大 key
- # redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 --eval /root/redis-bigkey.lua 3 hset_test list_test set_test
- (nil)
- # redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 hlen hset_test
- (integer) 10000000
- # redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 scard sadd_test
- (integer) 10000000
- # redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 llen lpush_test
- (integer) 10000000
向原生 Redis【192.168.0.135】中插入大 key
- # redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 --eval /root/redis-bigkey.lua 3 hset_test list_test set_test
- (nil)
- # redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 hlen hset_test
- (integer) 10000000
- # redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 scard sadd_test
- (integer) 10000000
- # redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 llen lpush_test
- (integer) 10000000
使用 memtier_benchmark 模拟业务压力的同时 对大 key 进行访问,观察对业务 qps 的影响。
编辑一个简单 shell 脚本,对大 key 进行频繁的访问
- #!/bin/bash
- while true
- do
- redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 hget hset_test $RANDOM
- redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 hget hset_test $RANDOM
- redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 LREM lpush_test 0 $RANDOM
- redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 LREM lpush_test 0 $RANDOM
- redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 SISMEMBER sadd_test $RANDOM
- redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 SISMEMBER sadd_test $RANDOM
- done
使用 memtier_benchmark 进行压测,读写混合场景。通过反馈的性能数据可以看到 GaussDB(for Redis) 和 Redis 每秒的操作数 ops/sec 分别为 14 万和 13 万,差别不大。
- #GaussDB(for Redis)
- memtier_benchmark -s 192.168.0.226 -a XXXXXXX -p 8635 -c 16 -t 12 -n 100000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000000 --key-minimum=1 --key-prefix= --ratio=1:1 --out-file=./result_gauss_setget.log
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 3%, 4 secs] 12 threads: 582045 ops, 144053 (avg: 145472) ops/sec, 21.16MB/sec (avg: 21.51MB/sec), 1.33 (avg: 1.32) msec latency
- #原生Redis
- memtier_benchmark -s 192.168.0.135 -a XXXXXXX -p 6379 -c 16 -t 12 -n 100000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000000 --key-minimum=1 --key-prefix= --ratio=1:1 --out-file=./result_redis_setget.log
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 7%, 11 secs] 12 threads: 1430798 ops, 132637 (avg: 130051) ops/sec, 70.51MB/sec (avg: 68.79MB/sec), 1.44 (avg: 1.47) msec latency
启动 shell 脚本后再次观察,发现 GaussDB(for Redis) 的每秒操作数几乎无变化,而原生 Redis 的每秒操作数波动巨大,甚至降低到了 3k 左右。说明大 key 操作对原生 Redis 性能有较大影响,对 GaussDB(for Redis) 的影响可控。
- # bash hget_bigkey.sh
- #GaussDB(for Redis)
- # memtier_benchmark -s 192.168.0.226 -a XXXXXXX -p 8635 -c 16 -t 12 -n 100000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000000 --key-minimum=1 --key-prefix= --ratio=1:1 --out-file=./result_gauss_setget.log
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 47%, 64 secs] 12 threads: 9099444 ops, 139186 (avg: 142163) ops/sec, 20.60MB/sec (avg: 20.96MB/sec), 1.38 (avg: 1.35) msec latency
- #原生Redis
- # memtier_benchmark -s 192.168.0.135 -a XXXXXXX -p 6379 -c 16 -t 12 -n 100000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000000 --key-minimum=1 --key-prefix= --ratio=1:1 --out-file=./result_redis_setget.log
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 29%, 75 secs] 12 threads: 5607700 ops, 3329 (avg: 74759) ops/sec, 1.80MB/sec (avg: 40.08MB/sec), 52.35 (avg: 2.55) msec latencyy
2、删除大 key
继续使用 memtier_benchmark 对 GaussDB(for Redis) 和原生 Redis 进行测试,只读场景。在 GaussDB(for Redis)中删除大 key 很快就能完成,且对性能几乎无影响。
- #GaussDB(for Redis)
- # memtier_benchmark -s 192.168.0.226 -a XXXXXXX -p 8635 -c 16 -t 12 -n 100000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000000 --key-minimum=1 --key-prefix= --ratio=0:1 --out-file=./result_gauss_setget.log
- Writing results to ./result_gauss_setget.log...
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 4%, 5 secs] 12 threads: 719216 ops, 151326 (avg: 143795) ops/sec, 22.16MB/sec (avg: 21.13MB/sec), 1.27 (avg: 1.33) msec latency
- # time redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 del sadd_test
- (integer) 1
- real 0m0.003s
- user 0m0.001s
- sys 0m0.002s
- # memtier_benchmark -s 192.168.0.226 -a XXXXXXX -p 8635 -c 16 -t 12 -n 100000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000000 --key-minimum=1 --key-prefix= --ratio=0:1 --out-file=./result_gauss_setget.log
- Writing results to ./result_gauss_setget.log...
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 42%, 57 secs] 12 threads: 8031731 ops, 144874 (avg: 140890) ops/sec, 21.46MB/sec (avg: 20.77MB/sec), 1.32 (avg: 1.36) msec latency
反观原生 Redis,删除大 key 耗时 3 秒,且在删除期间对性能影响较大。可以观察到在删除期间 ops/sec 变成 0,也就是说大 key 删除期间操作是没有办法正常响应的。
- #原生Redis
- # memtier_benchmark -s 192.168.0.135 -a XXXXXXX -p 6379 -c 16 -t 12 -n 100000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000000 --key-minimum=1 --key-prefix= --ratio=0:1 --out-file=./result_redis_setget.log
- Writing results to ./result_redis_setget.log...
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 6%, 7 secs] 12 threads: 1107132 ops, 157621 (avg: 158125) ops/sec, 16.07MB/sec (avg: 16.13MB/sec), 1.22 (avg: 1.21) msec latency
- # time redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 del sadd_test
- (integer) 1
- real 0m3.001s
- user 0m0.000s
- sys 0m0.003s
- # memtier_benchmark -s 192.168.0.135 -a XXXXXXX -p 6379 -c 16 -t 12 -n 100000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000000 --key-minimum=1 --key-prefix= --ratio=0:1 --out-file=./result_redis_setget.log
- Writing results to ./result_redis_setget.log...
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 57%, 68 secs] 12 threads: 1015893 ops, 0 (avg: 126961) ops/sec, 0.00KB/sec (avg: 12.98MB/sec), -nan (avg: 1.13) msec latencyy
手动删除大 key 对性能的影响差别明显,如果设置大 key 的过期时间交由 Redis 删除过期数据 是否会有性能影响呢?下面简单测试下
手动设置大 key 的过期时间,并启动 memtier_benchmark 读写混合测试,查看对性能的影响。通过测试发现大 key 的过期对于 GaussDB(for Redis)的性能几乎没有影响。
- #GaussDB(for Redis)
- [root@ecs-ef13-0001 ~]# redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 EXPIRE sadd_test 8 && redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 EXPIRE sadd_test1 12
- (integer) 1
- (integer) 1
- [root@ecs-ef13-0001 ~]# memtier_benchmark -s 192.168.0.226 -a XXXXXXX -p 8635 -c 16 -t 12 -n 10000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000 --key-minimum=1 --key-prefix= --ratio=1:1 --out-file=./result_gauss_setget.log
- Writing results to ./result_gauss_setget.log...
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 100%, 17 secs] 0 threads: 1920000 ops, 106367 (avg: 109940) ops/sec, 105.02MB/sec (avg: 108.55MB/sec), 1.74 (avg: 1.74) msec latency
在对原生 Redis 测试时,我们发现大 key 过期操作几乎阻塞了正常的读写,在 memtier_benchmark 测试时 ops/sec 指标为 0,只有当大 key 过期操作结束后才恢复正常。
- #原生Redis
- [root@ecs-ef13-0001 ~]# redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 EXPIRE sadd_test 8 && redis-cli -h 192.168.0.135 -a XXXXXXX -p 6379 EXPIRE sadd_test1 12
- (integer) 1
- (integer) 1



- [root@ecs-ef13-0001 ~]# memtier_benchmark -s 192.168.0.135 -a XXXXXXX -p 6379 -c 16 -t 12 -n 10000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000 --key-minimum=1 --key-prefix= --ratio=1:1 --out-file=./result_redis_setget.log
- Writing results to ./result_redis_setget.log...
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 100%, 42 secs] 0 threads: 1920000 ops, 134502 (avg: 45551) ops/sec, 132.80MB/sec (avg: 44.98MB/sec), 1.43 (avg: 4.21) msec latency
开源 redis 的过期虽然也支持异步,但需要用户手动配置策略;删除操作则需用 UNLINK 替换常规的 DEL,具体对性能的影响可能会有所降低,本次不做深入验证。华为 GaussDB(for Redis)的删除和过期对性能 0 影响。
3、大 key 对 GaussDB(for Redis)扩容操作的影响
在上一篇文章中我们测试了 GaussDB(for Redis)的在线扩容功能,经测试 GaussDB(for Redis)可以在不影响业务读写的前提下实现秒级的扩容。这次我们增加一些“难度”,看看存在大 key 的情况下 GaussDB(for Redis)扩容操作是否还能做到秒级和业务零感知。
预先在 GaussDB(for Redis)中插入大 key
- [root@ecs-ef13-0001 ~]# redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 scard sadd_test4
- (integer) 10000000
- [root@ecs-ef13-0001 ~]# redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 scard sadd_test5
- (integer) 10000000
- [root@ecs-ef13-0001 ~]# redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 scard sadd_test6
- (integer) 10000000
- [root@ecs-ef13-0001 ~]# redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 scard sadd_test7
- (integer) 10000000
- [root@ecs-ef13-0001 ~]# redis-cli -h 192.168.0.226 -a XXXXXXX -p 8635 scard sadd_test8
- (integer) 10000000
使用 memtier_benchmark 模拟读写请求,同时在控制台上进行扩容操作。同之前的测试效果一样,GaussDB(for Redis)同样实现了对业务零感知的秒级扩容
- [root@ecs-ef13-0001 ~]# memtier_benchmark -s 192.168.0.226 -a XXXXXXX -p 8635 -c 16 -t 12 -n 50000 --random-data --randomize --distinct-client-seed -d 1000 --key-maximum=65000 --key-minimum=1 --key-prefix= --ratio=0:1 --out-file=./result_gauss_setget.log
- Writing results to ./result_gauss_setget.log...
- [RUN #1] Preparing benchmark client...
- [RUN #1] Launching threads now...
- [RUN #1 9%, 20 secs] 12 threads: 902361 ops, 42634 (avg: 45112) ops/sec, 41.99MB/sec (avg: 44.44MB/sec), 4.53 (avg: 4.23) msec latencycy


4、总结
原生 Redis 对大 key 的访问,删除等操作会严重阻塞业务的正常访问,这是由 Redis 自身单线程处理请求的架构决定的。使用原生 Redis 时需要严格限制大 key 的使用,一旦出现大 key 对系统的性能影响通常是“致命”的。
反观 GaussDB(for Redis)由于采用多线程架构,对大 key 的访问、删除,以及存在大 key 情况下的扩容操作,对性能的影响都是可控的。1)大 key 访问场景中,由于 GaussDB(for Redis)采用的多线程的架构,不易阻塞其他业务操作。2)大 key 删除的场景中,由于 GaussDB(for Redis)实现的逻辑不同,删除操作能够快速完成,对业务无影响。3)扩容场景中,GaussDB(for Redis)不涉及 key 迁移,大 key 对扩容更是 0 影响。
综上,虽然一般推荐业务设计避免大 key,但在一些需要操作少量大 key 的业务场景,华为云 GaussDB(for Redis)表现更佳。
此外,从业务开发角度看,当多业务共用一个实例时,使用 GaussDB(for Redis)的话,即使其他业务引入大 key,自己的业务也不至于受太大影响。
深度评测丨 GaussDB(for Redis) 大 Key 操作的影响的更多相关文章
- Redis大 key的发现与删除方法全解析
个推作为国内第三方推送市场的早期进入者,专注于为开发者提供高效稳定的推送服务,经过9年的积累和发展,服务了包括新浪.滴滴在内的数十万APP.由于我们推送业务对并发量.速度要求很高,为此,我们选择了高性 ...
- Redis大key的发现与删除方法全解析
个推作为国内第三方推送市场的早期进入者,专注于为开发者提供高效稳定的推送服务,经过9年的积累和发展,服务了包括新浪.滴滴在内的数十万APP.由于我们推送业务对并发量.速度要求很高,为此,我们选择了高性 ...
- Redis 大 key 问题 & 问题分析 & 解决方案
Redis 大 key 问题 & 问题分析 & 解决方案 Redis 什么是 Redis 大 key 单个key 存储的 value 很大 hash, set,zset,list 结构 ...
- Redis 大 key 问题总结
多大的 key 算大? 阿里云Redis 最佳实践中提到 合理的 Key 中 Value 的字节大小,推荐小于10 KB.过大的 Value 会引发数据倾斜.热点Key.实例流量或 CPU 性能被占满 ...
- 统计redis大key信息(前topN)
相关包下载链接 https://github.com/sripathikrishnan/redis-rdb-tools/releaseshttps://pypi.org/project/python- ...
- C#Redis 常用key操作
一.前戏 在该系列的前几篇博客中,主要讲述的是与Redis数据类型相关的命令,如String.List.Set.Hashes和Sorted-Set.这些命令都具有一个共同点,即所有的操作都是针对与Ke ...
- redis 删除大key集合的方法
redis大key,这里指的是大的集合数据类型,如(set/hash/list/sorted set),一个key包含很多元素.由于redis是单线程,在删除大key(千万级别的set集合)的时候,或 ...
- Redis 的大 Key 对持久化有什么影响?
作者:小林coding 图解计算机基础(操作系统.计算机网络.计算机组成.数据库等)网站:https://xiaolincoding.com 大家好,我是小林. 上周有位读者字节一二面时,被问到:Re ...
- 如何提取Redis中的大KEY
工作中,经常有些Redis实例使用不恰当,或者对业务预估不准确,或者key没有及时进行处理等等原因,导致某些KEY相当大. 那么大Key会带来哪些问题呢? 如果是集群模式下,无法做到负载均衡,导致请求 ...
随机推荐
- 【LeetCode】1110. Delete Nodes And Return Forest 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 日期 题目地址:https://leetcode ...
- 【LeetCode】697. Degree of an Array 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 求出最短相同子数组度的长度 使用堆求最大次数和最小长 ...
- idea使用教程-模板的使用
一.代码模板是什么 它的原理就是配置一些常用代码字母缩写,在输入简写时可以出现你预定义的固定模式的代码,使得开发效率大大提高,同时也可以增加个性化.最简单的例子就是在Java中输入sout会出现Sys ...
- libecc:一个可移植的椭圆曲线密码学库
libecc:一个可移植的椭圆曲线密码学库 这段时间要写毕设关于椭圆曲线的部分,就参考了一个椭圆曲线库的代码来编写.这个库中的代码的结构.风格和封装在我看来是十分完善的.用起来也比较方便,当作一个密码 ...
- 去除input标签点击时的默认样式
去除input标签点击时的默认样式的方法 outline:none; //去除点击时的边框 border : none; //去除input框的边框
- CS5213替代AG6200 AG6201|HDMI转VGA带音频输出方案芯片
台湾安格AG6200 AG6201专门用于设计HDMI转VGA带音频输出的方案芯片,CS5213是一款HDMI to VGA转换器且结合了HDMI输入接口和模拟RGB DAC输出.带支持片上音频数模转 ...
- SpringCloud创建Eureka Client服务注册
1.说明 本文详细介绍微服务注册到Eureka的方法, 即Eureka Client注册到Eureka Server, 这里用任意一个Spring Cloud服务为例, 比如下面已经创建好的Confi ...
- Lombok的利弊
1.介绍 Lombok是一个可以大量减少代码的工具, 通过Pluggable Annotation Processing API的方式解析注解, 在编译期为class文件注入getter,setter ...
- STM32新建模板之库文件
一.新建项目文件夹 在桌面创建项目文件夹,用于存放工程,命名为"stm32f10x_project" 在项目文件夹中创建3个文件夹,分别命名为:CMSIS.OUTPUT.STM32 ...
- Azure Terraform(九)GitHub Actions 实现 Infra 资源的自动化部署
思路浅析 使用 Terraform Code 部署 Azure 基础设施资源是特别受欢迎的,我曾经有写文章分享过利用 Azure DevOps 自动部署 Terraform Code 所描述的 Azu ...