Ubuntu14.04の複数のMemcachedサーバーでPHPセッションを共有する方法
序章
Memcachedは、アクセスを高速化するために情報をディスクではなくメモリに保存する分散オブジェクトキャッシングシステムです。 PHPのMemcacheモジュールを使用して、ファイルシステムに保存されるセッションを処理できます。 PHPセッションをMemcachedに保存すると、セッションの冗長性を維持するために、Memcachedを実行している複数のクラウドサーバーにPHPセッションを分散できるという利点があります。
このMemcachedセットアップがないと、アプリケーションが複数のサーバーで負荷分散されている場合、ロードバランサーでセッションスティッキを構成する必要があります。 これにより、ユーザーエクスペリエンスが維持され、突然ログオフされるのを防ぎます。 セッションを処理するようにMemcachedを構成すると、Memcachedプール内のすべてのクラウドサーバーが同じセッションデータのセットを持つようになり、セッションを維持するために1台のサーバーに固執する必要がなくなります。
前提条件
このチュートリアルは、UbuntuでのLAMPサーバーのセットアップに精通していることを前提としています。 このセットアップでは、 Ubuntu14.04イメージの3つのドロップレットを使用します。
ドロップレット1
- 名前:lamp01
- パブリックIP:1.1.1.1
- プライベートIP:10.1.1.1
ドロップレット2
- 名前:lamp02
- パブリックIP:2.2.2.2
- プライベートIP:10.2.2.2
ドロップレット3
- 名前:lamp03
- パブリックIP:3.3.3.3
- プライベートIP:10.3.3.3
ドロップレットを作成するときは、プライベートネットワークチェックボックスがオンになっていることを確認してください。 また、後で必要になるため、プライベートIPアドレスをメモしておきます。
3台のサーバーすべてにLAMPをインストールします。
まず、リポジトリを更新してApacheをインストールします。
apt-get update
apt-get install apache2
PHPとApacheのmod_php拡張機能をインストールします。
apt-get install php5 libapache2-mod-php5 php5-mcrypt
詳細については、この記事を参照してください。
ステップ1-Memcacheパッケージをインストールする
lamp01 に、MemcachedデーモンとPHPのMemcacheモジュールをインストールします。
apt-get install php5-memcache memcached
PHPには、php5-memcacheとphp5-memcachedの2つのパッケージがあります(最後の「d」に注意してください)。 最初のパッケージ(memcache)は、依存関係がなく軽量であるため、使用します。 memcacheとmemcachedの比較をお読みください。
Memcachedサービスは、ローカルホスト(127.0.0.1)でのみリッスンします。 プライベートネットワークからの接続を受け入れるには、これを変更する必要があります。
nano /etc/memcached.conf
次の行を見つけます。
-l 127.0.0.1
このサーバーのプライベートIPアドレスでリッスンするように変更します。
-l 10.1.1.1
memcached
サービスを再起動します。
service memcached restart
127.0.0.1
を適切なプライベートIPアドレスに置き換えて、他の2つのサーバーでこれらの手順を繰り返します。
ランプ02
-l 10.2.2.2
ランプ03
-l 10.3.3.3
次の2台のサーバーでmemcached
サービスを再起動します。
ステップ2-MemcacheをPHPのセッションハンドラーとして設定する
lamp01 で、php.ini
ファイルを開いて編集します。
nano /etc/php5/apache2/php.ini
このファイルは、PHP-FPMインストールの/etc/php5/fpm/php.ini
にあります。
次の構成ディレクティブを見つけます。
session.save_handler =
session.save_path =
次のようにMemcacheを使用するように変更します。 session.save_path
で3つすべてのプライベートIPアドレスを使用します。
session.save_handler = memcache
session.save_path = 'tcp://10.1.1.1:11211,tcp://10.2.2.2:11211,tcp://10.3.3.3:11211'
最初のセミコロンを削除して、session.save_path
のコメントを解除する必要がある場合があります。 Memcachedはこのポートでリッスンするため、各IPアドレスの後にポート番号11211を入力することを忘れないでください。
他の2つのサーバーにまったく同じ設定を追加します。
lamp02 の場合:
session.save_handler = memcache
session.save_path = 'tcp://10.1.1.1:11211,tcp://10.2.2.2:11211,tcp://10.3.3.3:11211'
lamp03 の場合:
session.save_handler = memcache
session.save_path = 'tcp://10.1.1.1:11211,tcp://10.2.2.2:11211,tcp://10.3.3.3:11211'
この構成は、セッション共有が正しく機能するために、すべてのドロップレットで完全に同じである必要があります。
ステップ3-セッション冗長性のためにMemcacheを構成する
lamp01 で、memcache.ini
ファイルを編集します。
nano /etc/php5/mods-available/memcache.ini
このファイルの最後に次の構成ディレクティブを追加します。
memcache.allow_failover=1
memcache.session_redundancy=4
memcache.session_redundancy
ディレクティブは、セッション情報をすべてのサーバーにレプリケートするために、memcachedサーバーの数+1に等しくなければなりません。 これは、PHPのバグが原因です。
これらのディレクティブはセッションのフェイルオーバーと冗長性を有効にするため、PHPはsession.save_path
で指定されたすべてのサーバーにセッション情報を書き込みます。 RAID-1セットアップに似ています。
使用しているものに応じて、WebサーバーまたはPHPFPMデーモンを再起動します。
service apache2 reload
lamp02とlamp03でこれらの手順を正確に繰り返します。
ステップ4-テストセッションの冗長性
この設定をテストするには、すべてのドロップレットで次のPHPスクリプトを作成します。
/var/www/html/session.php
<?php
header('Content-Type: text/plain');
session_start();
if(!isset($_SESSION['visit']))
{
echo "This is the first time you're visiting this server\n";
$_SESSION['visit'] = 0;
}
else
echo "Your number of visits: ".$_SESSION['visit'] . "\n";
$_SESSION['visit']++;
echo "Server IP: ".$_SERVER['SERVER_ADDR'] . "\n";
echo "Client IP: ".$_SERVER['REMOTE_ADDR'] . "\n";
print_r($_COOKIE);
?>
このスクリプトはテスト専用であり、ドロップレットが設定されると削除できます。
curlを使用して最初のドロップレットでこのファイルにアクセスし、Cookie情報を抽出します。
curl -v -s http://1.1.1.1/session.php 2>&1 | grep 'Set-Cookie:'
これにより、次のような出力が返されます。
< Set-Cookie: PHPSESSID=8lebte2dnqegtp1q3v9pau08k4; path=/
PHPSESSID
Cookieをコピーし、このCookieを使用して他のドロップレットにリクエストを送信します。 このセッションは、1440秒間リクエストが行われない場合、PHPによって削除されるため、この時間枠内にテストを完了するようにしてください。 これについて詳しくは、PHPのsession.gc-maxlifetimeをご覧ください。
curl --cookie "PHPSESSID=8lebte2dnqegtp1q3v9pau08k4" http://1.1.1.1/session.php http://2.2.2.2/session.php http://3.3.3.3/session.php
セッションがすべてのドロップレットに引き継がれていることがわかります。
Your number of visits: 1
Server IP: 1.1.1.1
Client IP: 117.193.121.130
Array
(
[PHPSESSID] => 8lebte2dnqegtp1q3v9pau08k4
)
Your number of visits: 2
Server IP: 2.2.2.2
Client IP: 117.193.121.130
Array
(
[PHPSESSID] => 8lebte2dnqegtp1q3v9pau08k4
)
Your number of visits: 3
Server IP: 3.3.3.3
Client IP: 117.193.121.130
Array
(
[PHPSESSID] => 8lebte2dnqegtp1q3v9pau08k4
)
フェイルオーバーをテストするには、memcached
サービスを停止し、そのサービスでこのファイルにアクセスします。
service memcached stop
ドロップレットは、他の2つのサーバーに保存されているセッション情報を透過的に使用します。
curl --cookie "PHPSESSID=8lebte2dnqegtp1q3v9pau08k4" http://1.1.1.1/session.php
出力:
Your number of visits: 4
Server IP: 1.1.1.1
Client IP: 117.193.121.130
Array
(
[PHPSESSID] => 8lebte2dnqegtp1q3v9pau08k4
)
これで、セッションスティッキネスを構成する手間をかけずに、リクエストを均等に分散するようにロードバランサーを構成できます。
テストが終了したら、memcached
を再度開始します。
service memcached start
ステップ5-IPTablesでMemcachedを保護する
Memcachedがプライベートネットワークを使用している場合でも、同じデータセンター内の他のDigitalOceanユーザーは、プライベートIPを知っていれば、ドロップレットに接続できます。 そのため、 IPTablesルールを設定して、Memcachedプール内のクラウドサーバーのみが相互に通信できるようにします。
誤ったルールが適用された場合に発生する可能性のある問題のトラブルシューティングを容易にするために、セッションの冗長性をテストした後にこの手順を実行しています。
lamp01にlamp02およびlamp03のプライベートIPアドレスを使用してファイアウォールルールを作成します。
iptables -A INPUT -s 10.2.2.2 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT
iptables -A INPUT -s 10.3.3.3 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT
一般的なLAMPサーバーでは、次のルールの完全なセットになります。
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
iptables -A INPUT -s 10.2.2.2 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT
iptables -A INPUT -s 10.3.3.3 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
iptables -P INPUT DROP
lamp02にファイアウォールルールをlamp01およびlamp03のプライベートIPアドレスで入力します。
iptables -A INPUT -s 10.1.1.1 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT
iptables -A INPUT -s 10.3.3.3 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT
lamp03でプライベートIPアドレスlamp01とlamp02を使用して同じことを行います。
iptables -A INPUT -s 10.1.1.1 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT
iptables -A INPUT -s 10.2.2.2 -i eth1 -p tcp -m state --state NEW -m tcp --dport 11211 -j ACCEPT
ステップ4のテストを繰り返して、ファイアウォールがトラフィックをブロックしていないことを確認します。