华为云企业级Redis评测第二期:大Key操作的影响

点击蓝字

f414f0e105e8936f6b76fbb74af69ee6.png

关注我们

在前一篇文章《华为云企业级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

348741458e7b89eaa6d111f7da0ae462.png

cfcc3958577741775ff8d1c970942746.png

e5b33505ace94e9726af1ece954e06ef.png

[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

1f61a5871e702c7612790d7d3d379bfe.png

25da6067bdc5cc6d94e5e3e8b3a4ecdd.png

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,自己的业务也不至于受太大影响。


墨天轮原文链接:https://www.modb.pro/db/240347?sjhy(复制到浏览器或者点击“阅读原文”立即查看)

关于作者

杨明翰,云和恩墨服务总监。拥有MySQL、TDSQL、TiDB、openGauss等认证。长期从事MySQL、PG、Redis、MongoDB的数据库技术服务。现负责云和恩墨西区开源数据库交付运维工作;热衷于开源数据库产品的研究。

END

推荐阅读:331页!2021年度数据库技术年刊

推荐下载:2021数据技术嘉年华视频回放及PPT下载


2021数据技术嘉年华50余个PPT下载、视频回放已上传墨天轮平台,可在“数据和云”公众号回复关键词“2021DTC”获得!

你知道吗?我们的视频号里已经发布了很多精彩的内容,快去看看吧!↓↓↓

点击下图查看更多 ↓

f628275bbaabf2c882d48b688a96ee54.png

9d96559bc83c46b6e78cf6f914763419.png

4631af4f1238b1beb8c79b6a385dab25.png

云和恩墨大讲堂 | 一个分享交流的地方

长按,识别二维码,加入万人交流社群

请备注:云和恩墨大讲堂

  点个“在看” 

你的喜欢会被看到❤

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值