Joomla Bài học 16: Tối ưu hóa hiệu năng với hệ thống Caching (Page Cache, Conservative vs Progressive Cache) và Gzip
Một hệ thống CMS mạnh mẽ với cây phân quyền #__assets và đa ngôn ngữ như Joomla sẽ phải thực hiện hàng chục truy vấn SQL và khởi tạo hàng trăm đối tượng PHP trong mỗi chu kỳ Request nếu không có cơ chế bộ nhớ đệm. Trong Joomla Bài học 16, chúng ta sẽ mổ xẻ kiến trúc Multi-layer Caching (Bộ nhớ đệm đa tầng) của Joomla 5, phân biệt rạch ròi sự khác nhau giữa Conservative Cache, Progressive Cache và Page Cache, đồng thời tích hợp Redis và nén Gzip để giảm chỉ số TTFB (Time To First Byte) xuống dưới ngưỡng 50ms.
1. Giải phẫu 3 cơ chế Caching cốt lõi trong Joomla 5
Nhiều quản trị viên thường bật đại một chế độ Cache trong Global Configuration mà không hiểu rõ Joomla đang lưu trữ cái gì ở bên dưới. Thực chất, Joomla 5 cung cấp 3 cơ chế hoạt động ở các tầng hoàn toàn khác nhau của vòng đời ứng dụng (Application Lifecycle):
| Chế độ Cache | Nơi kích hoạt | Phạm vi lưu trữ (What is cached?) | Cơ chế hoạt động & Trường hợp sử dụng |
|---|---|---|---|
| 1. Conservative Caching (Khuyên dùng chuẩn) |
Global Configuration System System Cache: ON - Conservative |
Từng mảnh nhỏ: Output của Component View + Từng Module độc lập (chỉ những Module cho phép cache). | Cho phép tắt cache riêng cho từng Module động (như Giỏ hàng, Form đăng nhập, Bài viết ngẫu nhiên) trong khi các Module tĩnh (Menu, Footer) và nội dung bài viết vẫn lấy từ Cache. |
| 2. Progressive Caching | Global Configuration System System Cache: ON - Progressive |
Gom cụm toàn bộ Modules: Kết xuất của Component + Một khối Snapshot gộp chung tất cả các Module của trang đó theo từng User. | Nhanh hơn một chút khi trang có quá nhiều module tĩnh, nhưng bỏ qua cấu hình tắt cache của từng Module lẻ. Rất dễ gây lỗi hiển thị sai dữ liệu trên các module động hoặc tốn dung lượng lưu trữ khi có nhiều thành viên đăng nhập. |
| 3. Page Cache (Full-Page Cache) | System Plugins Bật plugin System - Page Cache |
Toàn bộ HTML của cả trang (Từ thẻ <!DOCTYPE html> đến </html>). |
Bắt sự kiện ngay từ đầu vòng đời ứng dụng (onAfterRoute), trả về thẳng cục HTML tĩnh mà không cần khởi tạo Template, Module hay gọi Component cho khách vãng lai (Guest). Nhanh gấp 10 lần nhưng chỉ áp dụng cho người chưa đăng nhập. |
Chiến lược kết hợp chuẩn Production:
Đối với Website Tin tức, Cổng thông tin doanh nghiệp, Landing Page (Ít tương tác tài khoản): Bật cả
Conservative Cachingkết hợp với PluginSystem - Page Cache.Đối với Website Thương mại điện tử, Hệ thống quản lý có đăng nhập, Giỏ hàng động: Chỉ bật
Conservative Cachingvà TẮTSystem - Page Cache(hoặc cấu hình loại trừ các URL giỏ hàng/thanh toán trong phần Exclude URLs của plugin Page Cache).
2. Cấu hình Cache Handler: Chuyển từ File sang Redis (In-Memory)
Mặc định, Joomla lưu các bản ghi cache dưới dạng tệp tin vật lý trong thư mục /cache và /administrator/cache (Cache Handler = File). Khi ổ cứng có hàng vạn file cache nhỏ, thao tác đọc/ghi đĩa (Disk I/O) sẽ trở thành nút thắt cổ chai.
Để đạt hiệu năng cao nhất trên môi trường Docker của chúng ta, hãy chuyển Cache Handler sang Redis:
Bước 1: Bổ sung Redis vào docker-compose.yml và cài đặt PHP Redis Extension
-
Trong
docker/php/Dockerfile, thêm cài đặtredisqua PECL:Dockerfile
RUN pecl install redis && docker-php-ext-enable redis -
Trong
docker-compose.yml, thêm serviceredis:YAML
redis: image: redis:7-alpine container_name: joomla_redis restart: unless-stopped ports: - "6379:6379" networks: - joomla-net
Bước 2: Kích hoạt Redis trong Global Configuration
-
Truy cập System Global Configuration Tab System Mục Cache.
-
System Cache: Chọn
ON - Conservative caching. -
Cache Handler: Chọn
Redis(Chỉ xuất hiện khi PHP đã càiext-redis). -
Redis Server Host: Điền
redis(tên container trong mạng Docker) và Port:6379. -
Cache Time (Minutes): Đặt
15hoặc60phút (tương đương TTL - Time To Live của key trong Redis). -
Platform Specific Caching: Giữ là No (Chỉ bật Yes nếu bạn dùng code PHP để trả về HTML hoàn toàn khác nhau giữa Mobile và Desktop trên cùng một URL; nếu giao diện responsive bằng CSS Bootstrap 5 thì để No để dùng chung bản cache).
3. Nén dữ liệu Gzip / Brotli (Data Compression)
Nén Gzip giúp giảm dung lượng gói tin truyền tải qua mạng (HTML, JSON) từ 60% – 80% trước khi gửi về trình duyệt của người dùng.
-
Cách bật trong Joomla: Truy cập System Global Configuration Tab Server Bật Gzip Page Compression = Yes.
-
Nguyên tắc kiến trúc (Web Server vs PHP):
-
Khi bạn bật Gzip trong Joomla, tiến trình PHP-FPM sẽ phải tốn chu kỳ CPU để dùng hàm
gzencode()nén chuỗi HTML ở cuối request. -
Best Practice cho Backend Engineer: Nếu bạn làm chủ cấu hình máy chủ Nginx hoặc đứng sau Cloudflare, hãy TẮT Gzip Page Compression trong Joomla (
No) và để tầng Nginx đảm nhận việc nén cho cả HTML, CSS, JS và Font chữ (vì Nginx viết bằng C nén ở tầng mạng nhanh và nhẹ CPU hơn PHP rất nhiều):
-
Nginx
# Thêm vào khối server {} hoặc http {} trong docker/nginx/default.conf
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss image/svg+xml;
4. Quản lý và Xóa Cache (Cache Invalidation)
Khi biên tập viên sửa một bài viết hoặc thay đổi cấu hình Module nhưng ngoài trang chủ chưa cập nhật ngay, bạn cần thực hiện xóa Cache:
-
Xóa thủ công trên giao diện: Vào System Clear Cache Chọn các nhóm cache cần xóa (ví dụ:
com_content,mod_menu,page) và bấm Delete (hoặc bấm Delete All). -
Tự động xóa Cache quá hạn (Expired Cache): Các file cache đã hết hạn TTL sẽ không tự mất đi trên ổ đĩa cho đến khi có tiến trình dọn dẹp. Bạn có thể dùng Task Scheduler (sẽ học ở Bài 19) hoặc chạy lệnh Joomla CLI định kỳ:
Bash
# Xóa toàn bộ cache ngay lập tức qua dòng lệnh docker exec -it joomla_php php cli/joomla.php cache:clean # Hoặc chỉ dọn dẹp các bản ghi cache đã hết hạn (Expired) docker exec -it joomla_php php cli/joomla.php cache:clean --expired
5. Giải phẫu Code PHP: Sử dụng CacheController trong lập trình (Góc nhìn Backend)
Khi bạn tự lập trình một Module hoặc Component có các tác vụ nặng (như gọi API tỷ giá ngoại tệ từ bên thứ ba, hoặc chạy một câu truy vấn SQL thống kê phức tạp), bạn nên chủ động bọc logic đó bằng CacheControllerFactoryInterface của Joomla 5.
Joomla hỗ trợ 3 kiểu Cache Controller phổ biến trong code:
-
callback: Lưu kết quả trả về của một hàm/phương thức PHP bất kỳ dựa trên tham số đầu vào (Phổ biến nhất). -
output: Lưu đoạn mã HTML đượcechora giữa khốistart()vàend(). -
view: Lưu toàn bộ kết quả render của một đối tượng MVC View.
Ví dụ sử dụng CallbackController trong Joomla 5:
PHP
use Joomla\CMS\Factory;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;
use Joomla\CMS\Cache\Controller\CallbackController;
class PricingHelper
{
public static function getHeavyReportData(int $categoryId, string $currency = 'VND'): array
{
// 1. Lấy CacheControllerFactory từ Dependency Injection Container
/** @var CacheControllerFactoryInterface $cacheFactory */
$cacheFactory = Factory::getContainer()->get(CacheControllerFactoryInterface::class);
// 2. Khởi tạo CallbackController với nhóm cache tên là 'com_myreport'
/** @var CallbackController $cache */
$cache = $cacheFactory->createCacheController('callback', [
'defaultgroup' => 'com_myreport',
'caching' => true, // Luôn bật cache cho tác vụ này kể cả khi Global Cache tắt
'lifetime' => 30, // Lưu trong 30 phút
]);
// 3. Định nghĩa hàm xử lý nặng (Closure hoặc [Class, Method])
$heavyTask = static function (int $catId, string $curr): array {
// Giả lập truy vấn SQL nặng hoặc gọi cURL API mất 2 giây
$db = Factory::getContainer()->get('DatabaseDriver');
$query = $db->getQuery(true)
->select('COUNT(*) as total_articles, SUM(hits) as total_views')
->from($db->quoteName('#__content'))
->where($db->quoteName('catid') . ' = :catid')
->bind(':catid', $catId, \Joomla\Database\ParameterType::INTEGER);
$result = $db->setQuery($query)->loadAssoc();
$result['currency'] = $curr;
$result['generated_at'] = date('Y-m-d H:i:s');
return $result;
};
// 4. Gọi qua $cache->get($callable, $argsArray)
// Joomla sẽ tự băm (hash) mảng tham số [$categoryId, $currency] thành Cache ID duy nhất!
return $cache->get($heavyTask, [$categoryId, $currency]);
}
}
6. Tổng kết bài học
-
Phân biệt rõ ràng 3 chế độ: Conservative Cache (linh hoạt cho từng module), Progressive Cache (gom cụm toàn bộ module) và Page Cache (lưu toàn bộ trang tĩnh cho khách
Guest). -
Biết cách tích hợp Redis làm Cache Handler thay thế cho ổ cứng vật lý và tối ưu hóa nén Gzip ở tầng Nginx.
-
Làm chủ lệnh
php cli/joomla.php cache:cleanvà sử dụngCallbackControllertrong PHP để lưu đệm các phép tính hoặc truy vấn nặng.
Trong Bài học 17, chúng ta sẽ khám phá công cụ tìm kiếm toàn văn (Full-text Search) thế hệ mới của Joomla: Thiết lập tìm kiếm thông minh (Smart Search / Finder) và lập chỉ mục nội dung (Indexing).
All rights reserved