Các bạn thực hiện các dự án sẽ có một số service và hoạt động nào đó mà tốn nhiều CPU hoặc thời gian thực thi. Khi gặp phải các tình huống tương tự, các bạn nên cân nhắc sử dụng cache để lưu kết quả hoạt động của bạn và cũng là để cho lần gọi tiếp theo (nếu dữ liệu không phải cần realtime).
Bộ nhớ lưu trữ cache có thể là Redis, Memcached,… Bạn nào dùng Laravel thì sẽ thấy có API để các bạn làm việc với đa số các bộ nhớ cache có trong store phổ biến. Các thao tác dùng cũng không có gì rắc rối.
Khái niệm về cache
Cache được hiểu là bộ nhớ đệm. Về cơ bản, nó là một lớp nằm giữa website và cơ sở dữ liệu. Các dữ liệu được lưu trữ trong bộ nhớ cache là kết quả của những lần thao tác với trang web và dữ liệu của bạn trước đó. Nó cũng là bản sao dữ liệu được trữ ở nơi khác.
Các truy vấn đến cơ sở dữ liệu có thể bị chậm nếu trang web có nhiều người truy cập vào cùng một thời điểm. Lớp cache khi đó sẽ hoạt động với vai trò là trung gian để lưu trữ các dữ liệu không thay đổi giữa các request. Việc lấy các thông tin từ bộ nhớ cache sẽ nhanh hơn và bạn không phải tính toán lại kết quả. Bạn thậm chí không phải truy vấn lại các cơ sở dữ liệu hiện hữu.
Cấu hình cho Cache
Hệ thống Laravel thường cung cấp một API thống nhất cho các hệ thống cache khác nhau. Cấu hình cho cache được đặt trong file config/cache.php. Ở trong file này, các bạn có thể chỉ định chính xác cache driver nào cần sử dụng mặc định trong ứng dụng. Laravel cũng cung cấp sẵn các hệ thống cache (phía backends) thông thường như Redis và memcached.
File cấu hình cache cũng chứa nhiều tùy chọn khác nhau. Chúng thường được ghi chú đầy đủ bên trong. Do đó, đừng làm biếng mà đọc sơ sài. Các chỉ dẫn bên trong đó sẽ giúp các bạn đỡ sai sót các thao tác sau đó. Laravel được cấu hình mặc định để sử dụng cache driver là file và để lưu giữ các cache object (đã được serialized) trong hệ thống file.
Ở các ứng dụng lớn hơn, các bạn nên sử dụng in-memory cache như Memcached hoặc APC. Nếu thành thạo hơn, thì các bạn tự cấu hình để sử dụng nhiều cấu hình cache riêng cho cùng một driver.
Yêu cầu cho cache như thế nào?
Sử dụng cache driver database
Khi bạn sử dụng cache driver database, nên thiết lập một bảng để lưu trữ các loại cache của nó. Xem ví dụ về khai báo Schema cho bảng ở dưới đây:
Schema::create('cache', function($table) {
$table->string('key')->unique();
$table->text('value');
$table->integer('expiration');
});
Bạn cũng có thể dùng câu lệnh Artisan PHP artisan cache:table để tạo 1 migration với schema. Sử dụng Memcached thì bạn phải cài đặt Memcached PECL package. Liệt kê toàn bộ Memcached servers trong file cấu hình config/cache.php như sau:
'memcached' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 100
],
],
Thiết lập thông số host tới 1 đường dẫn hướng tới UNIX socket cũng là 1 cách khác mà bạn có thể thử. Nếu chọn cách này, thì đừng quên port phải được điều chỉnh về 0.
'memcached' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
Sử dụng Redis cache
Trước khi sử dụng Redis cache trong Laravel, bạn cần cài đặt thư viện Composer predis/predis package (~1.0). Bạn nên tham khảo thêm thông tin về cấu hình cho Redis và Laravel documentation page.
Sử dụng Cache có khó không?
Lấy 1 đối tượng cache
Illuminate\Contracts\Cache\Factory và Illuminate\Contracts\Cache\Repository contracts có nhiệm vụ truy xuất tới Laravel cache services. Contract Factory cung cấp truy cập đến tất cả cache drivers (được khai báo cho ứng dụng). Còn Contract Repository có vai trò cơ bản là triển khai của cache driver mặc định cho ứng dụng mà bạn chỉ định trong file cấu hình cache.
Ngoài 2 cái vừa nêu, các bạn cũng có thể dùng cache façade. Cache façade cũng thường xuất hiện nhiều lần. Nó cung cấp cách truy xuất dễ dàng và ngắn gọn đến các phần triển khai của các Laravel contracts.
Truy xuất đến nhiều cache stores
Khi sử dụng Cache façade, nó cho phép ta truy xuất đến nhiều cache store thông qua hàm stor. Giá trị khóa truyền vào hàm store cần thích hợp với một trong các store danh sách có trong mảng cấu hình file của cache.
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 10);
Lấy các items trong cache
Hàm get trong cache façade có vai trò là lấy các items trong cache. Nếu item nào đó không hiện hữu trong cache, giá trị null sẽ được trả về. Bạn cũng có thể truyền vào tham số thứ nhì để hàm get chỉ định giá trị mặc định (nếu item đó không tồn tại).
$value = Cache::get('key');
$value = Cache::get('key', 'default');
Bạn thậm chí có thể truyền vào 1 closure như giá trị mặc định. Kết quả của closure sẽ được trả về nếu item cần lấy không tồn tại trong cache. Khi truyền vào 1 closure, bạn có thể trì hoãn việc lấy giá trị mặc định từ trong 1 database hoặc từ 1 dịch vụ bên ngoài.
$value = Cache::get('key', function() {
return DB::table(...)->get();
});
Kiểm tra sự tồn tại của item
Hàm has có nhiệm vụ kiểm tra xem liệu 1 item có tồn tại trong cache hay không.
if (Cache::has('key')) {
//
Tăng hoặc giảm giá trị
Hàm increment và decrement có nhiệm vụ điều chỉnh giá trị của các items số nguyên nằm trong cache. Hai hàm này cho phép tham số thứ nhì chỉ định giá trị tăng hoặc giảm cho cache item.
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
Retrieve và Store
Đôi khi, bạn cần lấy ra 1 item trong cache nhưng đồng thời muốn lưu giá trị mặc định cho item (nếu không tồn tại). Ví dụ bạn muốn lấy tất cả users nằm trong cache. Nếu chúng không tồn tại, thì bạn sẽ lấy từ database và bỏ vào trong cache. Dùng hàm Cache::remember để thực hiện chuyện này.
$value = Cache::remember('users', $minutes, function() {
return DB::table('users')->get();
});
Nếu item không có tồn tại trong cache, thì closure sẽ truyền vào trong hàm remember. Khi đó, nó sẽ được thực thi và kết quả lưu vào trong cache.
Retrieve và Delete
Nếu muốn lấy ra 1 item trong cache và xóa, thì bạn dùng hàm pull. Hàm pull tương tự như hàm get. Null sẽ được trả về nếu item không tồn tại trong cache từ trước đó.
$value = Cache::pull('key');
Cách lưu trữ items trong cache
Sử dụng hàm put của cache façade để lưu các item trong cache. Khi thêm 1 item trong cache, bạn cần chỉ rõ số phút mà giá trị sẽ được lưu. Thực hiện dòng lệnh này:
Cache::put('key', 'value', $minutes);
Thay vì truyền vào số phút cho đến khi item hết hạn, bạn cũng có thể truyền vào 1 đối tượng PHP (kiểu Date và Time) để thể hiện thời gian hết hạn của item được cache.
$expiresAt = Carbon::now()->addMinutes(10);
Cache::put('key', 'value', $expiresAt);
Store (if not present)
Hàm add chỉ nên thêm vào cache khi nó chưa tồn tại sẵn. Hàm này sẽ trả về true nếu item thật sự được thêm vào cache. Nếu không, thì hàm sẽ trả về false.
Cache::add('key', 'value', $minutes);
Xóa các items ra khỏi cache
Hàm forever có thể được dùng để lưu 1 item trong cache vĩnh viễn. Các giá trị cần phải được tháo ra (bằng tay) khi sử dụng hàm forget.
Cache::forever('key', 'value');
Nếu đang sử dụng Memcached driver, items sẽ được lưu forever và có thể được xóa khi cache bị đầy.
Cách xóa các item từ cache
Sử dụng hàm forget sẽ giúp bạn xóa các item ra khỏi cache.
Cache::forget('key');
Còn nếu muốn xóa toàn bộ cache, thì hãy sử dụng hàm flush.
Cache::flush();
Việc xóa toàn bộ cache không tuân theo tiền tố cache đặc biệt nào hết. Nó sẽ xóa toàn bộ items trong cache. Do đó, bạn nên chú ý thao tác xóa bất cứ giá trị cache (đặc biệt là khi item có liên quan đến nhau và được sử dụng chung giữa các ứng dụng).
The Cache Helper là gì?
Khi sử dụng cache façade hoặc cache contract, bạn có thể dùng hàm cache để nhận và lưu dữ liệu từ cache. Khi hàm cache được gọi 1 mình nó, tham số tring và nó sẽ trả về giá trị của key.
$value = cache('key');
Nếu cung cấp 1 mảng cặp key/value và thời gian hết hàm của hàm, thì nó sẽ lưu giá trị vào cache (trong 1 khoảng thời gian được chỉ định).
cache(['key' => 'value'], $minutes);
cache(['key' => 'value'], Carbon::now()->addSeconds(10));
Khi testing gọi hàm cache, bạn có thể dùng hàm Cache::shouldReceive để thực hiện testing 1 façade.
Cache Tags
Cache tag thường không hỗ trợ chúng ta khi sử dụng cache driver là file hoặc database. Khi sử dụng nhiều tag với cache (được lưu dưới dạng forever), hiệu năng sẽ đạt đỉnh vào lúc driver đủ khả năng tự động xóa các danh sách đã lưu quá lâu như memcached.
Cách lưu các item đã được tag
Cache tag cho phép ta dùng tag các item có liên quan cùng nhau trong cache và có thể xóa toàn bộ các giá trị cache mà chúng có chung 1 tag. Các bạn có thể truy xuất vào 1 cache được tag bằng cách truyền vào 1 mảng các tên tag. Ví dụ hãy truy cập vào 1 tagged cache và đặt giá trị vào trong cache.
Cache::tags(['people', 'artists'])->put('John', $john, $minutes);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);
Truy xuất vào cache item đã được tag
Để lấy được 1 cache item (đã được tag), bạn truyền vào danh sách tương tự các tag trong hàm tags. Sau đó, bạn dùng hàm get và key để lấy.
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');
Cách xóa tagged cache items
Chúng ta có thể xóa tất cả item có chung 1 tag hoặc danh sách các tag. Ví dụ thực hiện mã lệnh sau sẽ xóa toàn bộ cache được tag với giá trị là people hoặc authors (thậm chí cả 2 giá trị). Do đó, Anne và John sẽ bị xóa ra khỏi cache.
Cache::tags(['people', 'authors'])->flush();
Ngược lại, dòng lệnh đó sẽ chỉ xóa các cache có tag là authors. Vì vậy, chỉ có Anne là bị xóa.
Cache::tags('authors')->flush();
Bạn có thể bổ sung 1 cache driver tùy biến.
Viết tùy biến cache driver
Để viết 1 tùy biến cache driver, bạn cần thực hiện Illuminate\Contracts\Cache\Store contract contract. MongoDB sẽ giúp bạn làm chuyện đó.
Bạn chỉ cần thực hiện mỗi phương thức khi sử dụng kết nối MongoDB. Làm thế nào để thực thi các phương thức đó? Hãy chú ý đến Illuminate\Cache\MemcachedStore. Khi đã bắt đầu thực hiện, bạn có thể tùy biến đăng ký driver.
Cache::extend('mongo', function($app) {
return Cache::repository(new MongoStore);
});
Khi nào thì tùy biến code cache driver? Bạn có thể tạo 1 Extensions namespace trong thư mục của ứng dụng. Tuy nhiên, bạn nên để cấu trúc ứng dụng linh hoạt để sắp xếp theo trật tự riêng của bạn.
Cách đăng ký tùy biến cache driver
Để đăng ký tùy biến cache driver trong Laravel, bạn sử dụng hàm extend trong cache façade. Gọi Cache::extend có thể được thực hiện trong hàm boot của App\Providers\AppServiceProvider mặc định hoặc bạn có thể tạo tùy biến service provider để mở rộng. Đừng quên đăng ký provider trong mảng config/app.php provider:
Tham số đầu tiên khi truyền vào hàm extend là tên của driver. Nó tương thích với driver đã lựa chọn trong file cấu hình config/cache.php. Tham số thứ nhì là 1 closure thật nên ta có thể trả về 1 Illuminate\Cache\Repository instance.
Closure sẽ truyền vào 1 $app instance vì nó là instance của service container. Khi mở rộng tùy biến của bạn được chấp nhận, bạn chỉ cần cập nhật file cấu hình config/cache.php giống với tên của mở rộng driver.
Events
Để thực thi code khi có 1 thao tác làm việc với cache, bạn có thể lắng nghe các events từ cache. Về cơ bản, bạn nên đặt các phần này trong EventServiceProvider.
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Cache\Events\CacheHit' => [
'App\Listeners\LogCacheHit',
],
'Illuminate\Cache\Events\CacheMissed' => [
'App\Listeners\LogCacheMissed',
],
'Illuminate\Cache\Events\KeyForgotten' => [
'App\Listeners\LogKeyForgotten',
],
'Illuminate\Cache\Events\KeyWritten' => [
'App\Listeners\LogKeyWritten',
]];
Cập nhật thêm được vài kiến thức mới
Bài viết hữu ích.
Hữu ích
Cảm ơn Admin. Bài viết khá hay !
OK bạn, mình sẽ sắp xếp viết một bài về Extend Validation. Cảm ơn bạn đã quan tâm nhé.