読者です 読者をやめる 読者になる 読者になる

【Elasticache】ELB配下の複数インスタンス間でのセッション管理【Laravel】

Laravel AWS KVS

AWS の ELB に複数のインスタンスをぶら下げて負荷分散をしようと思った際に、Laravel アプリのセッション管理について考えたメモです。

ユーザにログインさせる必要があるアプリなどは、ELB によって接続先インスタンスを振り分けられたとしても、そのセッションを維持することが必要になってきます。
単に ELB にインスタンスを沢山ぶら下げるだけだと、デフォルトでは1クライアントからの各リクエストが別々のインスタンスに割り振られてしまいます。
つまり、インスタンス間でセッションを共有できていないので「さっきログインしたはずなのにまたログインしろ画面が出てきたんだけど」ということになってしまいます。

この記事では、この問題を解決する方法の紹介と、そのうちの一つを Laravel で設定してみます。

解決策

先に書いた問題を解決するための方法をいくつか簡単に紹介します。

スティッキーセッションを使う

ELB には、クライアントとリクエスト先のインスタンスを固定するスティッキーセッションという機能が備わっています。
この機能を使用した場合、一度クライアントがインスタンスに接続すると有効期限が切れるまで同じインスタンスに接続され続けます。
これによって、インスタンス間でセッション情報を共有する必要もなく問題を解決できます。
ただ、接続先のインスタンスがダウンした場合などは、やむを得ず他のインスタンスに接続する必要があります。
この場合、新しく接続されたインスタンスは新しく接続してきたクライアントのセッション情報を保持していないことに注意が必要です。
f:id:norikone:20160208023613p:plain:h300

セッション情報をDBで管理する

セッションをDBで管理することによってWebサーバ間で情報を共有できるので、スティッキーセッションを使用した際に注意しなければならない問題は発生しません。
しかし、DBで管理する際にはセッション情報の更新や削除処理が頻繁に行われるようになり、パフォーマンスの低下に繋がる可能性があります。
f:id:norikone:20160208023611p:plain:h300

セッション情報をKVSで管理する

memcached や Redis などの KVS を使用することで、DB で管理した場合に必要となるセッション破棄のための削除処理の実装が要らなくなります。
また、DB を使用する際に発生するディスクI/Oによる影響を減らすことにも期待ができます。
セッション情報は多くの場合で永続化する必要のないデータなので、揮発性が高くてもそこまで問題になりません。

f:id:norikone:20160208023612p:plain:h300

ということで、単純なセッション管理には KVS が向いていると判断したので、Laravel から KVS を使用してセッション管理をする設定をしてみます。

Laravel で Elasticache を使ってセッション管理をしてみる

セッション管理の KVS にElasticache 上の Redis を使います。
ここでは memcached か Redis かの検討については書きません。

まずは、Elasticache で Redis クラスタを作成します。
作成されると、エンドポイントを確認することができるので、それを控えておきます。

次に、Laravel 側の設定です。
config/session.php で、セッションドライバに Redis を使用するよう指定します。

'driver' => 'redis',

config/database.php に、接続するクラスタの情報を記述します。

'redis' => [
        'cluster' => false,
        'default' => [
            'host'     => 'hoge-cluster.XXXX.XXXX.XXXX.cache.amazonaws.com',
            'port'     => 6379,
            'database' => 0,
        ],
],

host には先程控えたエンドポイントを指定します。

設定はこれだけです。
実際にセッションが Redis に格納されるようになっているか確認していきます。
あらかじめ Laravel アプリにアクセスしてセッションを作成しておきましょう。

  • 接続用クライアントツールインストール
sudo wget http://download.redis.io/redis-stable.tar.gz
sudo tar xvzf redis-stable.tar.gz
cd redis-stable
sudo make
  • 接続
src/redis-cli -h hoge-cluster.XXXX.XXXX.XXXX.cache.amazonaws.com' -p 6379
  • 既存のキーを確認
keys *

ここで、"laravel:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" のように表示されていればセッションが格納できています。

  • 切断
quit

おわり

Elasticache(Redis) を使用してセッション管理をしてみました。
今のままだと、Redis が単一障害点となってしまっているのでよろしくありませんが、Elasticache の設定でレプリケーションをすることでこれを回避できます。
memcahced の場合はレプリケーションは行えません。
Redis とは冗長化の方式が異なるので、興味のある方はそちらも調べてみるといいかもしれません。