はじめに

自称Webアプリ屋のサカベです。
ちょっと日が開いてしまいましたが、Redisを使ってみるブログ第3弾です。

今回は実践編として、いよいよPHPからphpredisを使用してRedisを操作してみます。

今までの。

Redisをセットアップして使ってみた
Redisを使ってみるその2: PHPからRedisを扱えるようにする(準備編)

早速書いてみる

では早速PHPのコードを書いてみます。

<?php
$Redis = new Redis();
$Redis->connect('127.0.0.1', 6379);

$Redis->set('call', 'PanzerVor!');

var_dump($Redis->get('call')); // string(10) "PanzerVor!"

callというKeyに、PanzerVor!というValueをセットして表示する、という至極単純なプログラムです。
これだけではRedisを使う意味がまるでありませんが、そこは気にせずに。。

1行づつ見てみましょう。

$Redis = new Redis();

phpredisを使用するには、Redisクラスのインスタンスを作成するだけ。
特にrequireなどをする必要もなく、いきなりインスタンスを作成すれば使えちゃいます。楽ちん。
ただこれだけだとRedisを呼び出しただけになってしまうので、

$Redis->connect('127.0.0.1', 6379);

connect関数で接続までしてあげてください。
connect関数は、第1引数が Host 、第2引数が Port です。
特に何も設定をいじっていなければ、Hostは127.0.0.1、Portは6379になっているはずです。


Redisでは、RedisにKey-Valueペアを登録するためにsetというコマンドを使用します。
CLI上では、

127.0.0.1:6379>set call PanzerVor!

と書くことで、callというKeyに、PanzerVor!というValueをセットすることが出来ます。
そうすると、このように

127.0.0.1:6379>get call

getというコマンドでKeyを指定することで、そのValueが取得出来ます。
これをそっくりそのまま、PHPでも書くことが出来ます。

setコマンドは、

$Redis->set('call', 'PanzerVor!');

と書くことが出来ます。
第1引数がKey、第2引数がValueとなります。
そのまんまですね。

getコマンドも同様で、

$Redis->get('call')

と書けばValueが返り値になります。何も難しいことは無い。

もう少し応用

これだけではあまりにつまらないので、もう少し応用してみましょう。
先程までのはString型といって、Key-Valueが1対1になる非常にシンプルなパターンでした。
今度は、PHPの連想配列のように、複数のKey-Valueペアをセットにして、1つの名前を付けておけるHash型というものを使ってみます。

パターン1: とりあえずHashで入れてみる

コード

<?php
$Redis = new Redis();
$Redis->connect('127.0.0.1', 6379);

$ankouTeam = [
    'name' => 'Ankou Team',
    'member' => [
        'commander' => 'Miho Nishizumi',
        'operator' => 'Saori Takebe',
        'gunner' => 'Hana Isuzu',
        'charger' => 'Yukari Akiyama',
        'driver' => 'Mako Reizei'
    ],
    'tank' => 'MarkIV type-H'
];

$kamesanTeam = [
    'name' => 'Kame-san Team',
    'member' => [
        'commander' => 'Anzu Kadotani',
        'charger' => 'Momo Kawashima',
        'driver' => 'Yuzu Koyama'
    ],
    'tank' => 'Hetzer'
];

setRedis($Redis, $ankouTeam);
setRedis($Redis, $kamesanTeam);

displayHash($Redis, $ankouTeam['name']);
displayHash($Redis, $kamesanTeam['name']);

/**
 * RedisにHashをセットする
 * @param Redis $Redis Redisインスタンス
 * @param array $team チーム情報を持った配列
 * @return void
 */
function setRedis(Redis $Redis, $team) {
    $Redis->hSet($team['name'], 'name', $team['name']);
    $Redis->hSet($team['name'], 'member', json_encode($team['member'], JSON_UNESCAPED_UNICODE));
    $Redis->hSet($team['name'], 'tank', $team['tank']);
}

/**
 * RedisからHashを取得して表示する
 * @param Redis $Redis Redisインスタンス
 * @param string $teamName チーム名(HashKey)
 */
