序章

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

lamp02lamp03でこれらの手順を正確に繰り返します。

ステップ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プール内のクラウドサーバーのみが相互に通信できるようにします。

誤ったルールが適用された場合に発生する可能性のある問題のトラブルシューティングを容易にするために、セッションの冗長性をテストした後にこの手順を実行しています。

lamp01lamp02および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アドレスlamp01lamp02を使用して同じことを行います。

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のテストを繰り返して、ファイアウォールがトラフィックをブロックしていないことを確認します。

追加の読み物