Redis 有序集合(zset)取交集(zinterstore)操作耗时测试

         取交集的场景很多,比如公众号文章显示有多少个好友已读,又或者群聊成员列表显示有多少个好友已经入群。最近遇到一个类似场景,一开始的觉得线上数据量较大,redis 取交集操作时间复杂度在O(N),实时计算会不会不合适?是否离线计算更好?请教了组内资深大佬,大佬说数据量不大的情况下redis计算挺快的。听了之后感觉需要实际测试一下,不然贸然上线心里没底。下面是测试流程,有需要的同学可以参考下。

        假定测试目标是统计在线用户中付费用户数量,测试结果如下图,先说结论:耗时和数据集大小以及数据集重合度有关(废话,耗时肯定和数据集大小有关^_^)。测试结果也和zinterstore 的时间复杂度是一致的。下图右侧是提高重合度的结果,耗时明显有增加。

ZINTERSTORE 时间复杂度: O(N*K)+O(M*log(M)) 
这里N表示有序集合中成员数最少的数字,K表示有序集合数量。M表示结果集中重合的数量。

测试设备:

        腾讯云服务器 16核 32G内存

数据集通过redis lua脚本跑出

create_data.lua 脚本:

-- 1000 用户量
redis.call("del","online_user_1000", "rich_user_1000","online_user_5000","rich_user_5000","online_user_10000","rich_user_10000","online_user_50000","rich_user_50000","online_user_100000","rich_user_100000")
for i = 1, 1000, 1 do
redis.call("zadd", "online_user_1000", math.random(1000000)*math.random(100000), math.random(10000000))
redis.call("zadd", "rich_user_1000", math.random(1000000)*math.random(100000), math.random(10000000))
end

-- 5000 用户量
for i = 1, 5000, 1 do
redis.call("zadd", "online_user_5000", math.random(1000000)*math.random(100000), math.random(10000000))
redis.call("zadd", "rich_user_5000", math.random(1000000)*math.random(100000), math.random(10000000))
end

-- 10000 用户量
for i = 1, 10000, 1 do
redis.call("zadd", "online_user_10000", math.random(1000000)*math.random(100000), math.random(10000000))
redis.call("zadd", "rich_user_10000", math.random(1000000)*math.random(100000), math.random(10000000))
end

-- 50000 用户量
for i = 1, 50000, 1 do
redis.call("zadd", "online_user_50000", math.random(1000000)*math.random(100000), math.random(10000000))
redis.call("zadd", "rich_user_50000", math.random(1000000)*math.random(100000), math.random(10000000))
end

-- 100000 用户量
for i = 1, 100000, 1 do
redis.call("zadd", "online_user_100000", math.random(1000000)*math.random(100000), math.random(10000000))
redis.call("zadd", "rich_user_100000", math.random(1000000)*math.random(100000), math.random(10000000))
end

-- 500000 用户量
for i = 1, 500000, 1 do
redis.call("zadd", "online_user_500000", math.random(1000000)*math.random(100000), math.random(10000000))
redis.call("zadd", "rich_user_500000", math.random(1000000)*math.random(100000), math.random(10000000))
end

-- 1000000 用户量
for i = 1, 1000000, 1 do
redis.call("zadd", "online_user_1000000", math.random(1000000)*math.random(100000), math.random(10000000))
redis.call("zadd", "rich_user_1000000", math.random(1000000)*math.random(100000), math.random(10000000))
end

return "OK"

 测试工具:redis-benchmark

测试命令如下,-n表示执行次数

redis-benchmark -n 10000 zinterstore inter_user_1000 2 online_user_1000 rich_user_1000
redis-benchmark -n 10000 zinterstore inter_user_5000 2 online_user_5000 rich_user_5000
redis-benchmark -n 10000 zinterstore inter_user_10000 2 online_user_10000 rich_user_10000
redis-benchmark -n 10000 zinterstore inter_user_50000 2 online_user_50000 rich_user_50000
redis-benchmark -n 10000 zinterstore inter_user_100000 2 online_user_100000 rich_user_100000
redis-benchmark -n 10000 zinterstore inter_user_500000 2 online_user_500000 rich_user_500000
redis-benchmark -n 10000 zinterstore inter_user_1000000 2 online_user_1000000 rich_user_1000000

测试截图:

         在我的业务场景里,数据集一般在1万以下,上限不会超过100万,结合本次实测结果,实时计算应该没啥问题。测试过程中也发现,虽然单个请求耗时不大,但是如果存在大量请求,并且这些请求对应数据规模很大,则势必占用redis server大量处理时间,带来普通请求的延迟或者超时,这一点也需要在业务中考虑。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值