Lua 如何改进Redis服务器';什么是CPU使用率?
我的目标是让我们的Redis服务器在生产中达到大约80%的CPU利用率。这将有利于我们的后端服务器设计,确保我们不会利用CPU不足,同时也为增长和峰值留出一些空间 在使用Redis自己的基准测试工具时,很容易达到100%的CPU使用率:Lua 如何改进Redis服务器';什么是CPU使用率?,lua,redis,benchmarking,Lua,Redis,Benchmarking,我的目标是让我们的Redis服务器在生产中达到大约80%的CPU利用率。这将有利于我们的后端服务器设计,确保我们不会利用CPU不足,同时也为增长和峰值留出一些空间 在使用Redis自己的基准测试工具时,很容易达到100%的CPU使用率: $ redis-benchmark -h 192.168.1.6 -n 1000000 -c 50 在这个基准测试中,我们分配了50个客户端将1000000个请求推送到我们的Redis服务器 但是,在使用其他一些客户端工具(如或)时,最大CPU使用率低
$ redis-benchmark -h 192.168.1.6 -n 1000000 -c 50
在这个基准测试中,我们分配了50个客户端将1000000个请求推送到我们的Redis服务器
但是,在使用其他一些客户端工具(如或)时,最大CPU使用率低于60%
我在webdis
和redislua
中浏览了一些代码webdis
依赖于hiredis
,redis-lua
在lua中实现,并依赖于socket(lua-socket
)
与Redis基准相比,这些客户端是否太慢,无法最大限度地提高Redis的CPU消耗
我还在redis benchmark.c
中浏览了一些代码。基准测试的主要工作在aeMain
中完成。似乎redis基准测试使用了来自redis的快速代码,而我的测试客户机(webdis
和redis lua
)则没有
目前,我的客户有两种选择:
使用redis lua
使用类似于webdis的工具
然而,这两种方法并不能最大限度地提高Redis的CPU利用率(低于60%)。还有其他选择吗
或者,是否有可能在redis benchmark
工具本身之外充分利用redis服务器?我怀疑最大限度地提高redis的CPU使用率将有助于您的后端设计。正确的问题是Redis是否有足够的效率来维持给定延迟下的吞吐量。Redis是一个单线程服务器:在80%的CPU消耗下,延迟可能会非常糟糕
我建议您在redis benchmark工作时测量延迟,看看它是否适合您的需要,然后再尝试增加redis的CPU消耗。redis cli的--latency选项可用于:
- 启动redis服务器
- 尝试redis cli--latency,注意平均值,然后停止
- 在另一个窗口中,启动基准测试,并确保它运行一段时间
- 尝试redis cli--latency,注意平均值,然后停止
- 停止基准测试
- 比较两个平均值
现在,如果你真的想增加Redis的CPU消耗,你需要一个高效的客户端程序(比如Redis benchmark),能够同时处理多个连接,或者是客户端程序的多个实例
Lua是一种快速解释语言,但它仍然是一种解释语言。它将比C代码慢一到两个数量级。Redis在解析/生成其协议方面比lua Redis快得多,因此您将无法使用唯一的lua客户端使Redis饱和(除非您使用O(n)Redis命令-请参阅下文)
webdis是用C语言实现的,有一个高效的客户端库,但必须解析http/json协议,而http/json协议恰好比Redis协议更详细、更复杂。对于大多数操作,它可能比Redis本身消耗更多的CPU。因此,您也不会让一个webdis实例使Redis饱和
下面是一些使用多个Lua客户端使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不足的虚拟机上,否则在这种情况下,瓶颈可能是网络。我认为你不能用低于1Gbe的链路让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个项目,所以LuaRedis可以快速解析它们,而不会占用CPU。在这种情况下,所有的CPU消耗都在服务器端
最后一句话
可能有比Redis lua更快的Redis客户端:
- (基于hiredis)
- (基于hiredis,使用luajit FFI)
你可能想试试