深度评测丨 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会带来哪些问题呢? 如果是集群模式下,无法做到负载均衡,导致请求 ...
随机推荐
- 【九度OJ】题目1047:素数判定 解题报告
[九度OJ]题目1047:素数判定 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1047 题目描述: 给定一个数n,要求判 ...
- 【LeetCode】572. 另一个树的子树 Subtree of Another Tree(Python & Java)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:先序遍历 方法二:DFS + DFS 方法三 ...
- 【LeetCode】648. Replace Words 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 set 字典 前缀树 日期 题目地址:https:/ ...
- Interesting Fibonacci(hdu 2814)
Interesting Fibonacci Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- Spring企业级程序设计 • 【第7章 Spring框架整合】
全部章节 >>>> 本章目录 7.1 模型数据解析及控制器返回值 7.1.1 SSM框架环境搭建 7.1.1 ModelAndView多种用法 7.1.2 整合MyBati ...
- spring练习,使用Eclipse搭建的Spring开发环境,属性注入通过构造方法方式实现,模拟用户的正常登录。
相关 知识 >>> 相关 练习 >>> 实现要求: 使用Eclipse搭建的Spring开发环境,属性注入通过构造方法方式实现,模拟用户的正常登录.要求如下: 通过 ...
- 编写Java程序,用户在网上购买商品(good),当用户买了一本书(book)、一顶帽子(hat)或者买了一双鞋子(shoe),卖家就会通过物流将商品邮寄给用户,使用简单工厂模式模拟这一过程。
查看本章节 查看作业目录 需求说明: 编写Java程序,用户在网上购买商品(good),当用户买了一本书(book).一顶帽子(hat)或者买了一双鞋子(shoe),卖家就会通过物流将商品邮寄给用户, ...
- pod运行到指定node节点
利用labels 1.一般来说都每个节点有自己特有的labels 比如 2.利用nodeSelector nodeSelector: kubernetes.io/hostname: master3 ...
- windows环境下node安装教程(超详细)
安装node.js 1.下载node: 下载地址:http://nodejs.cn/download/ node.js的zip包安装时是直接解压缩后就可以了, node.js的msi包是傻瓜式一路ne ...
- Windows环境下使用Linux命令
1.说明 如何在Windows环境下使用Linux命令, 这是一个屡见不鲜的问题, 而且已经有很多解决方法, 下面仅推荐几个我觉得好用的工具, 这些工具可能就是我们常用的软件, 而且已经在Window ...