RitoLabo

Laravelのキャッシュを用いてDB負荷の削減と高速化を行う(入門/導入編)

  • 公開:
  • カテゴリ: PHP Laravel
  • タグ: PHP,Laravel,5.5,5.4,5.3,cache,Redis,Memcached

今回はLaravelでキャッシュを扱います。入門・導入編という事で、導入部分から、全てのキャッシュ操作の共通部分までを解説します。

アジェンダ
  1. 開発環境
  2. キャッシュを使う事の利点
  3. Laravelで扱えるキャッシュの種別
  4. キャッシュの設定
  5. キャッシュ操作
    1. キャッシュの保存
    2. キャッシュの永久保存
    3. キャッシュからデータを取得
    4. キャッシュとDB取得ハンドル
    5. キャッシュからデータ取得&削除
    6. キャッシュからデータを削除
    7. キャッシュの全削除

開発環境

今回の開発環境は以下の通りです。

  • Linux CentOS 7
  • Apache 2.4
  • PHP 7.1
  • Laravel 5.5

Laravelのバージョンについては5.5だけでなく、5.4、5.3でも同一手順で進めていけます。

Laravelのルートディレクトリを「laravel/」としています。

キャッシュを使う事の利点

WEBアプリケーションを公開し運用していくと、段々とアクセスも上がり、リクエストも増えていきます。それに伴い、データベースへの負荷ももちろん上昇していきますが、スケールアップを行わず、チューニングだけで対応するのには限界があります。

そんな時は、キャッシュを上手く使うとデータベースへの負荷を削減する事が出来ます。

データ取得を、データベースからではなくキャッシュから行う事によって、DBへのリクエストを減らし、結果負荷が削減できる。ということになります。

また、複雑なクエリなどが多い場合は、その結果をキャッシュさせる事によってデータの読み出しが早くなり、リクエスト処理も高速化できます。

また、MemcachedやRedisなどのインメモリデータベースと合わせることによって、更なる高速化を図ることもできます。

Laravelで扱えるキャッシュの種別

Laravelで扱えるキャッシュは以下の6種類です。

apc
APC(Alternative PHP Cache)というPHPの中間コードのキャッシュや最適化を行う拡張モジュールを使用します。
array
キャッシュ自体は行われませんが、これを指定しておく事でキャッシュを用いる実装をしていても動作します。
database
データベースを用いたキャッシュを行います。
file
ファイルベースでのキャッシュを行います。
memcached
Memcachedという分散メモリ・オブジェクト・キャッシング・システムを用いてキャッシュを行います。
https://memcached.org
redis
Redisというインメモリデータベースを用いてキャッシュを行います。
https://redis.io/

キャッシュの設定

それでは実際にLaravelでキャッシュを使う為の設定を行います。

キャッシュの設定に関しては laravel/config/cache.php に書かれていますが、どのキャッシュシステムを採用するかはenvファイルで設定するようになっているので、そこに先ほど記述した6種類の中の何を使うかを記述します。

laravel/.env
# apc / array / database / file / memcached / redis のどれかを設定する
CACHE_DRIVER=file

今回はデフォルトであるファイルベースでのキャッシュを設定しました。fileはキャッシュシステムに関して特別な用意は不要なので、まず気軽に試してみるにはこれで良いです。

これだけです。これでキャッシュを使う為の設定は完了です。

キャッシュ操作

それでは実際にキャッシュに関する操作を行います。

データベースではなくキャッシュからデータ取得を行う事で、その負荷を削減する。を今回の目的としてコードを記述していきます。

データ取得を行える適当なテーブルとコントローラを1つ用意してください。そこへ記述していきます。

キャッシュの保存

データをキャッシュへ保存します。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use DB;
use Illuminate\Support\Facades\Cache;

class SampleCacheController extends Controller
{
protected $table;
protected $id;

public function __construct()
{
$this->table = 'users';
}

/**
* キャッシュに保存する
*/
public function put()
{
// Cache::put('key', 'value', 'minutes');
// key 識別子
// value 格納する値
// minutes キャッシュを保持する時間(分)

// セット対象のID
$this->id = 3;

// キャッシュ保持を30分間とする
$minutes = 30;

// DBからデータ取得
$data = DB::table($this->table)->select('id', 'name', 'email')->where('id', $this->id)->first();

// データをキャッシュに保存する
Cache::put($this->id, json_encode($data), $minutes);
}
}

Cacheファサードのput()メソッドを使い、引数にはキャッシュへストアする識別子・保存したい値・キャッシュ保持時間をセットして実行する事でデータをキャッシュへ保存できます。

ちなみに、保存する値をjson_encode()していますが、複数の値を収納する際にはjson型の方が後々使いまわせて扱いやすいので変換しています。

キャッシュの永久保存

先ほどはキャッシュの保持時間を設定しましたが、期限無制限としてストアする事もできます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use DB;
use Illuminate\Support\Facades\Cache;

