こんにちは、UOZUです!
先にエンハンスドロードバランサのセッション維持機能について記事を書きましたが、今回はセッション維持機能の無いロードバランサのPHPセッションをmemcachedで共通化してみようと思います。
PHPセッションの管理サンプル
PHPセッションでは、ブラウザ側のCookieにセッションIDを持たせ、サーバー側に保存されたセッション情報と照合することで、同じ利用者の状態を管理します。
デフォルトではセッション情報は各サーバーのローカルディスクに保存されるため、ロードバランサ配下で接続先サーバーが切り替わると、セッション情報を正しく参照できない場合があります。
サンプルコードを作って試してみます。
[root@uozu-lb1 ~]# vi /var/www/html/session.php
<?php
session_name("php_uozu");
session_start();
if (isset($_SESSION['count'])) {
$_SESSION['count']++;
} else {
$_SESSION['count'] = 1;
}
?>
<?php echo gethostname(),"\n", $_SESSION['count'], "\n" ; ?>「php_uozu」でセッション情報を管理し、すでにブラウザにセッションCookieがある場合、ホスト名の下の数字が増える単純なスクリプトです。
[root@uozu-lb1 ~]# curl http://localhost/session.php
uozu-lb1
1
[root@uozu-lb1 ~]# curl http://localhost/session.php
uozu-lb1
1[root@uozu-lb1 ~]# curl -c cookie.txt -b cookie.txt http://localhost/session.php
uozu-lb1
1
[root@uozu-lb1 ~]# curl -c cookie.txt -b cookie.txt http://localhost/session.php
uozu-lb1
2また、ブラウザ上のCookieの情報と、サーバ内のセッション情報は同じ名前で保存され、アクセスの際に突合されるという仕組みになっています。
[root@uozu-lb1 ~]# cat cookie.txt
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
localhost FALSE / FALSE 0 php_uozu ar8ejnsnknl66vikfbtv66lhee[root@uozu-lb1 ~]# ll -t /var/lib/php/session/
total 12
-rw------- 1 apache apache 10 Aug 9 21:27 sess_ar8ejnsnknl66vikfbtv66lhee
-rw------- 1 apache apache 10 Aug 9 21:27 sess_mo3peefa8jf2unhh14o6poa1mk
-rw------- 1 apache apache 10 Aug 9 21:27 sess_ge4mfdmdcc6lso1eiogap0lfq1
[root@uozu-lb1 ~]# cat /var/lib/php/session/sess_ar8ejnsnknl66vikfbtv66lhee
count|i:2;ロードバランサ利用の際の問題
ロードバランサを利用した際、ロードバランサ自身にセッション維持機能は無く、常に振り分けアルゴリズムはleast connection(変更不可)となる為、アクセス後にどのサーバーにつながるかは保証されておらず、正しくPHPセッションが利用できなくなります。
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb1
1
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb2
1
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb1
2
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb2
2memcachedとPHPの設定変更
サーバ内のPHPセッションの保存方法(session.save_handler)ですが、デフォルトではfilesとなっているので、サーバのローカルディスクに追記されていきます。
[root@uozu-lb1 ~]# less /etc/php-fpm.d/www.conf
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/sessionmemcachedを導入し、このセッション情報の保存先を変更していきます。
今回は検証のため 0.0.0.0 で待ち受けていますが、待ち受けIPはプライベート側のIPアドレスに限定し、パケットフィルターやOSのファイアウォールでWebサーバー間の通信だけを許可する構成をおすすめします。
[root@uozu-lb1 ~]# dnf install memcached php-pecl-memcached
[root@uozu-lb1 ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1,::1"
[root@uozu-lb1 ~]# vi /etc/sysconfig/memcached
[root@uozu-lb1 ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 0.0.0.0,::"
[root@uozu-lb1 ~]# systemctl enable --now memcached
[root@uozu-lb1 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 1024 0.0.0.0:11211 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 1024 [::]:11211 [::]:*
LISTEN 0 511 *:80 *:*
LISTEN 0 128 [::]:22 [::]:*[root@uozu-lb1 ~]# vi /etc/php-fpm.d/www.conf
php_value[session.save_handler] = memcached
php_value[session.save_path] = "localhost:11211,203.0.113.132:11211"
[root@uozu-lb1 ~]# php-fpm -t
[09-Aug-2026 21:44:24] NOTICE: configuration file /etc/php-fpm.conf test is successful
[root@uozu-lb1 ~]# systemctl restart php-fpmまた、同様の作業は他のサーバーでも行います。
memcached設定後の動作確認
設定変更後、改めてcurlでロードバランサからPHPセッションの管理サンプルにアクセスをしてみます。
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb1
1
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb2
2
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb1
3
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb2
4
$ curl -c cookie.txt -b cookie.txt http://203.0.113.130/session.php
uozu-lb1
5無事、サーバ間でPHPセッションの共通化が出来ました。
$ cat cookie.txt
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
133.125.230.181 FALSE / FALSE 0 php_uozu 3peamno9nun1ftu3o7k1po66sgmemcachedの中にもセッション情報が入っていることが確認できますね。
[root@uozu-lb1 ~]# memcached-tool localhost:11211
# Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM
2 120B 240s 1 1 no 0 0 0
[root@uozu-lb1 ~]# echo 'stats cachedump 2 1' | nc localhost 11211
ITEM memc.sess.key.3peamno9nun1ftu3o7k1po66sg [10 b; 1786281655 s]
END
[root@uozu-lb1 ~]# echo 'get memc.sess.key.3peamno9nun1ftu3o7k1po66sg' | nc localhost 11211
VALUE memc.sess.key.3peamno9nun1ftu3o7k1po66sg 0 10
count|i:5;
ENDただし、memcachedを利用したセッションは、memcachedやサーバが再起動してしまうと消えてしまうため注意が必要です。
さいごに
今回は、ロードバランサ配下でPHPセッションを利用する際の問題と、memcachedを使ってセッション情報を共通化する方法を確認しました。
PHPのデフォルト設定では、セッション情報は各サーバーのローカルディスクに保存されます。そのため、ロードバランサによって接続先サーバーが切り替わると、同じセッションIDを持っていても、別サーバー側ではセッション情報を参照できない場合があります。
session.save_handler を memcached に変更し、複数サーバーから同じセッション保存先を参照できるようにすることで、接続先サーバーが切り替わってもPHPセッションを継続できることを確認できました。
ただし、memcachedに保存したセッション情報は、memcachedやサーバーの再起動で消える可能性があります。また、memcachedを外部から接続できる状態にすると危険なため、待ち受けIPやファイアウォール設定には注意が必要です。
| 状態 | セッション保存先 | ロードバランサ配下での挙動 |
|---|---|---|
| デフォルト設定 | 各サーバーのローカルディスク | 接続先サーバーが変わるとセッション情報を共有できない |
| memcached設定後 | memcached | 接続先サーバーが変わってもセッション情報を参照できる |
| memcached再起動後 | 消失する可能性あり | セッションが消えるため注意が必要 |
| 永続化したい場合 | NFSなどの共有ストレージも候補 | 性能・ロック・障害影響を考慮する必要あり |
ロードバランサ配下でPHPアプリケーションを動かす場合は、セッション情報をどこに保存するかを事前に設計しておくことをおすすめします。
最後までお読みいただき、ありがとうございます!