CakePHPのセッション管理をElactiCache Memcachedで

CakePHPのセッション管理はデフォルトではローカルのディレクトリにファイルで〜という形になっていて、
AWSのEC2などを使ってスケーラブルなものにしようとした場合、裏側はスケーラブルなKeyValueストアにするのが良い感じです。
 
AWSの場合はElastiCacheのMemcached(Consistent Hashing)とRedis(Master-Slave)という選択肢がありますが、
今回はMemcahedで構築してみたいと思います。(次回はRedisやります)
 
 
■ EC2インスタンスの起動
 
EC2のAmazon LinuxにCakePHPをインストールしてきます。
 
友人の@yandoが著者のCakePHP2実践入門によると、
– PHP5.2.8以上
– Apache等のHTTPサーバー(IISやNginxでもOK)、
– mod_rewriteが使えると良さ気
– データベース使う場合はPDO(PHP Data Object)モジュール
とのことで、Amazon LinuxにApacheとPHPとMySQLをyumでインストールすれば良いかな、と。
 
Management ConsoleからLaunch Instanceする時に、サクっとReview and Launchボタンで立ち上げると、
デフォルトでセキュリティグループの設定で80番ポートが開いてないので↓のようにAddしてやります。

 
 
■ Apache, PHP, MySQLのインストール
 
yumで↓こんな感じでインストールしていきます。

$ sudo yum -y install httpd php mysql-server php-mysql
読み込んだプラグイン:priorities, update-motd, upgrade-helper
依存性の解決をしています
〜略〜
インストール:
  httpd.x86_64 0:2.2.26-1.1.amzn1    mysql-server.noarch 0:5.5-1.3.amzn1    php.x86_64 0:5.3.27-1.0.amzn1    php-mysql.x86_64 0:5.3.27-1.0.amzn1

依存性関連をインストールしました:
  apr.x86_64 0:1.4.6-1.10.amzn1                     apr-util.x86_64 0:1.4.1-4.14.amzn1              apr-util-ldap.x86_64 0:1.4.1-4.14.amzn1
  generic-logos.noarch 0:17.0.0-2.5.amzn1           httpd-tools.x86_64 0:2.2.26-1.1.amzn1           mysql55.x86_64 0:5.5.34-1.40.amzn1
  mysql55-common.x86_64 0:5.5.34-1.40.amzn1         mysql55-libs.x86_64 0:5.5.34-1.40.amzn1         mysql55-server.x86_64 0:5.5.34-1.40.amzn1
  perl-DBD-MySQL.x86_64 0:4.020-2.8.amzn1           perl-DBI.x86_64 0:1.609-4.4.amzn1               php-cli.x86_64 0:5.3.27-1.0.amzn1
  php-common.x86_64 0:5.3.27-1.0.amzn1              php-pdo.x86_64 0:5.3.27-1.0.amzn1

完了しました!

 
ApacheとMySQLを起動します。
ついでにマシンイメージを取得して、そこからインスタンスを立ち上げる場合などに備えて、
自動起動の設定を入れておきましょう。
– Apache

$ sudo /etc/init.d/httpd start
httpd を起動中:                                            [  OK  ]
$ sudo chkconfig httpd on

– MySQL

$ sudo /etc/init.d/mysqld start
MySQL データベースを初期化中:  Installing MySQL system tables...
OK
Filling help tables...
OK
〜略〜
Please report any problems with the /usr/bin/mysqlbug script!

                                                           [  OK  ]
mysqld を起動中:                                           [  OK  ]
$ sudo chkconfig mysqld on

 
 
■ CakePHPのインストール
 
続きましてCakePHPのインストール、というかダウンロードして配置します。
http://cakephp.jp/ をみると、ダウンロードのリンクが https://codeload.github.com/cakephp/cakephp/zip/2.4.3 だったので、

$ cd /var/www/html/
$ sudo curl -O https://codeload.github.com/cakephp/cakephp/zip/2.4.3
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 2042k  100 2042k    0     0   367k      0  0:00:05  0:00:05 --:--:--  495k
$ ls -ltr
合計 2044
-rw-r--r-- 1 root root 2091758 12月 17 01:39 2013 2.4.3
$ sudo unzip 2.4.3
Archive:  2.4.3
eb34e011e2384041997da167821c36125e8f836e
   creating: cakephp-2.4.3/
  inflating: cakephp-2.4.3/.editorconfig
  inflating: cakephp-2.4.3/.gitignore
