我怀疑最大化 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 饱和。
下面是一些使用多个 Lua 客户端使 Redis 饱和的示例。
如果尚未完成,我建议您先查看Redis 基准页面。
如果您在与 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 客户端:
您可能想尝试一下。