class SampleCacheController extends Controller
{
protected $table;
protected $id;

public function __construct()
{
$this->table = 'users';
}

/**
* 期限無期限としてキャッシュに保存する
*/
public function forever()
{
// Cache::forever('key', 'value');
// key 識別子
// value 格納する値

// セット対象のID
$this->id = 3;

// DBからデータ取得
$data = DB::table($this->table)->select('id', 'name', 'email')->where('id', $this->id)->first();

// データをキャッシュに保存する
Cache::forever($this->id, json_encode($data));
}
}

forever()メソッドを使う事で期限無制限での保存が出来ます。もちろん、先ほどあった第三引数は不要になります。

forever()メソッドでデータを登録した場合は、保持期限によってデータが削除されないので、forget()メソッドで削除する必要があります。(データ量が上限に達した場合は削除されていきます)

キャッシュからデータを取得

データをキャッシュから取得する場合です。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use DB;
use Illuminate\Support\Facades\Cache;

class SampleCacheController extends Controller
{
protected $table;
protected $id;

public function __construct()
{
$this->table = 'users';
}

/**
* キャッシュからデータを取得する
*/
public function get()
{
// Cache::get('key');
// key 取得対象の識別子

// 取得対象のID
$this->id = 3;

// キャッシュからデータを取得する
$data = json_decode(Cache::get($this->id));

}
}

Cacheファサードのget()メソッドを使い、引数には取得したい識別子(プロパティ)を指定する事で指定したデータを取得できます。

データストア時にjson型へ変換を行ったので、取得時にはjson_decode()でデコードを行いオブジェクトへ戻しています。

stdClass Object
(
[id] => 3
[name] => user03
[email] => test03@test.com
)

キャッシュとDB取得ハンドル

状況によってはキャッシュにデータが存在しているかが不明な場合もあります。

そんな時は、キャッシュからデータ取得を行い、存在していなければDBからデータ取得を行い、さらにキャッシュへ登録する事もできます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use DB;
use Illuminate\Support\Facades\Cache;

class SampleCacheController extends Controller
{
protected $table;
protected $id;

public function __construct()
{
$this->table = 'users';
}

/**
* キャッシュからデータ取得を行い、存在していなければ
* DBからデータ取得を行いキャッシュへ登録する
*/
public function getRemember()
{
// 取得対象のID
$this->id = 3;

// キャッシュ保持を30分間とする
$minutes = 30;

// Cache::remember('key', 'minutes', function () { return $ret; });
// key 取得対象の識別子
// minutres キャッシュを保持する時間(分)
// function キャッシュ内に存在しなかった場合の処理

// キャッシュから取得。存在しなければDBから取得したものをキャッシュに登録し返す
$data = Cache::remember($this->id, $minutes, function () {
$d = DB::table($this->table)->select('id', 'name', 'email')->where('id', $this->id)->get();
return json_encode($d);
});

}
}

remember()メソッドの第三引数にクロージャ(無名関数)を実装する事により、キャッシュに指定したデータが存在していない場合はコールバックとしてクロージャの返り値を取得します。また、その際にキャッシュへの登録も行われます。

キャッシュからデータ取得&削除

キャッシュからデータを取得後、削除する事も可能です。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use DB;
use Illuminate\Support\Facades\Cache;

class SampleCacheController extends Controller
{
protected $table;
protected $id;

public function __construct()
{
$this->table = 'users';
}

/**
* キャッシュからデータを取得後、削除する
*/
public function pull()
{
// 取得対象のID
$this->id = 3;

// Cache::pull('key');
// key 取得&削除対象の識別子

$data = Cache::pull($this->id);
}

}

データを取得後、キャッシュからは削除されます。

{"id":3,"name":"user03","email":"test03@test.com"}

キャッシュからデータを削除

キャッシュからデータを削除する場合は、Cacheファサードのforget()メソッドを使う事で、キャッシュからデータを削除できます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use DB;
use Illuminate\Support\Facades\Cache;

class SampleCacheController extends Controller
{
protected $table;
protected $id;

public function __construct()
{
$this->table = 'users';
}

/**
* キャッシュからデータを削除する
*/
public function forget()
{
// 取得対象のID
$this->id = 3;

// Cache::forget('key');
// key 削除対象の識別子

// キャッシュを削除する
Cache::forget($this->id);

}
}

キャッシュの全削除

キャッシュしたデータを全て削除するには、flush()メソッドを使います。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use DB;
use Illuminate\Support\Facades\Cache;

class SampleCacheController extends Controller
{
protected $table;
protected $id;

public function __construct()
{
$this->table = 'users';
}

/**
* キャッシュを全削除する
*/
public function flush()
{
// キャッシュ全削除
Cache::flush();
}
}

まとめ

作業は以上で完了です。

キャッシュベースとしてファイルベースを設定しましたが、今回紹介したCacheファサードでのメソッドはMemcachedやRedisなどべつのキャッシュシステムを設定した場合でも共通して使えるものなので、超入門・基本編として覚えておくとよいと思います。

DBへのリクエストが多かったり、複雑なクエリが多かったりするシステムなどには特に効果が出るので是非試してみてください。