たんたんめん日記

ソシャゲ関連のなんでもやさん備忘録

【php】【redis】phpredisのRedisArray

phpredisには、RedisArrayというものが実装されています。

複数のRedisインスタンスコンストラクタに与えると、分散してデータを保持してくれるというスグレモノです。

で、下記のようなスクリプトで、ちょっと動作を確認

<?php
define('DATA_COUNT', 10000 );

define('KEY_PREFIX', 't1:');
$host_array = array(
        '127.0.0.1:6379',
        '127.0.0.1:6380',
);

$start_time = microtime( true );
$RedisArray = new RedisArray($host_array);

for( $i = 0; $i < DATA_COUNT ; $i++ ){
        $ret = $RedisArray->set( KEY_PREFIX.$i, $i );
}
$end_time = microtime( true );

echo $i;
echo "\n";
echo ($end_time - $start_time);
echo "\n";

で、redis-cliで確認

redis 127.0.0.1:6379> dbsize
(integer) 4890

もう1つのインスタンス

redis 127.0.0.1:6380> dbsize
(integer) 5110

実行時間は 0.5751秒。

ぼちぼち2つのインスタンスに分かれてデータを保存しているようです。


サーバーを増やしても古いホスト群を教えてやれば、うまく対応してくれるとのこと。

で、上記のスクリプトを動かした後に、下記のスクリプトを動かします。 サーバーを追加した後、増加するデータはどのように保存されるのか確認します。

<?php
define('START_DATA_COUNT', 10000 );
define('END_DATA_COUNT', 20000 );

define('KEY_PREFIX', 't1:');
$new_host_array = array(
        '127.0.0.1:6379',
        '127.0.0.1:6380',
        '127.0.0.1:6381',
);

$previous_host_array = array(
        '127.0.0.1:6379',
        '127.0.0.1:6380',
);

$start_time = microtime( true );
$RedisArray = new RedisArray($new_host_array, array('previous' => $previous_host_array));

for( $i = START_DATA_COUNT; $i < END_DATA_COUNT ; $i++ ){
        $ret = $RedisArray->set( KEY_PREFIX.$i, $i );
}
$end_time = microtime( true );

echo $i;
echo "\n";
echo ($end_time - $start_time);
echo "\n";

dbsizeは

redis 127.0.0.1:6379> dbsize
(integer) 8230

そして、

redis 127.0.0.1:6380> dbsize
(integer) 8446

追加したインスタンス

redis 127.0.0.1:6381> dbsize
(integer) 3324

実行時間は、0.5686秒。2インスタンスの場合と、大差なしです。 データも新しいインスタンスにも分散しているようです。


じゃあ、もう1インスタンス増やしたらどうなるんでしょう?

<?php
define('START_DATA_COUNT', 20000 );
define('END_DATA_COUNT', 30000 );

define('KEY_PREFIX', 't1:');
$new_host_array = array(
        '127.0.0.1:6379',
        '127.0.0.1:6380',
        '127.0.0.1:6381',
        '127.0.0.1:6382',
);

$previous_host_array = array(
        '127.0.0.1:6379',
        '127.0.0.1:6380',
        '127.0.0.1:6381',
);

$start_time = microtime( true );
$RedisArray = new RedisArray($new_host_array, array('previous' => $previous_host_array));

for( $i = START_DATA_COUNT; $i < END_DATA_COUNT ; $i++ ){
        $ret = $RedisArray->set( KEY_PREFIX.$i, $i );
}
$end_time = microtime( true );

echo $i;
echo "\n";
echo ($end_time - $start_time);
echo "\n";

dbsizeは、

redis 127.0.0.1:6379> dbsize
(integer) 10730

dbsizeその2

redis 127.0.0.1:6380> dbsize
(integer) 10946

dbsizeその3

redis 127.0.0.1:6381> dbsize
(integer) 5824

新しいインスタンス

redis 127.0.0.1:6382> dbsize
(integer) 2500

で、処理時間は、0.5833秒。大差なし。


このままでは古いサーバーにデータが溜まっていくので、データを再分配しないとダメかもです。 そこで使用するのが、_rehashというメソッドです。

<?
$new_host_array = array(
        '127.0.0.1:6379',
        '127.0.0.1:6380',
        '127.0.0.1:6381',
        '127.0.0.1:6382',
);

$previous_host_array = array(
        '127.0.0.1:6379',
        '127.0.0.1:6380',
        '127.0.0.1:6381',
);

$start_time = microtime( true );
$RedisArray = new RedisArray($new_host_array, array('previous' => $previous_host_array));

$RedisArray->_rehash();

$end_time = microtime( true );

echo ($end_time - $start_time);
echo "\n";

処理時間は、6.652秒でした。 さすがに時間がかかります…

で、結果は

redis 127.0.0.1:6379> dbsize
(integer) 7446

redis 127.0.0.1:6380> dbsize
(integer) 7445

redis 127.0.0.1:6381> dbsize
(integer) 7555

redis 127.0.0.1:6382> dbsize
(integer) 7556

なるほど。データが再分配されています。


結果的に、増え続けるRedisデータについて、RedisArrayを利用してサーバー追加すれば対応可能な印象です。

ただ、どこかのタイミングで_rehashする必要があるかもしれません。

クラスタのような冗長性はReisArray単独では難しいかもですが、各インスタンスにSlaveサーバーを付けて、フェイルオーバー出来るようにすれば良いかもですね。

RedisArrayには他にもいくつか特徴があるので、RedisArrayをご確認下さい!