function displayHash(Redis $Redis, $teamName) {
    var_dump(sprintf('##### %s #####', $teamName)); // ただの仕切り
    var_dump($Redis->hGetAll($teamName));
}

※各種値チェックは入れていません。超手抜き。

Hash型でKey-Valueペアを登録するためには、hset(phpredisではhSet)を使用します。
取得する際には、2種類のコマンドがあります。

  • hget(phpredis: hGet): Keyの中からfield (※)を指定して取得 ※Keyの中に存在するKey-ValueペアのKey
  • hgetall(phpredis: hGetAll): Keyだけ指定して中身をごっそり取得する

今回はhgetallを使用しています。

実行結果

[vagrant@localhost ~]$ php -f phpredis.php
string(22) "##### Ankou Team #####"
array(3) {
  ["tank"]=>
  string(13) "MarkIV type-H"
  ["name"]=>
  string(10) "Ankou Team"
  ["member"]=>
  string(128) "{"commander":"Miho Nishizumi","operator":"Saori Takebe","gunner":"Hana Isuzu","charger":"Yukari Akiyama","driver":"Mako Reizei"}"
}
string(25) "##### Kame-san Team #####"
array(3) {
  ["tank"]=>
  string(6) "Hetzer"
  ["name"]=>
  string(13) "Kame-san Team"
  ["member"]=>
  string(79) "{"commander":"Anzu Kadotani","charger":"Momo Kawashima","driver":"Yuzu Koyama"}"
}

当然ですが、memberがJSONのままになっています。
とはいえ、JSONにしてしまえば 実態はただの文字列 なので、多次元配列だろうがなんだろうが余裕ですね。

Redisの中では

Redisの中ではこういう風に保存されます。

まずはKey一覧。

# Key一覧
127.0.0.1:6379> keys *
1) "Kame-san Team"
2) "Ankou Team"

「Ankou Team」というKeyの中身だけを取得してみます。

127.0.0.1:6379> hgetall "Ankou Team"
1) "tank"
2) "MarkIV type-H"
3) "name"
4) "Ankou Team"
5) "member"
6) "{\"commander\":\"Miho Nishizumi\",\"operator\":\"Saori Takebe\",\"gunner\":\"Hana Isuzu\",\"charger\":\"Yukari Akiyama\",\"driver\":\"Mako Reizei\"}"

6つのValueが並列で入っているようにしか見えないのですが、一応Key-Valueペアでちゃんと入っています。
試しに「member」というKey(=field)に対応するValueを取得しています。
hgetを使います。

127.0.0.1:6379> hget "Ankou Team" member
"{\"commander\":\"Miho Nishizumi\",\"operator\":\"Saori Takebe\",\"gunner\":\"Hana Isuzu\",\"charger\":\"Yukari Akiyama\",\"driver\":\"Mako Reizei\"}"

ちゃんとKey-Valueペアになっているようです。

パターン2: もう少しこだわる

さて、現状memberがJSONのままです。
実際扱う時はここから適宜加工すればいいんですが、 今回は連想配列で表示出来てないと 見栄え的に微妙 なので、JSONを連想配列に復元してから表示させてみます。
displayHash()を少し改良してみましょう。

コード

/**
 * RedisからHashを取得して表示する
 * @param Redis $Redis Redisインスタンス
 * @param string $teamName チーム名(HashKey)
 */
function displayHash(Redis $Redis, $teamName) {
    var_dump(sprintf('##### %s #####', $teamName)); // ただの仕切り
    $pairs = $Redis->hGetAll($teamName);
    foreach ($pairs as $field => &$value) {
        if ($field === 'member') $value = json_decode($value, true);
    }
    unset($value);
    var_dump($pairs);
}

※ここでも、各種値チェックは入れていません。
本当は$Redis->exists()とかでHashの存在確認をすべき。超手抜きその2。

実行結果

