墨天轮评测:GaussDB(for Redis)大Key操作的影响

高斯Redis官方博客 发表于 2022/01/25 13:55:20 2022/01/25
【摘要】 本文转载自第三方墨天轮评测。评估了GaussDB(for Redis)大Key操作的表现。

目录导航

  1. 访问大key
  2. 删除大key
  3. 大key对GaussDB(for Redis)扩容操作的影响
  4. 总结


在前一篇文章《墨天轮评测: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

image.png
image.png
image.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

image.png

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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。