未分類

あなたのサイトは大丈夫?Redisの速度面の向上を考える

Redis 5.0.5 言語 PHP 5.5.18 phpredisモジュールを使用 CentOS 7.6.1810 VirtualBox 4.3.12

複数まとめて登録(mset)したほうがパフォーマンスが良いらしい

実際に検証してみる。 まずは、1件ずつのセットです。 「1件ずつのデータセットを1万回繰り返す」 という動作を100回繰り返しその平均タイムを出しています。

$times = 100;
for($count=1;$count<=$times;$count++){
    $time_start = microtime(true);
            $host = '127.0.0.1';
            $port = 6379;
            $r = new Redis();
            $r->connect($host, $port);
            for($i=1;$i<=10000;$i++){
            $r->set('key'.$i,'value'.$i);
            }
    $sum += microtime(true) - $time_start;
}
$ave = $sum / $times;
echo $ave;

今度は、複数のセットです。 ここでは、作成したKVを一度配列にまとめ、 それをまとめてRedisに登録しています。

$times = 100;
for($count=1;$count<=$times;$count++){
    $time_start = microtime(true);
            $host = '127.0.0.1';
            $port = 6379;
            $r = new Redis();
            $r->connect($host, $port);
            $regist = '';
            for($i=1;$i<=10000;$i++){
                $regist['key'.$i] = 'value'.$i;
            }
            $r->mSet($regist);
        $sum += microtime(true) - $time_start;
    }
    $ave = $sum / $times;
    echo $ave;

計測結果は、 1つずつセット 0.39885906934738(秒) 複数同時にセット 0.029414405822754(秒) 結果は、明らかですね笑 複数同時セットの方が10倍以上速いです。 Redisのパフォーマンスを生かすには、msetを利用する方が断然良いようです。 しかし、msetを使用するには問題があります。 それは、有効期限です。 Redisに登録するデータはあくまで一時的なもの。 基本的には、有効期限を設定する必要があるからです。 もし、1つずつ値をセットするのなら、有効期限を決めてセットするsetexコマンドというものがあります。 しかし、有効期限を決めて、複数のデータを登録するコマンド(msetex)はありません。 そのため、有効期限を決めてセットする場合には、 ・setexで1つずつデータを登録するか ・msetでまとめて登録した後、expireで有効期限を設定するか という方法があります。 しかし、これでは速度はあまり変わりそうにありません。 念のため、どちらでの登録が高速か、先ほどと同じ方法で計測してみます。 有効期限付きで、一つずつ登録する。

$times = 100;
for($count=1;$count<=$times;$count++){
    $time_start = microtime(true);
            $host = '127.0.0.1';
            $port = 6379;
            $r = new Redis();
            $r->connect($host, $port);
            for($i=1;$i<=10000;$i++){
             $r->setex('key'.$i,10,'value'.$i);
            }
    $sum += microtime(true) - $time_start;
}
$ave = $sum / $times;
echo $ave;

まとめて登録した後、一つずつ有効期限を設定する

$times = 100;
for($count=1;$count<=$times;$count++){
    $time_start = microtime(true);
            $host = '127.0.0.1';
            $port = 6379;
            $r = new Redis();
            $r->connect($host, $port);
            $regist = '';
            for($i=1;$i<=10000;$i++){
                $regist['key'.$i] = 'value'.$i;
            }
            $r->mSet($regist);
            for($i=1;$i<=10000;$i++){
                $r->expire('key'.$i, 10);
            }
        $sum += microtime(true) - $time_start;
    }
    $ave = $sum / $times;
    echo $ave;

計測結果は、 有効期限付きで、一つずつ登録する 0.41783607721329(秒 まとめて登録した後、一つずつ有効期限を設定する 0.43793610334396(秒) という結果でした。 ほとんど変わらないですが、有効期限付きで一つずる登録したほうがわずかに速いようです。 うーん、これじゃあ、せっかくのパフォーマンスが生かせない。

結論

まとめてセットしたほうが速度は断然早いけれど、その速度を保ったまま有効期限を設定する方法が存在しない。

改善案

1 . hSetを使用し、複数データを一つにまとめ、それら全てを同じ有効期限で管理する。 2 . lua scriptを使用し、高速に処理できるmsetexコマンドを実装する。 1の方は、やってみましたが、データの扱いが難しく、多次元配列を使用していたこともあり、 後からデータを追加する場合には、サブキーで値を上書きしないように、 valueのみをJSONでエンコードし、登録するという動作をしていたために、 そのために使用していたforeachの処理で、結果として処理速度が落ちてしまったため、断念しました。 そもそも、複雑なデータをRedisに登録しようっていう考えが間違っているとは思うのだけど。 今度時間があるときに、2のパターンも試してみようと思います。