〜略〜
$ pwd
/var/www/html
$ ls -l
合計 2048
-rw-r--r-- 1 root root 2091758 12月 17 01:39 2013 2.4.3
drwxr-xr-x 6 root root    4096 11月 25 02:25 2013 cakephp-2.4.3

 
Apacheのプロセスはapacheユーザーで動いているので、ディレクトリの権限をapacheに変更します。

$ ps -ef | grep httpd
root      1397     1  0 01:21 ?        00:00:00 /usr/sbin/httpd
apache    1400  1397  0 01:21 ?        00:00:00 /usr/sbin/httpd
apache    1401  1397  0 01:21 ?        00:00:00 /usr/sbin/httpd
apache    1402  1397  0 01:21 ?        00:00:00 /usr/sbin/httpd
apache    1403  1397  0 01:21 ?        00:00:00 /usr/sbin/httpd
apache    1404  1397  0 01:21 ?        00:00:00 /usr/sbin/httpd
apache    1405  1397  0 01:21 ?        00:00:00 /usr/sbin/httpd
apache    1406  1397  0 01:21 ?        00:00:00 /usr/sbin/httpd
apache    1407  1397  0 01:21 ?        00:00:00 /usr/sbin/httpd
ec2-user  1766  1304  0 01:42 pts/0    00:00:00 grep httpd

$ sudo chown -R apache:apache /var/www/html/cakephp-2.4.3

 
Apacheの設定ファイルでDocumentルートをcakephp-2.4.3にします。
Apacheの設定ファイルは /etc/httpd/conf.d/ に配置されますが、そこのREADMEを読むと、
以下のように書かれていて、このディレクトリにある”.conf”ファイルならOKとのことです。
ついでにアルファベット順で並ぶから、mod_perlを使うようなモノはperl.confより後で〜
って注意書きもあったりもします。 #ハマったりしそうですね。。コレ。。。

This directory holds Apache 2.0 module-specific configuration files;
any files in this directory which have the ".conf" extension will be
processed as Apache configuration files.

Files are processed in alphabetical order, so if using configuration
directives which depend on, say, mod_perl being loaded, ensure that
these are placed in a filename later in the sort order than "perl.conf".

ということで、以下のように cake.conf というファイルを作ってみました。
.htaccessを使いたいのでAllowOverride Allにします。
↓こちらのブログを参考にさせていただきました。
http://d.hatena.ne.jp/hrendoh/20110501/1304271044

$ sudo vim /etc/httpd/conf.d/cake.conf
<VirtualHost ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com:80>
    DocumentRoot /var/www/html/cakephp-2.4.3
    <Directory /var/www/html/cakephp-2.4.3>
      AllowOverride All
    </Directory>
</VirtualHost>

 
最後にApacheを再起動して、EC2にCakePHPがインストールできました。

$ sudo /etc/init.d/httpd restart
httpd を停止中:                                            [  OK  ]
httpd を起動中:                                            [  OK  ]

 
↓saltが〜とか、データベースの設定ファイルが〜って言われていますね、、、w

 
ということで、データベースにテーブルを作ってScaffoldしてみようと思います。

- UTF-8でデータベース作って
mysql> create database caketest default character set utf8;
Query OK, 1 row affected (0.00 sec)

- データベースユーザー作って
mysql> create user cakeuser@localhost;
Query OK, 0 rows affected (0.01 sec)

- データベースユーザーのパスワードを設定して
mysql> set password for cakeuser@localhost = password('cakepassword');
Query OK, 0 rows affected (0.00 sec)

- 作ったユーザーに権限を付与します
mysql> grant all on caketest.* to cakeuser@localhost;
Query OK, 0 rows affected (0.00 sec)

- 作ったデータベースにテーブルを作ります
mysql> use caketest
Database changed
mysql> create table cakes (id INT(11) NOT NULL AUTO_INCREMENT, description VARCHAR(64), created DATE, PRIMARY KEY(id));
Query OK, 0 rows affected (0.03 sec)

 
CakePHPのデータベース接続設定を変更します。

