我怀疑最大化 Redis 的 CPU 使用率是否有利于您的后端设计。正确的问题是 Redis 是否足够高效,能够在给定的延迟下维持吞吐量。 Redis 是一个单线程服务器:在 80% CPU 消耗时,延迟可能会非常糟糕。
我建议您在 redis-benchmark 运行时测量延迟,看看它是否可以满足您的需求,然后再尝试增加 Redis CPU 消耗。 redis-cli 的 --latency 选项可用于此目的:
- 启动 redis 服务器
- 尝试 redis-cli --latency,记下 avg 值,停止它
- 在另一个窗口中,启动基准测试,并确保它运行一段时间
- 尝试 redis-cli --latency,记下 avg 值,停止它
- 停止基准测试
- 比较两个平均值
现在,如果您确实想增加 Redis CPU 消耗,您需要一个能够同时处理多个连接的高效客户端程序(如 redis-benchmark),或者客户端程序的多个实例。
Lua 是一种快速解释性语言,但它仍然是一种解释性语言。它会比 C 代码慢一两个数量级。 Redis 在解析/生成其协议方面比 lua-redis 快得多,因此您将无法使用唯一的 Lua 客户端使 Redis 饱和(除非您使用 O(n) Redis 命令 - 见下文)。
webdis是用C实现的,具有高效的客户端库,但必须解析http/json协议,该协议恰好比Redis协议更冗长和复杂。对于大多数操作来说,它可能比 Redis 本身消耗更多的 CPU。再说一遍,您不会用单个 webdis 实例使 Redis 饱和。
以下是一些让 Redis 充满多个 Lua 客户端的示例。
如果还没有完成,我建议你看一下Redis 基准页面 http://redis.io/topics/benchmarks first.
如果您在与 Redis 相同的机器上运行基准测试:
关键是要专门给Redis一个核心,而在其他核心上运行客户端程序。在Linux 上,您可以使用taskset 命令来执行此操作。
# Start Redis on core 0
taskset -c 0 redis-server redis.conf
# Start Lua programs on the other cores
for x in `seq 1 10` ; do taskset -c 1,2,3 luajit example.lua & done
Lua 程序应该使用管道来最大化吞吐量并减少系统活动。
local redis = require 'redis'
local client = redis.connect('127.0.0.1', 6379)
for i=1,1000000 do
local replies = client:pipeline(function(p)
for j=1,1000 do
local key = 'counter:'..tostring(j)
p:incrby(key,1)
end
end)
end
在我的系统上,Lua 程序占用的 CPU 是 Redis 的 4 倍以上,因此您需要 4 个以上的核心才能使用此方法使 Redis 饱和(6 核的盒子应该没问题)。
如果您在与 Redis 不同的机器上运行基准测试:
除非您在 CPU 匮乏的虚拟机上运行,否则瓶颈可能是在这种情况下的网络。我认为低于 1 GbE 的链路无法使 Redis 饱和。
确保尽可能地管道化您的查询(请参阅前面的 Lua 程序),以避免网络延迟瓶颈,并减少 CPU 上的网络中断成本(填充以太网数据包)。尝试在未绑定网卡(并处理网络中断)的核心上运行 Redis。您可以使用 htop 等工具来检查最后一点。
如果可以的话,尝试在网络中的其他各种机器上运行 Lua 客户端。同样,您将需要大量 Lua 客户端来使 Redis 饱和(6-10 应该没问题)。
在某些情况下,一个独特的 Lua 进程就足够了:
现在,如果每个查询都足够昂贵,则可以用单个 Lua 客户端使 Redis 饱和。这是一个例子:
local redis = require 'redis'
local client = redis.connect('127.0.0.1', 6379)
for i=1,1000 do
local replies = client:pipeline(function(p)
for j=1,1000 do
p:rpush("toto",i*1000+j)
end
end)
end
N = 500000
for i=1,100000 do
local replies = client:pipeline(function(p)
for j=1,10 do
p:lrange("toto",N, N+10)
end
end)
end
该程序用 1M 个项目填充列表,然后使用 lrange 命令从列表中间获取 10 个项目(Redis 的最坏情况)。因此,每次执行查询时,服务器都会扫描 500K 项。因为只返回 10 个项目,所以 lua-redis 解析速度很快,不会消耗 CPU。在这种情况下,所有的CPU消耗都将在服务器端。
最后的话
可能有比 redis-lua 更快的 Redis 客户端:
-
https://github.com/agladysh/lua-hiredis https://github.com/agladysh/lua-hiredis(基于hiredis)
-
https://github.com/agladysh/ljffi-hiredis https://github.com/agladysh/ljffi-hiredis(基于hiredis,使用luajit FFI)
您可能想尝试一下。