深度评测丨 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】858. Mirror Reflection 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 1046:Square Number
总时间限制: 1000ms 内存限制: 65536kB 描述 给定正整数b,求最大的整数a,满足a*(a+b) 为完全平方数 输入 多组数据,第一行T,表示数据数.对于每组数据,一行一个正整数表示b. ...
- Java线程安全MAP ,LIST ,SET
ConcurrentHashMap是线程安全的HashMap, CopyOnWriteArrayList是线程安全的ArrayList CopyOnWriteArraySet是线程安全的Set.
- Chapter 7 Confounding
目录 7.1 The structure of confounding Confounding and exchangeability Confounding and the backdoor cri ...
- 关于 base64 编码
一.什么是Base64编码 Base64是一种用64个字符来表示任意二进制数据的方法.它是一种编码方式,而非加密方式.它通过将二进制数据转变为64个"可打印字符",完成了数据在HT ...
- Java面向对象程序设计作业目录(作业笔记)
持续更新中............. 我的大学笔记>>> 第1章 面向对象 >>> 1.1.5 编写Java程序,创建Dota游戏中的防御塔类,通过两个坐属性显示防 ...
- css 快速入门 系列 —— 浮动
浮动 以 mdn float 文档 为基础,逐一介绍浮动的本质.浮动的诸多特性.清除浮动以及块格式化上下文(bfc). 概念 当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移 ...
- 2 - 基于ELK的ElasticSearch 7.8.x技术整理 - java操作篇 - 更新完毕
3.java操作ES篇 3.1.摸索java链接ES的流程 自行创建一个maven项目 3.1.1.依赖管理 点击查看代码 <properties> <ES-version>7 ...
- JMeter跨线程,怎么定义全局变量,跨线程使用变量?
JMeter跨线程时,怎么定义全局变量,跨线程使用此变量? 通过函数助手,获取到设置变量的语法脚本 2.通过Bean shell Sampler取样器,定义全局变量 3.定义好全局变量,可以调用,调用 ...
- 779. 第K个语法符号
<找规律> <递归> 题目描述 在第一行我们写上一个 0.接下来的每一行,将前一行中的0替换为01,1替换为10. 给定行数 N 和序数 K,返回第 N 行中第 K个字符.(K ...