$ cd /var/www/html/cakephp-2.4.3/app/Config
$ sudo cp database.php.default database.php
$ sudo chown apache:apache database.php
 62 class DATABASE_CONFIG {
 63
 64         public $default = array(
 65                 'datasource' => 'Database/Mysql',
 66                 'persistent' => false,
 67                 'host' => 'localhost',
 68                 'login' => 'cakeuser', //データベースユーザー
 69                 'password' => 'cakepassword', //パスワード
 70                 'database' => 'caketest', //データベース名
 71                 'prefix' => '',
 72                 //'encoding' => 'utf8',
 73         );

 
Scaffold用Controllerを作ります。

cd /var/www/html/cakephp-2.4.3/app/Controller
$ sudo vim CakesController.php
<?php
class CakesController extends AppController {
  public $scaffold;
}

 
ブラウザからアクセスすると↓

 
動いてるっぽいですが、ワーニングが出まくってるのが気になる。。。

 
ググっていくと↓こちらのページに詳しく書かれていますね。
http://oki2a24.com/2012/08/24/how-to-set-php-ini-date-timezone/
Timezoneの設定をしてApacheを再起動します

$ sudo vim /etc/php.ini
 953 [Date]
 954 ; Defines the default timezone used by the date functions
 955 ; http://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone
 956 date.timezone = "Asia/Tokyo"
$ sudo /etc/init.d/httpd restart
httpd を停止中:                                            [  OK  ]
httpd を起動中:                                            [  OK  ]

ワーニング出なくなりましたーヽ(´▽`)ノ

 
 
■ CakePHPのセッション管理
 
CakePHPのデフォルトではローカルのファイルシステムを使ってセッション管理をします。
Controllerは↓こんな感じ。セッションオブジェクトに出し入れしてViewに渡す。

<?php
class TestController extends AppController {
  function index() {
    $this->Session->write('TestKey', 'TestValue');
    $value = $this->Session->read('TestKey');
    $this->set('session', $value);
  }
}

 
Viewは↓こんな感じ。
Controllerから受け取った値を表示する。

<?php
echo "Hello World!!";
echo $session;

 
設定ファイルをみると↓のような感じ。デフォルトではphp.iniの設定に従う、と。
(セッションをDBでという場合はapp/Config/Schema/sessions.phpを流してテーブル作ってね、って感じ)

181 /**
182  * Session configuration.
〜略〜
204  * The built in defaults are:
205  *
206  * - 'php' - Uses settings defined in your php.ini.
207  * - 'cake' - Saves session files in CakePHP's /tmp directory.
208  * - 'database' - Uses CakePHP's database sessions.
209  * - 'cache' - Use the Cache class to save sessions.
〜略〜
214  * To use database sessions, run the app/Config/Schema/sessions.php schema using
215  * the cake shell command: cake schema create Sessions
216  *
217  */
218         Configure::write('Session', array(
219                 'defaults' => 'php'
220         ));

 
では、php.iniの中はどうなっているかというと↓ココのようです。

1277 session.save_path = "/var/lib/php/session"

 
実際みてみると、タイムスタンプが更新されて中身も上記の値が入っています。

$ pwd
/var/lib/php/session
$ ls -ltr
total 152
-rw------- 1 apache apache 138 Dec 17 12:52 sess_hrs97ck4c5ie709dic2956ob60
〜略〜
-rw------- 1 apache apache  81 Dec 18 12:45 sess_gqad70guq37jocap6kmkqjcka5
-rw------- 1 apache apache  81 Dec 18 13:18 sess_00vn5bs2o8b540qkh9dvcs5vg3
-rw------- 1 apache apache 138 Dec 18 13:21 sess_8bo261uc8grii2rlkn3konjk17

- 現在の時刻は UTCで13時31分。
$ date
Wed Dec 18 13:31:44 UTC 2013

- ブラウザからアクセス後にみてみると、現在時刻のファイルができています。
$ ls -ltr
total 152
-rw------- 1 apache apache 138 Dec 17 12:52 sess_hrs97ck4c5ie709dic2956ob60
〜略〜
-rw------- 1 apache apache  81 Dec 18 13:18 sess_00vn5bs2o8b540qkh9dvcs5vg3
-rw------- 1 apache apache 138 Dec 18 13:31 sess_8bo261uc8grii2rlkn3konjk17

- 中身を参照してみると、Controllerで入れたKeyとValueが確認できました。
$ cat sess_8bo261uc8grii2rlkn3konjk17
Config|a:3:{s:9:"userAgent";s:32:"6d912fd2293bc65a0521c338cf959e27";s:4:"time";i:1387387908;s:9:"countdown";i:10;}TestKey|s:9:"TestValue"; 

 
 
■ CakePHPのセッション管理をElastiCacheのMemcachedで
 
ElastiCacheのManagementConsoleで3ノード。t1.microで。

 
それ用のセキュリティグループ(11211ポート)を立てます。

 
↓ElastiCacheが起動するとこんな感じになります。

 
↓各ノード

 
Configration Endpointにtelnetで接続してみます。

$ sudo yum install telnet
$ telnet cakecache.nwiwua.cfg.apne1.cache.amazonaws.com 11211
Trying 172.31.20.172...
Connected to cakecache.nwiwua.cfg.apne1.cache.amazonaws.com.
Escape character is '^]'.
set key 0 900 4 //"key"というキーで
hoge            //"hoge"という文字列を保存
STORED
get key         //"key"というキーの値を取得
VALUE key 0 4
hoge            //取得した文字列
END
quit

 
Configuration Endpointというは、AWSが提供しているライブラリを使用すれば、
AutoDiscoveryで〜的な(詳しくは↓のリア充な先輩のブログを参照)事が出来ますが、
http://understeer.hatenablog.com/entry/2013/01/04/061717
今回は、作った3つのノードを普通に使います。
 
CakePHPの設定ファイルのcore.phpを変更します。
私の環境では /var/www/html/cakephp-2.4.3/app/Config/core.php になります。
 
defaults を php から cache に変えて、handler で config を defaultに。
206 * – ‘php’ – Uses settings defined in your php.ini.
209 * – ‘cache’ – Use the Cache class to save sessions.

        Configure::write('Session', array(
                'defaults' => 'cache',
                'handler' => array(
                  'config' => 'default'
                ),
        ));

そしてdefaultの設定。
serversの所をElasciCacheのNodesのEndpointを記載します。
(ソレ以外はコメントに書いてあった設定をそのままです)

         Cache::config('default', array(
                'engine' => 'Memcache', //[required]
                'duration' => 3600, //[optional]
                'probability' => 100, //[optional]
                'prefix' => Inflector::slug(APP_DIR) . '_', //[optional]  prefix every cache file with this string
                'servers' => array(
                        'cakecache.nwiwua.0001.apne1.cache.amazonaws.com:11211',
                        'cakecache.nwiwua.0002.apne1.cache.amazonaws.com:11211',
                        'cakecache.nwiwua.0003.apne1.cache.amazonaws.com:11211',
                ), //[optional]
                'persistent' => true, // [optional] set this to false for non-persistent connections
                'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory)
        ));

 
が、エラーになってしまいました。。

 
↓こちらのブログをみると、MemcachedのPHPクライアントとして、php-pecl-memcacheが必要なようでしたので、
http://ab.blog.jp/archives/3867657.html
↓yumでインストールしてApacheを再起動します。

$ sudo yum install php-pecl-memcache
$ sudo /etc/init.d/httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

 
無事に画面が表示できました↓

 
↓ローカルにはタイムスタンプ的にファイルは作成されていません。

$ date
Wed Dec 18 14:37:15 UTC 2013
$ ls -ltr
total 152
-rw------- 1 apache apache 138 Dec 17 12:52 sess_hrs97ck4c5ie709dic2956ob60
〜略〜
-rw------- 1 apache apache  81 Dec 18 13:18 sess_00vn5bs2o8b540qkh9dvcs5vg3
-rw------- 1 apache apache 138 Dec 18 13:31 sess_8bo261uc8grii2rlkn3konjk17

 
telnetでMamcachedの方を見てみましょう。stats items と stats cachedump を使います。
– 0001のインスタンスには入ってないようです。

$ telnet cakecache.nwiwua.0001.apne1.cache.amazonaws.com 11211
Trying 172.31.20.44...
Connected to cakecache.nwiwua.0001.apne1.cache.amazonaws.com.
Escape character is '^]'.
stats items
STAT items:4:number 1
STAT items:4:age 1132
〜略〜
STAT items:4:evicted_unfetched 0
END
stats cachedump 4 1
ITEM app_qs0c11va9rt51ldi9u1td3n5a0 [81 b; 1387382341 s]
END
get app_qs0c11va9rt51ldi9u1td3n5a0
VALUE app_qs0c11va9rt51ldi9u1td3n5a0 0 81
Config|a:3:{s:9:"userAgent";s:0:"";s:4:"time";i:1387393140;s:9:"countdown";i:10;}
END
quit

– 続いて0002。入ってますね。

$ telnet cakecache.nwiwua.0002.apne1.cache.amazonaws.com 11211
Trying 172.31.30.203...
Connected to cakecache.nwiwua.0002.apne1.cache.amazonaws.com.
Escape character is '^]'.
stats items
STAT items:6:number 1
STAT items:6:age 1138
〜略〜
STAT items:6:evicted_unfetched 0
END
stats cachedump 6 1
ITEM app_8bo261uc8grii2rlkn3konjk17 [159 b; 1387382492 s]
END
get app_8bo261uc8grii2rlkn3konjk17
VALUE app_8bo261uc8grii2rlkn3konjk17 0 159
Config|a:3:{s:9:"userAgent";s:32:"6d912fd2293bc65a0521c338cf959e27";s:4:"time";i:1387393288;s:9:"countdown";i:10;}TestKey|s:9:"TestValue";From01|s:7:"Value01";
END

– 0003にはありません(先ほどテストで入れた”key”が残っていますが。)

$ telnet cakecache.nwiwua.0003.apne1.cache.amazonaws.com 11211
Trying 172.31.20.172...
Connected to cakecache.nwiwua.0003.apne1.cache.amazonaws.com.
Escape character is '^]'.
stats items
STAT items:1:number 1
STAT items:1:age 39292
〜略〜
STAT items:1:evicted_unfetched 0
END
stats cachedump 1 1
ITEM key [4 b; 1387341830 s]
END

 
 
■ 複数台のWebサーバーからセッションにデータを出し入れ
 
1台のCakePHPのWebサーバーからはMemcahedにアクセスできる事がわかったので、
今回はマシンイメージを取得して、そこから3インスタンス立ち上げて、前段にロードバランサを設置してみましょう。
 
では、まずマシンイメージを取得。EC2のManagement Consoleで右クリックして”Create Image”するだけです。

名前を付けて保存します。

 
3つインスタンスを立ち上げてみます。
上記で保存したイメージを右クリックして”Launch”するだけです。

続いてロードバランサを立てます。

ヘルスチェックはindex.phpで行います。レスポンスコード200が返ればOK。
ヘルスチェックのインターバルやスレッショルドはテストの為、短めで。

セキュリティグループの設定も忘れずに。

 
in service(全部OK)になりました。

 
続いて、ApacheのVirtualHostの設定を書き換えます。
他に何か動かす予定もないため*で。

$ sudo vim /etc/httpd/conf.d/cake.conf
<VirtualHost *:80>

 
CakePHPのコントローラーでは、他のインスタンスでセットした値を読み込むようにしてみました。
– 1つ目のインスタンス

<?php
class TestController extends AppController {
  function index() {
    $this->Session->write('From01', 'Value01');
    $value = $this->Session->read('From02');
    $this->set('session', $value);
  }
}

– 2つ目のインスタンス

<?php
class TestController extends AppController {
  function index() {
    $this->Session->write('From02', 'Value02');
    $value = $this->Session->read('From03');
    $this->set('session', $value);
  }
}

– 3つ目のインスタンス

<?php
class TestController extends AppController {
  function index() {
    $this->Session->write('From03', 'Value03');
    $value = $this->Session->read('From01');
    $this->set('session', $value);
  }
}

 
MemcachedのクラスタをManagement ConsoleからRebootして、
何回かブラウザでアクセスしていくと↓のようにイイ感じです。

 
次回はElastiCache Cluster ClientをCakePHPに組み込んで、Configuration Endpointでやりくりしてみたいと思います。
 

CakePHP2 実践入門 (WEB+DB PRESS plus)
安藤 祐介 岸田 健一郎 新原 雅司 市川 快 渡辺 一宏 鈴木 則夫
技術評論社
売り上げランキング: 32,187

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中