Khi bạn đang làm việc với PHP và MySQL, việc sử dụng Redis làm cache sẽ cải thiện hiệu suất ứng dụng của bạn. Bởi Redis lưu trữ dữ liệu trong RAM, nhanh hơn rất nhiều so với ổ đĩa HDD hoặc ổ đĩa SSD. Bộ nhớ cache cũng làm giảm cost cơ sở dữ liệu và tránh làm quá tải phần backend. Bài viết này, Vietnix sẽ hướng dẫn bạn cách sử dụng Redis để cache dữ liệu MySQL bằng PHP trên Ubuntu 20.04.
Yêu cầu để thiết lập Redis làm cache cho MySQL bằng PHP trên Ubuntu 20.04
- Máy chủ Ubuntu 20.04 với user non-root có quyền sudo.
- LAMP stack.
- Máy chủ Redis.
Để thiết lập Redis làm cache cho MySQL bằng PHP trên Ubuntu 20.04, bạn cần một VPS với cấu hình đủ mạnh để đáp ứng được yêu cầu của ứng dụng. Vietnix hiện đang cung cấp các gói VPS hỗ trợ hệ điều hành Ubuntu 20.04 với nhiều cấu hình và giá thành khác nhau để phù hợp với nhu cầu của bạn. Liên hệ ngay với Vietnix để được tư vấn lựa chọn.
Bước 1: Cài đặt thư viện Redis cho PHP
Đầu tiên, cài đặt extension php-redis
, cho phép bạn sử dụng PHP để communicate với Redis. Chạy các lệnh sau để cập nhật server của bạn và cài đặt extension:
sudo apt update
sudo apt install php-redis
Xác nhận cài đặt và khởi động lại web server Apache để load extension:
sudo systemctl restart apache2
Bước 2: Thiết lập cơ sở dữ liệu thử nghiệm, table và data mẫu
Bạn tạo cơ sở dữ liệu MySQL để lưu trữ dữ liệu vĩnh viễn vào đĩa. Bạn cũng sẽ tạo một số table và tài khoản user có đầy đủ đặc quyền đối với cơ sở dữ liệu.
Đầu tiên, đăng nhập vào máy chủ MySQL của bạn với tư cách là người dùng root:
sudo mysql -u root -p
Nhập mật khẩu root của máy chủ MySQL mà bạn đã thiết lập trong LAMP. Sau đó, nhấn ENTER
để tiếp tục.
Tiếp theo, tạo cơ sở dữ liệu test_store
bằng lệnh sau:
CREATE database test_store;
Đảm bảo thao tác thành công bằng cách xác nhận output:
Output
Query OK, 1 row affected (0.00 sec)
Tiếp theo, tạo người dùng cho cơ sở dữ liệu của bạn. Trong bài viết này, chúng ta sẽ gọi người dùng này là test_user. Thay thế PASSWORD
bằng một mật khẩu mạnh hơn:
CREATE USER 'test_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'PASSWORD';
Sau đó cấp các đặc quyền đầy đủ của test_user cho cơ sở dữ liệu test_store
bằng lệnh:
GRANT ALL PRIVILEGES ON test_store.* TO 'test_user'@'localhost';
Cuối cùng chạy lệnh sau để load lại các grant table trong MySQL:
FLUSH PRIVILEGES;
Hãy đảm bảo là bạn nhận được output sau mỗi lệnh như sau:
Output
Query OK, 0 rows affected (0.01 sec)
Kết thúc MySQL root session:
quit;
Bạn sẽ nhận được thông báo Bye
và hệ thống sẽ đưa bạn trở lại command line interface của server.
Đăng nhập lại vào máy chủ MySQL bằng thông tin đăng nhập cho test_user mà bạn vừa tạo:
mysql -u test_user -p
Nhập mật khẩu cho test_user để tiếp tục. Sau đó, chuyển sang cơ sở dữ liệu test_store
khi bạn đang ở trong prompt mysql>
:
USE test_store;
Output sẽ như sau:
Output
Database Changed.
Tiếp theo, bạn sẽ tạo một bảng products
có ba cột. Bạn sẽ sử dụng cột product_id
để nhận dạng duy nhất từng sản phẩm. Để tránh assign ID theo cách thủ công, bạn sẽ sử dụng keyword AUTO_INCREMENT
. Sau đó, bạn sẽ sử dụng kiểu dữ liệu BIGINT
cho cột product_id
để hỗ trợ tập dữ liệu lớn. Loại dữ liệu BIGINT
có thể giữ giá trị tối thiểu là -2^63 và giá trị tối đa là 2^63 – 1.
Field product_name
này sẽ chứa tên thực tế của các mặt hàng của bạn. Trong trường hợp này, một kiểu dữ liệu VARCHAR
có độ dài 50
ký tự là đủ. Cột cuối cùng trong bảng pr
oducts
là price
—bạn sẽ sử dụng loại dữ liệu DOUBLE
để điều chỉnh giá có số thập phân (ví dụ: 16,33).
Để tạo bảng products
, hãy chạy lệnh sau:
CREATE table products
(
product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_name VARCHAR(50),
price DOUBLE
) Engine = InnoDB;
Bạn sẽ nhận được output như sau:
Output
Query OK, 0 rows affected (0.01 sec)
Bây giờ, bạn sẽ điền vào bảng products
một số bản ghi để test thử.
Bạn không cần nhập dữ liệu vào cột product_id
theo cách thủ công vì cột AUTO_INCREMENT
sẽ làm việc này. Lần lượt chạy các lệnh sau:
INSERT INTO products(product_name, price) VALUES ('Virtual Private Servers', '5.00');
INSERT INTO products(product_name, price) VALUES ('Managed Databases', '15.00');
INSERT INTO products(product_name, price) VALUES ('Block Storage', '10.00');
INSERT INTO products(product_name, price) VALUES ('Managed Kubernetes', '60.00');
INSERT INTO products(product_name, price) VALUES ('Load Balancer', '10.00');
Sau khi chạy từng lệnh, đảm bảo bạn nhận được output như sau:
Output
Query OK, 1 row affected (0.00 sec)
Xác minh dữ liệu bằng lệnh SELECT
:
SELECT * FROM products;
Bạn sẽ nhận được output tương tự như sau:
Output
+------------+-------------------------+-------+
| product_id | product_name | price |
+------------+-------------------------+-------+
| 1 | Virtual Private Servers | 5 |
| 2 | Managed Databases | 15 |
| 3 | Block Storage | 10 |
| 4 | Managed Kubernetes | 60 |
| 5 | Load Balancer | 10 |
+------------+-------------------------+-------+
5 rows in set (0.00 sec)
Kết thúc MySQL session cho test_user:
quit;
Khi bạn đã thiết lập cơ sở dữ liệu test_store
, bảng products
và test_user, bạn sẽ code một PHP script để truy xuất dữ liệu từ cơ sở dữ liệu MySQL và cache nó vào Redis.
Bước 3: Thiết kế PHP Script để Fetch và cache dữ liệu MySQL
Trong bước này, bạn sẽ tạo PHP Script để truy xuất dữ liệu mẫu mà bạn đã tạo ở bước trước.
Khi bạn chạy script lần đầu tiên, nó sẽ đọc dữ liệu từ MySQL (nghĩa là từ đĩa) và sau đó lưu vào bộ nhớ cache Redis. Do đó, các lần đọc dữ liệu của sản phẩm tiếp theo sẽ từ Redis (tức là từ RAM hệ thống). Bộ nhớ hệ thống nhanh hơn gấp nhiều lần so với ổ đĩa SSD, do đó dữ liệu sẽ được truy xuất từ cache Redis nhanh hơn so với đọc từ đĩa system.
Lưu ý: Mặc dù bạn có thể không nhận được bất kỳ sự gia tăng hiệu suất nào, vì bạn chỉ đang truy xuất một vài bản ghi từ cơ sở dữ liệu MySQL, nhưng một số điểm chuẩn chứng minh rằng việc truy xuất dữ liệu được lưu trong bộ nhớ cache từ Redis nhanh hơn nhiều lần so với việc đọc nó từ MySQL khi bạn phải xử lý hàng trăm nghìn bản ghi.
Tạo một tệp products.php
trong thư mục gốc của trang web của bạn:
sudo nano /var/www/html/products.php
Để bắt đầu, hãy nhập thông tin sau để kết nối và tạo một instance của Redis và lưu trữ nó dưới dạng một object trong một biến $redis
.
Địa chỉ 127.0.0.1
kết nối với localhost
. Bạn có thể thay đổi giá trị này nếu đang chạy Redis từ một remote server. Hãy nhớ thay thế REDIS_PASSWORD
bằng mật khẩu cụ thể cho Redis được đặt trong tệp cấu hình /etc/redis/redis.conf
.
Ngoài ra, nhập số port thích hợp. Theo mặc định, Redis chạy trên port 6379
:
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('REDIS_PASSWORD');
Lưu ý: Trong hướng dẫn này, lệnh $redis->auth('REDIS_PASSWORD')
sẽ gửi mật khẩu của bạn tới Redis ở dạng văn bản thuần túy. Trong môi trường production, bạn có thể cân nhắc bảo mật end-to-end communication giữa Redis và server của client chạy PHP code bằng layer kiểm soát access mạnh hơn, chẳng hạn như TLS. Ngoài ra, khi định cấu hình mật khẩu Redis của bạn trong tệp /etc/redis/redis.conf
, hãy đảm bảo bạn đặt một giá trị dài và mạnh để ngăn chặn các cuộc tấn công brute-force.
Bước tiếp theo là khởi tạo biến PHP mà bạn sẽ sử dụng làm key trong Redis.
Redis hoạt động như một cơ sở dữ liệu key-value nên do đó bạn phải có một key duy nhất cho dữ liệu mà bạn định lưu trữ và truy xuất từ nó.
Vì vậy, hãy xác định key PRODUCTS
bằng cách thêm thông tin sau vào tệp /var/www/html/products.php
. Bạn có thể sử dụng bất kỳ tên nào thay cho key PRODUCTS
.
PHP script của bạn sẽ sử dụng key này để lưu trữ thông tin vào cache cho Redis sau khi dữ liệu được truy xuất từ cơ sở dữ liệu MySQL:
...
$key = 'PRODUCTS';
Tiếp theo, thêm một câu lệnh PHP có điều kiện if...else
để kiểm tra xem key PRODUCTS
có tồn tại trong Redis hay không:
...
if (!$redis->get($key)) {
$source = 'MySQL Server';
$database_name = 'test_store';
$database_user = 'test_user';
$database_password = 'PASSWORD';
$mysql_host = 'localhost';
$pdo = new PDO('mysql:host=' . $mysql_host . '; dbname=' . $database_name, $database_user, $database_password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT * FROM products";
$stmt = $pdo->prepare($sql);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$products[] = $row;
}
$redis->set($key, serialize($products));
$redis->expire($key, 10);
} else {
$source = 'Redis Server';
$products = unserialize($redis->get($key));
}
echo $source . ': <br>';
print_r($products);
Nếu key không tồn tại trong Redis, script sẽ kết nối với cơ sở dữ liệu mà bạn đã tạo trước đó, truy vấn bảng products
và lưu trữ dữ liệu trong Redis bằng lệnh $redis->set($key, serialize($products))
.
Lệnh $redis->expire($key, 10);
cài đặt hết hiệu lực trong 10
giây. Bạn có thể điều chỉnh giá trị này tùy thuộc vào policy cache của bạn.
Biến $
source
giúp bạn xác định nguồn dữ liệu sau khi nó được lặp lại dưới dạng một mảng ở cuối tập lệnh bằng lệnh echo $source
và print_r($products)
.
Khi bạn đã đặt mọi thứ lại với nhau, tệp /var/www/html/products.php
của bạn sẽ như sau:
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('REDIS_PASSWORD');
$key = 'PRODUCTS';
if (!$redis->get($key)) {
$source = 'MySQL Server';
$database_name = 'test_store';
$database_user = 'test_user';
$database_password = 'PASSWORD';
$mysql_host = 'localhost';
$pdo = new PDO('mysql:host=' . $mysql_host . '; dbname=' . $database_name, $database_user, $database_password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT * FROM products";
$stmt = $pdo->prepare($sql);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$products[] = $row;
}
$redis->set($key, serialize($products));
$redis->expire($key, 10);
} else {
$source = 'Redis Server';
$products = unserialize($redis->get($key));
}
echo $source . ': <br>';
print_r($products);
Lưu và đóng file.
Bước 4: Kiểm tra PHP Script
Để kiểm tra xem Redis có lưu trữ dữ liệu từ cơ sở dữ liệu MySQL hay không, bạn sẽ nhập đường dẫn của PHP Script vào cửa sổ trình duyệt. Hãy nhớ thay thế your_server_IP
bằng địa chỉ IP public của server của bạn như sau: .http://your_server_IP/products.php
Khi bạn chạy tập lệnh lần đầu tiên, bạn sẽ nhận được kết quả sau đây, nó sẽ hiển thị dữ liệu từ cơ sở dữ liệu MySQL, vì tại thời điểm này, PHP script chưa lưu trữ bất kỳ dữ liệu nào trong Redis:
MySQL Server
Array ( [0] => Array ( [product_id] => 1 [product_name] => Virtual Private Servers [price] => 5 ) [1] => Array ( [product_id] => 2 [product_name] => Managed Databases [price] => 15 ) [2] => Array ( [product_id] => 3 [product_name] => Block Storage [price] => 10 ) [3] => Array ( [product_id] => 4 [product_name] => Managed Kubernetes [price] => 60 ) [4] => Array ( [product_id] => 5 [product_name] => Load Balancer [price] => 10 ) )
Khi bạn chạy lại tập lệnh, bạn sẽ nhận được kết quả output xác nhận rằng nó đang đọc dữ liệu từ Redis, và hoạt động như một cache cho MySQL.
Redis Server
Array ( [0] => Array ( [product_id] => 1 [product_name] => Virtual Private Servers [price] => 5 ) [1] => Array ( [product_id] => 2 [product_name] => Managed Databases [price] => 15 ) [2] => Array ( [product_id] => 3 [product_name] => Block Storage [price] => 10 ) [3] => Array ( [product_id] => 4 [product_name] => Managed Kubernetes [price] => 60 ) [4] => Array ( [product_id] => 5 [product_name] => Load Balancer [price] => 10 ) )
Hãy nhớ rằng key sẽ hết hạn sau 10 giây và dữ liệu sẽ được truy xuất lại từ MySQL.
Ngoài ra, để có thể tạo ra một hệ thống hội nghị trực tuyến an toàn và riêng tư bạn nên tìm hiểu thêm cách thiết lập và cấu hình Jitsi Meet trên máy chủ của bạn, để có thể tạo ra các cuộc họp và giao tiếp trực tuyến chất lượng cao.
Lời kết
Trong hướng dẫn này, bạn đã sử dụng Redis làm cache cho MySQL bằng PHP trên Ubuntu 20.04. Bạn có thể sử dụng code trong hướng dẫn này để thiết lập cơ chế lưu vào bộ nhớ cache cho dữ liệu MySQL của mình, cơ chế này đặc biệt hữu ích cho các ứng dụng web có lưu lượng truy cập cao. Cảm ơn bạn đã theo dõi bài viết, nếu bạn thấy hay hãy chia sẻ cho mọi người cùng biết nhé.