Help us understand the problem. What is going on with this article?

laravel4+redis pub/sub

More than 5 years have passed since last update.

今回は、laravel4とredisの機能であるpub/subを組み合わせた実装方法を紹介します。

laravel4というか、どちらかというとredis寄りのものですが・・。

php(Laravel)でのsubscribe受信方法は別で紹介しています。そちらも合わせてご覧下さい
Laravel webscoket(push & pubsub) 後編

pub/sub

redisはmemcache以上の働きをするので、
session, cache以外にnosqlとして重宝してる方も多いのではないでしょうか?
自分も個人の開発で多用したり、会社でも好んで使ったりしています。

websocketと言えばデータストアはredis!といっても良いくらいなんですが、
それにはレスポンスが早いなどももちろんですが、
複数台のwebsocketサーバからmysqlなどのデータベースにつないだ場合、
サーバ01がinsertした後に取得はできますが、
サーバ02はinsertされた事を知る術がありません。
実際にはinsertしたよ!という情報を01から02へサーバ間でsocketでつないで、
通知して云々という方法でしょうか?

厄介!

そこで、redisのpub/subという機能を使用します。
この機能は何かと言いますと、publisherとsubscriberの関係をredisで管理でき、
早い話、redisに接続してる他のものに対して通知ができます。
いちいち情報を取得しにいかなくても送ってくれるというありがたい機能です。

そんな機能をlaravel4で使ってみます。
といっても実装自体はものすごく簡単です。

まず必要なものをインストールします。

といってもlaravel4でも使っているpredisのasyncというものを使います。

hiredis

hiredes
Cのredisクライアントで、predis-asyncがラッパーしてるそうな

git clone git://github.com/redis/hiredis.git
cd hiredis
make && make install

predis-async

predis-async
composerでいつも通りです。

では、実装!

app/commands/RedisAsyncCommand.php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;

class RedisAsyncCommand extends Command {

    /**
     * @var string
     */
    protected $name = 'redis:async';

    /**
     * @var string
     */
    protected $description = "redis async start";

    /**
     * @return void
     */
    public function fire()
    {
        // 接続先
        $client = new Predis\Async\Client('tcp://127.0.0.1:6379');


        $client->connect(function ($client) {
            echo "redis async start!\n";

            $logger = new Predis\Async\Client('tcp://127.0.0.1:6379', $client->getEventLoop());
            // subscriber チャンネルに登録します
            $client->pubsub('subscriber', function ($event) use ($logger) {
                // 受信したメッセージをlistにpush
                $logger->rpush("{$event->channel}", $event->payload, function () use ($event) {
                    echo "Stored message `{$event->payload}` from {$event->channel}.\n";
                });
            });
        });
        $this->info('connected!');
        $client->getEventLoop()->run();
    }
}

実際にはasync用にfacadeを作って実装した方が綺麗でしょう!
facadeの作り方
predis-asyncのサンプルまんまですね!
redisの subscriberというチャンネルに登録させます(チャンネル名は適当にどうぞ)
受信したデータはredisに保存される訳ではないので、
とりあえずlistに突っ込んでます。

artisanに登録を忘れずに

app/start/artisan.php
Artisan::add(new RedisAsyncCommand);

artisanで待機状態にさせます

artisanコマンド
php artisan redis:async
connected!
redis async start!

これで待機状態になりました。
では試しにredisからsubscriberチャンネルに大して通知してみます。

redis-cli
> publish subscriber 'Hello!'
(integer) 1

成功したようです。
起動させた待機状態のphpは・・・

Stored message `Hello!` from subscriber.

しっかりと通知を受信する事ができました。
これを元にwebsocketを使用したアプリケーションを作っていけば面白いものができると思います。
pushの実装方法も紹介しましたので、
両方組み合わせて開発をするとモテるかもしれません

新しい技術にも難なく対応できるlaravel4のポテンシャルの高さは凄まじい!(fuelでも同じ事できますが)

明日は@kurikazu さんの簡単デプロイの話 です

ytake
著: Laravelリファレンス(インプレス) Laravelエキスパート養成読本(技術評論社) PHPフレームワーク Laravel Webアプリケーション開発 バージョン 5.5 LTS対応(ソシム)
https://blog.ytake.jp.net/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away