Nhân bản máy chủ cơ sở dữ liệu MYSQL với laravel - MySQL Replication
Bài đăng này đã không được cập nhật trong 5 năm
Giới thiệu
Xin chào các bạn! Mình đã quay trở lại rồi đây.
Như bài trước mình đã chia sẻ cách sử dụng object caching để lưu trữ kết quả truy vấn vào cơ sở dữ liệu giúp tăng tốc hoạt động của trang web. Hoạt động của phương pháp này là lần đầu truy xuất cơ sở dữ liệu, kết quả trả về sẽ được lưu vào bộ nhớ có tốc độ đọc nhanh hơn (cache). Lần sau cùng câu truy vấn đấy dữ liệu sẽ được lấy trong cache mà không cần thực hiện truy vấn vào cơ sở dữ liệu. Nhưng khi dữ liệu trở lên rất lớn thì việc thực hiện câu truy vấn lần đầu vẫn rất chậm.
Thông thường thì chúng ta hay cài đặt tất cả mọi thứ (app, database, cache memory, worker,...) vào một máy chủ duy nhất để tiết kiệm chi phí. Để tăng tốc việc truy vấn cơ sở dữ liệu giải pháp đầu tiên cần phải nghĩ đến là nâng cấp máy chủ. Khi đã nâng cấp máy chủ nhưng truy vấn vẫn chậm thì bạn nên tạo cache cho các truy vấn như mình đã giới thiệu trước đó. Khi có cache mà vẫn chậm thì ta sẽ phải tách phần cơ sở dữ liệu ra làm một máy chủ riêng để các thành phần khác của hệ thống không chiếm dụng tài nguyên cho việc truy vấn dữ liệu. Máy chủ cơ sở dữ liệu thông thường sẽ là máy chủ mạnh nhất trong toàn bộ hệ thống trang web.
Khi làm việc này các bạn phải chú ý đến tốc độ truyền tải mạng giữa máy chủ chính và máy chủ cơ sở dữ liệu. Nếu tốc độ truyền tải mạng không đủ nhanh nó sẽ tạo thành nút thắt ở đường truyền thì chúng ta sẽ không thể khai thác hết được tài nguyên của máy chủ cơ sở dữ liệu được tách ra. Thông thường thì 2 máy chủ này phải cần được đặt cùng nhau và sử dụng mạng nội bộ giữa 2 máy để trao đổi dữ liệu giúp cho liên kết vừa nhanh, vừa bảo mật.
Nhưng khi bạn có một dữ liệu rất lớn, một lượng người truy cập khổng lồ, người sử dụng có mặt ở khắp mọi nơi trên thế giới,... thì một máy chủ cơ sở dữ liệu là không đủ để đáp ứng cho hệ thống web hoạt động trơn tru. Lúc này ta phải sử dụng chiêu cuối (ultimate) cực kỳ kinh khủng khiếp. Đó là nhân bản máy chủ cơ sở dữ liệu (Database Replication).
Database Replication là gì?
Nhân bản là tạo một bản sao y hệt bản gốc. Nhân bản máy chủ cơ sở dữ liệu tức là tạo các bản sao máy chủ cơ sở dữ liệu y hệt bản gốc. Nhưng cơ sở dữ liệu thì sẽ bị thay đổi theo thời gian nên việc sao chép giữa hai máy chủ phải được thực hiện liên tục. Như vậy nhân bản cơ sở dữ liệu được hiểu là thường xuyên sao chép dữ liệu từ cơ sở dữ liệu của một máy chủ sang cơ sở dữ liệu của một máy chủ khác.
Trong hệ thống Database Replication sẽ có một máy chủ master và nhiều máy chủ slave. Các máy chủ slave sẽ được nhân bản từ một máy chủ master duy nhất.
Khi thực hiện nhân bản máy chủ cơ sở dữ liệu và thực hiện cân bằng tải (load balancing) để phân phối truy vấn giữa các máy chủ đó thì ta sẽ phục vụ được nhiều truy vấn cùng một lúc hơn. Ví dụ ta có một máy chủ có thể phục vụ được 500 truy vấn cùng một lúc. Nếu ta dựng thêm 4 máy chủ nữa là thành 5 máy chủ có cấu hình tương tự và đặt một hệ thống cân bằng tải ở giữa thì số lượng truy vấn mà hệ thống có thể phục vụ được đồng thời là 5x500 truy vấn.
Bài toán áp dụng
Nhân bản máy chủ cơ sở dữ liệu sẽ hữu ích khi xử lý các bài toán sau:
- Mở rộng khả năng phục vụ của hệ thống: Khi một hệ thống có nhiều người sử dụng, nhiều truy vấn cần được thực thi (đa số là các truy vấn đọc) thì việc nhân bản là cần thiết. Nó sẽ giúp hệ thống phục vụ được nhiều truy vấn hơn từ đó đáp ứng được nhiều người sử dụng hơn. Khi người sử dụng ở nhiều nơi cách xa nhau về địa lý thì việc nhân bản này cũng rất cần thiết. Việc nhân bản sẽ tạo ra nhiều máy chủ. Chúng ta sẽ đặt các máy chủ đó ở gần người dùng hơn giúp người dùng ở xa truy cập hệ thống dễ dàng hơn.
- Giúp cho việc báo cáo phân tích dữ liệu: Một số hệ thống cho phép một số người (người làm báo cáo, thống kê,...) truy cập vào dữ liệu phục vụ cho công việc của họ. Việc truy cập thẳng vào dữ liệu production sẽ rất nguy hiểm vì có thể sẽ vô tình thực thi các câu truy vấn tốn nhiều tài nguyên, thời gian truy vấn dài làm treo hệ thống,... Việc cài đặt một máy chủ làm dữ liệu báo cáo sẽ giải quyết được vấn đề trên.
- Sao lưu cơ sở dữ liệu theo thời gian thực: Thông thường ta sẽ có một giải pháp sao lưu cơ sở dữ liệu offline định kì 1 ngày 1 lần hoặc 1 giờ một lần. Tuy nhiên khi cơ sở dữ liệu chưa được sao lưu mà máy chủ bị lỗi thì dữ liệu bị mất trong 1 giờ hay 1 ngày kia sẽ gây thiệt hại lớn đối với một số hệ thống giao dịch, thanh toán, thương mại điện tử,... Việc tạo các máy chủ nhân bản sẽ đóng vai trò như một cơ sở dữ liệu sao lưu realtime sẽ khắc phục được vấn đề trên.
Chú ý: Nhân bản máy chủ cơ sở dữ liệu không phải là một giải pháp để tăng tốc việc thực hiện câu truy vấn mà nó chỉ giúp hệ thống phục vụ được nhiều người dùng cùng một lúc hơn. Tức là khi hệ thống của bạn chỉ có một người dùng duy nhất thì việc bạn có nhiều máy chủ cơ sở dữ liệu hay chỉ có một máy chủ cùng cấu hình thì tốc độ thực hiện câu truy vấn là như nhau.
Một số mô hình hoạt động
Mô hình database replication thông thường sẽ có 1 máy chủ master để thực hiện ghi (write) dữ liệu và nhiều máy chủ slave thực hiện nhiệm vụ đọc (read) dữ liệu. Các máy chủ slave sẽ tự động đồng bộ dữ liệu của máy chủ master. Tất nhiên máy chủ master cũng có thể đọc được dữ liệu. Trong trường hợp mới ghi dữ liệu vào mà muốn đọc ngay thì sẽ đọc trực tiếp trên master tránh trường hợp slave chưa được đồng bộ.
Mô hình cụm máy chủ web - database
Đây là mô hình có các cụm máy chủ web và database được gộp từng nhóm với nhau. Các máy chủ web sẽ đọc trực tiếp dữ liệu từ máy chủ database mà nó liên kết. Và tất cả các máy chủ web muốn ghi dữ liệu đều phải gửi truy vấn đến máy chủ database master . Mô hình này được sử dụng trong trường hợp người dùng phân bố ở những nơi xa nhau về mặt địa lý. Việc đặt cụm máy chủ web và database gần người dùng hơn sẽ giúp cho việc truy cập dễ dàng hơn.
Mô hình cân bằng tải web, database riêng biệt
Mô hình sử dụng cân bằng tải các truy vấn đến máy chủ cơ sở dữ liệu sẽ giúp phân bổ các truy vấn cho từng máy chủ hợp lý hơn, tránh việc một máy chủ nào đó bị quá tải. Tất nhiên trong mô hình này việc ghi dữ liệu cũng phải thực hiện ở máy chủ cơ sở dữ liệu master.
Laravel và MySQL Replication
Bạn để ý rằng một hệ thống MySQL Replication đều có máy chủ master dùng để đọc hoặc ghi còn các máy chủ slave chỉ được dùng để đọc. Như vậy sẽ có 2 kết nối đến các máy chủ khác nhau. Thao tác thêm (create), sửa (update), xóa (delete) là các thao tác ghi, sẽ được thực hiện trên máy chủ master. Còn thao tác đọc (select) thì có thể được sử dụng trên mọi máy chủ. Trong laravel, bạn có thể cài đặt host
dùng để đọc và host
dùng để ghi một cách riêng rẽ thông qua file cấu hình config/database.php
.
Để hiểu rõ hơn bây giờ chúng ta sẽ đi vào việc cài đặt một hệ thống web đơn giản sử dụng framework laravel và MySQL Replication. Trong hệ thống này mình chỉ cài đặt 2 mysql server (1 master, 1 slave) và 1 laravel server.
Sơ đồ của hệ thống sẽ như sau:
Trong bài viết này mình sử dụng máy chủ chạy hệ điều hành ubuntu 18.04. Đối với những máy chủ có hệ điều hành khác thì cách cài đặt có thể khác nhưng file cấu hình vẫn tương tự.
Cài đặt và cấu hình MySQL Replication
Thông tin 2 máy chủ:
- Hệ điều hành: Ubuntu server 18.04
- Địa chỉ ip:
- master: 10.0.4.4
- slave: 10.0.4.5
- Hệ quản trị cơ sở dữ liệu: MySQL 5.7
Cài đặt mysql
Để cài đặt mysql-server vào máy ta dùng lệnh
sudo apt-get update
sudo apt-get install mysql-server
Kiểm tra phiên bản đã cài đặt
mysql --version
Kiểm tra trạng thái hoạt động
systemctl status mysql.service
Cấu hình MySQL
sudo mysql_secure_installation
Cấu hình MySQL Master Server
Thay đổi tập tin cấu hình /etc/mysql/mysql.conf.d/mysqld.cnf
như sau:
[mysqld]
# Bind to local private network rather than just loopback/localhost
# so others can connect to this server on the private networks
bind-address = 10.0.4.4
# Give the server an ID (any ID is fine)
server-id = 1
# Setup the binlog to be written to:
log-bin = /var/lib/mysql/mysql-bin
sync-binlog = 1
# Enable GTID replication
gtid-mode = ON # Must be "ON", is not a boolean
enforce-gtid-consistency = 1
binlog-format = MIXED
Chúng ta sử dụng binary logging để phục vụ cho việc nhân bản. Binary logging sẽ theo dõi tất cả các truy vấn dẫn đến thay đổi cơ sở dữ liệu.
- Cài đặt
sync-binlog = 1
là để tất cả các transactions sẽ được ghi vào binlog trước khi chúng được committed. Điều này sẽ tránh mất dữ liệu khi máy chủ gặp sự cố. Tuy nhiên hiệu năng hoạt động của máy chủ sẽ giảm đi một chút. Giá trị này có thể được cài đặt cao hơn, được đặt bằng số n chẳng hạn. Ý nghĩa của nó là sau n commits thì MySQL sẽ được ghi vào binlog. Như vậy giá trịsync-binlog
càng cao thì khả năng mất dữ liệu càng lớn nhưng hiệu suất sẽ tăng. enforce-gtid-consistency = 1
là bắt buộc khigtid-mode
được bật (on
).binlog-format
quy định cách mà dữ liệu được ghi vào binlog. Giá trị của nó có thể là: (i) statement Các câu lệnh sẽ được chuyển từmaster
sangslave
(ii) row dữ liệu từng hàng sẽ được chuyển từmaster
sangslave
(iii) mixed kết hợp 2 loại trên, mặc định sẽ làstatement
chuyển sangrow
trong một số tình huống nhất định.
Sau khi thay đổi cấu hình xong thì khởi động lại mysql
sudo service mysql restart
Xem lại các thay đổi trên dùng lệnh sau trong MySQL Command-Line Client
mysql> show variables like '%GTID%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
8 rows in set (0.00 sec)
Tạo user
để phục vụ việc nhân bản. User sẽ được bind với địa chỉ ip của máy slave
. Slave server
sẽ sử dụng user này để truy cập vào master server
.
mysql -u root -p -e "GRANT REPLICATION SLAVE ON *.* TO 'replica'@'10.0.4.5' IDENTIFIED BY 'secret';"
mysql -u root -p -e "FLUSH PRIVILEGES;"
Tiếp theo ta cần sao lưu toàn bộ cơ sở dữ liệu của master server
. Để làm được điều này ta phải cài đặt cho master server
chỉ đọc (read_only
). Sau đó dùng mysqldump
để export toàn bộ cơ sở dữ liệu ra. Cuối cùng là bỏ trạng thái read_only
của master server
. Chi tiết cụ thể như sau:
- Cài đặt chỉ đọc
mysql> FLUSH TABLES WITH READ LOCK;
mysql> SET GLOBAL read_only = ON;
- Export dữ liệu
mysqldump -u root -p --single-transaction --default-character-set=utf8mb4 --all-databases --triggers --routines --events > backup.sql
- Bỏ trạng thái
read_only
mysql> SET GLOBAL read_only = OFF;
mysql> UNLOCK TABLES;
Cấu hình MySQL Slave Server
Thay đổi tập tin cấu hình /etc/mysql/mysql.conf.d/mysqld.cnf
như sau:
[mysqld]
# Bind to local private network rather than just loopback/localhost
# so others can connect to this server on the private networks
bind-address = 10.0.4.5
# BINLOG
log-bin = /var/lib/mysql/mysql-bin
sync-binlog = 1
binlog-format = MIXED
server-id = 2
expire-logs-days = 14
# REPLICATION
gtid-mode = ON
enforce-gtid-consistency = 1
relay-log = /var/lib/mysql/mysql-relay-bin
Sau khi thay đổi cấu hình xong thì khởi động lại mysql
sudo service mysql restart
Để truyền được file từ master
sang slave
ta sử dụng lệnh scp
tải file backup từ master về máy sau đó lại dùng lệnh này để tải file backup từ máy của mình lên server slave.
# download: remote -> local
scp user@remote_host:remote_file local_file
# upload: local -> remote
scp local_file user@remote_host:remote_file
Tiếp theo import dữ liệu từ file dữ liệu backup lên slave server
:
mysql -u root -p < backup.sql
Bắt đầu quá trình nhân bản (replicating) sử dụng 2 lệnh mysql sau:
mysql> CHANGE MASTER TO MASTER_HOST='10.0.4.4',MASTER_USER='replica', MASTER_PASSWORD='secret', MASTER_AUTO_POSITION = 1;
mysql> START SLAVE;
Kiểm tra trạng thái quá trình replication
mysql> SHOW SLAVE STATUS\G
Cài đặt và cấu hình Laravel
Cấu hình máy chủ đọc/ghi cơ sở dữ liệu với laravel rất đơn giản. Ta chỉ cần thay đổi file cấu hình config/database.php
// config/database.php
<?php
return [
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'mysql' => [
'read' => ['host' => env('DB_READ_HOST', '')],
'write' => ['host' => env('DB_HOST', '')],
'sticky' => true,
'driver' => 'mysql',
# 'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
],
];
Và cài đặt thêm biến trong file cấu hình .env
DB_READ_HOST=10.0.4.5
DB_HOST=10.0.4.4
Mình giải thích một chút về cấu hình bên trên:
sticky
được đặt làtrue
nghĩa là khi ghi dữ liệu vào database và đọc ngay thì truy vấn đọc sẽ được thực hiện trực tiếp trênmaster server
. Nó sẽ khắc phục được trường hợp máy chủ master được ghi dữ liệu nhưng máy chủ slave chưa kịp cập nhật dữ liệu dẫn đến khi đọc trên slave dữ liệu có thể chưa được mới nhất.host
trongread
có thể truyền vào một mảng ip nếu bạn có nhiềuscale server
. Laravel sẽ chọn ngẫu nhiên một server trong danh sách để kết nối.
Kết luận
Như vậy chúng ta đã cùng tìm hiểu xong MySQL Replication là gì và cách cấu hình nó, tích hợp nó vào hệ thống sử dụng laravel framework. Bài viết của mình xin kết thúc tại đây. Hi vọng sẽ giúp ích được cho các bạn. Nếu bạn thấy hay thì hãy upvote và chia sẻ cho bạn bè cùng đọc. Đừng quên Follow mình để nhận được thông báo khi mình có bài viết mới nhé. Chúc các bạn có một ngày tốt lành!
All rights reserved