Zend_Cacheを使って、ボトルネックとなっている処理を最適化してみました
システムエンジニアの今井です。
先日、レスポンスが非常に遅いAPIを利用する案件がありました。
APIの処理結果が戻ってくるのが遅いため、ページが表示されるまで約6~7秒かかっていました。
返事が遅い部分の最適化を行うため、以前から興味がありました、「Zend_Cache」を使って処理が遅い部分の解決をしてみました。
今回は、その時に利用したZend_Cacheの使い方について書いてみました。
0:環境情報
今回行った処理の環境情報は以下の通りです。
・OS
CentOS6
・PHP
5.5.11
・ZendFramework
1.12.6
ZendFrameworkは
http://framework.zend.com/
からMinimalをダウンロードして解凍して利用しました。
(2014/12/08時点では、バージョンは1.12.9です)
1:状況
当初の仕様はこのような形でした。
ですが、実際はこのような問題が発生してしまいました。
2:設計
①:キャッシュの格納先設定
Zend_Cacheのキャッシュは以下の場所に保存することができます。
a):サーバ上にファイルとして保存
b):SQLite内に保存
c):Memcached内に保存
d):APC(Alternative PHP Cache)内に保存
e):Xcache内に保存
f):ZendPlatform内に保存
今回は、サーバ上にファイルとして保存すれば、目視で確認できることもありわかりやすいので
「a):サーバ上にファイルとして保存」で設定することにしました。
②:キャッシュする時間
キャッシュできる時間は以下の設定ができます。
a):無限
b):秒指定
今回は「b):秒指定」で1日を設定しました。(60 x 60 x 24 = 86400秒)
③:キャッシュできるデータの種類
キャッシュできるデータは以下の種類があります。
a):変数の値
b):関数の処理結果
c):クラスの処理結果
d):ファイルの中身
e):出力ページ自体
今回は、APIから取得した値を変数に保存するので「a):変数の値」で設定することにしました。
3:設定
ここではZendFrameworkのMVCモデルで作成したコントローラーでの設定例を表示しています。
ZendFrameworkのMVCモデルの使い方の説明については、省略しています。
①:説明
InfoControllerのindexAction内で、
APIから取得した値をviewで表示する直前にキャッシュの設定をしました。
(InfoControllerのindexActionでは$_GET[‘id’]をキー値としてAPIから情報を取得しています)
②:InfoControllerコントローラー設定
<?php class InfoController extends Zend_Controller_Action { public function init() { } public function indexAction() { // ①:キャッシュのキー値を指定しています // ここでは$_GET['id']をキー値としています $cacheId = $_GET['id']; // ②:キャッシュ時間は86400秒で指定します $frontEndOption = array('lifetime'=>86400, 'automatic_serialization'=>true); // ③:保存場所を指定します。 // ここでは、application/../data/cache以下に指定しています // ./data/cacheには書き込み権限を付与してください // APPLICATION_PATHはZendFrameworkのpublic/index.php内で設定されている定数です $backEndOption = array('cache_dir'=> realpath(APPLICATION_PATH.'/../data/cache')); // ④:インスタンスを生成します // ・キャッシュするデータの種類を「変数の値」=>Coreとして設定します // また、保存先を「ファイル」=>Fileとして設定しています $cache = Zend_Cache::factory('Core', 'File', $frontEndOption, $backEndOption); // ⑤:有効期限が切れたファイルを消す設定です $cache->clean(Zend_Cache::CLEANING_MODE_OLD); // ⑥:キャッシュされているデータを呼び出します // 初回アクセス時、またはキャッシュの有効期限が切れていれば、falseが戻ります $data = $cache->load($cacheId); // ⑦:データが空の場合APIからデータを取得します // 空でなければ、APIからデータを取得せず、そのまま表示します // ApiFunctionは$_GET['id']をキーとして一致する情報を取得する自作関数です // この関数は環境に合わせて変更してください if (false===$data) { $data = ApiFunction($_GET['id']); // キャッシュにAPIから取得した値を保存します。 $cache->save($data); } // ⑧:ビューに値を渡します $this->view->data = $data; } }
③:結果
以上の設定でブラウザーから /info/index?id=xxx とアクセスした場合、初回はキャッシュがないため時間がかかりましたが、
2回目以降はキャッシュからデータが呼び出されるので、明らかに表示が早くなりました。
・ZendCacheを使う前:約6~7秒
・ZendCacheを使った後:約1秒
(当社環境)
4:使ってみて
導入する際は、以下の点に気をつけたほうがいいかなと思いました。
・更新が不定期に行われるサイトには向いていない
=>キャッシュしたデータを表示するので、リアルタイムに情報を表示するサイトの場合はキャッシュする必要がない
・有効期限が切れたキャッシュファイルは定期的に消すこと
=>利用するにつれて、ゴミファイルが沢山できるので、有効期限が切れたキャッシュファイルは削除しておくこと
・有効期限が切れた後の1回目の処理は重い
=>ただ、この辺りは有効期限が切れたころを見て、指定したURLを叩くバッチ処理を使ってキャッシュファイルを作成してもいいかと思いました
・PHPのmemory_limitの値
=>キャッシュするデータサイズが肥大して、PHPのmemory_limit値を超えてしまうと、メモリ不足エラーになってしまうので、memory_limitに適切な値を割り振るようにしたほうがいいかと思います
導入をしたい方は参考にしていただければと思います。