[vagrant@localhost ~]$ php -f phpredis.php
string(22) "##### Ankou Team #####"
array(3) {
  ["tank"]=>
  string(13) "MarkIV type-H"
  ["name"]=>
  string(10) "Ankou Team"
  ["member"]=>
  array(5) {
    ["commander"]=>
    string(14) "Miho Nishizumi"
    ["operator"]=>
    string(12) "Saori Takebe"
    ["gunner"]=>
    string(10) "Hana Isuzu"
    ["charger"]=>
    string(14) "Yukari Akiyama"
    ["driver"]=>
    string(11) "Mako Reizei"
  }
}
string(25) "##### Kame-san Team #####"
array(3) {
  ["tank"]=>
  string(6) "Hetzer"
  ["name"]=>
  string(13) "Kame-san Team"
  ["member"]=>
  array(3) {
    ["commander"]=>
    string(13) "Anzu Kadotani"
    ["charger"]=>
    string(14) "Momo Kawashima"
    ["driver"]=>
    string(11) "Yuzu Koyama"
  }
}

どうでしょう、綺麗に復元出来てませんかね。
◯◯Teamと名前の付いた連想配列の変数をvar_dump()したのと変わらないと思います。

結局何だったのさ

ここまでの内容を読んで、 「ふーん、 で?」 と思う人もいるかもしれません。
ここで、Redisの特性を思い出してみましょう。
Redisをセットアップして使ってみた にて、私はこう書いておりました。

MySQLなどのRDBMSと違い、ストレージ上ではなくメモリ上にデータを展開するため、読み取りが非常に速いのが特徴です。

つまり、用途によっては RDBMSの代わりとして活用出来る だけでなく、オンメモリでの読み書きなので スピードアップも期待出来る ということです。
多次元配列でも、JSONにして文字列として突っ込んでおけばPHPから扱う分には全く問題無いので、RDBMS的な使い方も十分可能かと思います。
Hash型だけでなくString型でも十分使えそうですね。

もちろん、

ただしメモリ上に展開するということは、何かの拍子に消える揮発性も併せ持ちます。

としたように、あくまでメモリ上のデータなので、 何かの拍子に消えます 。それはもう、あっさりと。(※)

※ストレージに書き込んで永続化することも可能です。
でもそれだったらRDBMSでよくね。。?と思っちゃうのは私だけでしょうか

Redisが役に立つケース

なので、下記のような用途では非常に有用であると言えます。

  • 頻繁にアクセスするデータ (何かとアクセスする必要があるデータ)
  • 消えても良いデータ (消えても別の場所から復元出来るデータ)

例としては、「 キャッシュ 」や、「 セレクトボックスの選択項目マスタ 」が挙げられるでしょう。
実際私は、後者の用途でRedisを導入しました。
何かの拍子に消えたら、その時はRDBMSと同期して再度Redisに格納するように組んでいます。

RDBMSを別サーバーに置いて、ネットワーク経由でアクセスをする、といったよくある構成では、RDBMSやネットワークの速度がボトルネックになるケースも存在します。
そうした時、適宜Redisを活用していくことで、大幅なスピードアップが期待出来るのではないでしょうか。
RDBMSへのI/O回数が減らせる、というだけでもだいぶ違うと思いますし。

もちろん あっさり消える 恐怖が存在するので、速いからと言って何でもかんでもRedisに入れるのはヤバいです。
RDBMSとのデータの整合性を保つのも、意外と面倒ですし。
ご利用は計画的に。

おわりに

3回に分けて、RedisをPHPから操作する、というテーマのもと連載記事を書いてみました。
Redisそのものの使い方についてはそんなに触れてこなかったのですが、今回の記事でRedisを使ってみたくなったら、使い方なんぞたくさんネットの海に転がっているので、ぜひ調べてみてください。

。。さて次回以降何を書きましょうか。

Shere
  • はてなブログ
  • Twitter
  • Facebook
Redisを使ってみるその3: PHPからRedisを操作してみる

Writer

  • Name

    サカベ ケンイチ

  • Position

    横浜と大洗を往復する自称Webアプリ屋。

  • Profile

    必要あればサーバー構築からバックエンド、ちょっぴりフロントまで担当するWebアプリ屋。 本業はPHPエンジニア。 アプリも手を出そうとC#+Xamarin勉強中。 そして必要あれば曲も作る。なお出番は無い模様。