如何提高Redis服务器的CPU使用率?

时间:2013-04-25 08:13:00

标签: lua redis benchmarking

我的目标是让我们的Redis服务器在生产中达到大约80%的CPU利用率。这将有利于我们的后端服务器设计,确保我们不会充分利用CPU,同时为增长和峰值留下一些空间。

使用Redis自己的基准测试工具redis-benchmark时,很容易达到100%的CPU使用率:

    $ redis-benchmark -h 192.168.1.6 -n 1000000 -c 50

在此基准测试中,我们分配了50个客户端,以便向我们的Redis服务器推送1,000,000个请求。

但在使用其他一些客户端工具(例如redis-luawebdis)时,最大CPU使用率低于60%。

我浏览了webdisredis-lua中的一些代码。 webdis取决于hiredisredis-lua在Lua中实现,并依赖于套接字(lua-socket)。

与Redis基准测试相比,这些客户端是否太慢,无法最大化Redis CPU消耗?

我还浏览了redis-benchmark.c中的一些代码。基准测试的主要工作在aeMain完成。似乎redis-benchmark使用Redis的快速代码,而我的测试客户端(webdisredis-lua)则没有。

目前我的客户有两种选择:

  1. 使用redis-lua
  2. 使用webdis
  3. 等工具

    然而,这两个并没有最大化Redis的CPU利用率(低于60%)。还有其他选择吗?

    或者,是否可以在redis-benchmark工具本身之外充分利用redis-server?

1 个答案:

答案 0 :(得分:7)

我怀疑最大化Redis的CPU使用率将有利于您的后端设计。正确的问题是Redis是否足够有效以在给定的延迟时间内维持吞吐量。 Redis是一个单线程服务器:在80%的CPU消耗下,延迟可能非常糟糕。

我建议您测量延迟,而redis-benchmark在尝试增加Redis CPU消耗之前,看看它是否可以满足您的需求。 redis-cli的--latency选项可用于此:

  • 启动redis-server
  • 尝试redis-cli --latency,注意平均值,停止它
  • 在另一个窗口中,启动基准测试,并确保它运行一段时间
  • 尝试redis-cli --latency,注意平均值,停止它
  • 停止基准
  • 比较两个平均值

现在,如果你真的想增加Redis CPU消耗,你需要一个高效的客户端程序(比如redis-benchmark),能够同时处理多个连接,或者你的客户端程序的多个实例。

Lua是一种快速解释的语言,但它仍然是一种解释语言。它比C代码慢一到两个数量级。 Redis在解析/生成协议方面要比lua-redis快得多,因此您将无法使用独特的Lua客户端使Redis饱和(除非您使用O(n)Redis命令 - 请参阅后面的内容。)

webdis在C中实现,具有高效的客户端库,但必须解析比Redis协议更加冗长和复杂的http / json协议。对于大多数操作,它可能比Redis本身消耗更多的CPU。再说一遍,你不会用一个webdis实例来使Redis饱和。

以下是使用多个Lua客户端使Redis饱和的一些示例。

如果尚未完成,我建议您首先查看the Redis benchmark page

如果您在与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程序占Redis CPU的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客户端可能比redis-lua更快:

您可能想尝试一下。