RedisのCPU使用率を最大化することが、バックエンドの設計に役立つとは思えません。正しい質問は、Redisが特定のレイテンシでスループットを維持するのに十分効率的かどうかということです。 Redisはシングルスレッドサーバーです。CPU消費率が80%の場合、レイテンシは非常に悪くなる可能性があります。
Redis-benchmarkが機能している間にレイテンシーを測定して、RedisのCPU消費量を増やす前に、ニーズに適しているかどうかを確認することをお勧めします。これには、redis-cliの--latencyオプションを使用できます:
- redis-serverを起動
- redis-cli --latencyを試して、平均値をメモし、停止します
- 別のウィンドウでベンチマークを開始し、しばらくの間実行されることを確認します
- redis-cli --latencyを試して、平均値をメモし、停止します
- ベンチマークを停止する
- 2つの平均値を比較します
ここで、RedisのCPU消費量を本当に増やしたい場合は、複数の接続を同時に処理できる効率的なクライアントプログラム(redis-benchmarkなど)、またはクライアントプログラムの複数のインスタンスが必要です。
Luaは高速インタプリタ言語ですが、それでもインタプリタ言語です。 Cコードよりも1桁または2桁遅くなります。 Redisは、lua-redisよりもプロトコルの解析/生成がはるかに高速であるため、一意のLuaクライアントでRedisを飽和させることはできません(O(n)Redisコマンドを使用する場合を除く-後述)。
webdisは効率的なクライアントライブラリを使用してCで実装されていますが、Redisプロトコルよりも冗長で複雑なhttp/jsonプロトコルを解析する必要があります。ほとんどの操作で、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プログラムはRedisのCPUの4倍以上を使用するため、この方法でRedisを飽和させるには4コア以上が必要です(6コアボックスで十分です)。
Redisとは別のボックスでベンチマークを実行する場合:
CPUが不足している仮想マシンで実行している場合を除いて、その場合のボトルネックはネットワークである可能性があります。 1GbEリンク未満でRedisを飽和させることはできないと思います。
ネットワーク遅延のボトルネックを回避し、CPUでのネットワーク割り込み(イーサネットパケットの充填)のコストを削減するために、クエリを可能な限りパイプライン化してください(前のLuaプログラムを参照)。ネットワークカードにバインドされていない(そしてネットワーク割り込みを処理する)コアでRedisを実行してみてください。 htopなどのツールを使用して、この最後のポイントを確認できます。
可能であれば、ネットワークの他のさまざまなマシンでLuaクライアントを実行してみてください。ここでも、Redisを飽和させるためにかなりの数のLuaクライアントが必要になります(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
このプログラムは、リストに100万個のアイテムを入力し、lrangeコマンドを使用してリストの中央から10個のアイテムをフェッチします(Redisの場合は最悪の場合)。したがって、クエリが実行されるたびに、500Kのアイテムがサーバーによってスキャンされます。返されるアイテムは10個だけなので、CPUを消費しないlua-redisによる解析が高速です。この状況では、すべてのCPU消費はサーバー側で発生します。
最後の言葉
おそらくredis-luaよりも高速なRedisクライアントがあります:
- https://github.com/agladysh/lua-hiredis(hiredisに基づく)
- https://github.com/agladysh/ljffi-hiredis(hiredisに基づき、luajit FFIを使用)
試してみてください。