? ? ? ? ?取交集的场景很多,比如公众号文章显示有多少个好友已读,又或者群聊成员列表显示有多少个好友已经入群。最近遇到一个类似场景,一开始的觉得线上数据量较大,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大量处理时间,带来普通请求的延迟或者超时,这一点也需要在业务中考虑。
|