Amazon Aurora MySQL Bài 10: Kết nối ứng dụng Backend (Node.js/Go/PHP) vào Aurora MySQL an toàn và hiệu quả
Sau khi đã dựng xong cụm Aurora MySQL và hiểu rõ cách phân định Writer/Reader Endpoint, bước tiếp theo là kết nối từ các ứng dụng backend thực tế. Đối với một Backend Engineer làm việc với nhiều ngôn ngữ, việc thiết lập chuỗi kết nối chuẩn xác, quản lý Connection Pool thông minh và xử lý cơ chế tự động kết nối lại (Reconnect) khi Failover là chìa khóa giúp hệ thống không bị sập nguồn khi database biến động.
Bài viết này sẽ hướng dẫn cách cấu hình kết nối tối ưu cho 3 ngôn ngữ phổ biến: Go (Golang), PHP (Laravel), và Node.js.
1. Nguyên tắc vàng khi kết nối Aurora MySQL từ Backend
-
Tách biệt Write Connection và Read Connection: Trỏ Write qua Cluster Endpoint và Read qua Reader Endpoint.
-
Quản lý Connection Pool cẩn trọng: Do Aurora có thể thay đổi node khi Failover, việc giữ connection pool vô thời hạn mà không có cơ chế timeout/ping kiểm tra kết nối có thể dẫn đến lỗi
Lost connection to MySQL server during query. -
Retry Mechanism (Tự động thử lại): Khi xảy ra Failover, thời gian downtime diễn ra trong vài giây. Ứng dụng cần có logic bắt lỗi kết nối và retry lại 2-3 lần thay vì trả thẳng lỗi 500 ra cho người dùng.
2. Cấu hình kết nối trong Go (Golang) sử dụng database/sql và GORM
Trong Go, chúng ta sử dụng thư viện database/sql kết hợp với driver go-sql-driver/mysql hoặc ORM như GORM. Ta nên cấu hình hai instance database riêng biệt trong struct config:
Go
package database
import (
"database/sql"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
type AuroraCluster struct {
Writer *sql.DB
Reader *sql.DB
}
func ConnectAurora(writerDSN, readerDSN string) *AuroraCluster {
// Kết nối Writer Database
writerDB, err := sql.Open("mysql", writerDSN)
if err != nil {
log.Fatalf("Failed to connect to Aurora Writer: %v", err)
}
configurePool(writerDB)
// Kết nối Reader Database
readerDB, err := sql.Open("mysql", readerDSN)
if err != nil {
log.Fatalf("Failed to connect to Aurora Reader: %v", err)
}
configurePool(readerDB)
return &AuroraCluster{
Writer: writerDB,
Reader: readerDB,
}
}
func configurePool(db *sql.DB) {
// Thiết lập giới hạn connection pool để tránh quá tải
db.SetMaxOpenConns(50)
db.SetMaxIdleConns(10)
// Quan trọng: Đặt thời gian sống tối đa của connection để làm mới DNS/IP sau Failover
db.SetConnMaxLifetime(time.Minute * 30)
}
Chuỗi DSN mẫu: admin_hieu:Password123@tcp(hieu-aurora-cluster.cluster-xxx.us-east-1.rds.amazonaws.com:3306)/hieu_ecommerce?parseTime=true&charset=utf8mb4&timeout=5s
3. Cấu hình kết nối trong PHP (Laravel Framework)
Trong Laravel, file cấu hình .env và config/database.php hỗ trợ cấu hình đa kết nối (Read/Write Splitting) một cách cực kỳ mượt mà.
Trong tệp .env:
Đoạn mã
DB_CONNECTION=mysql
DB_HOST=hieu-aurora-cluster.cluster-xxx.us-east-1.rds.amazonaws.com # Cluster Endpoint (Writer)
DB_READ_HOST=hieu-aurora-cluster.cluster-ro-xxx.us-east-1.rds.amazonaws.com # Reader Endpoint
DB_PORT=3306
DB_DATABASE=hieu_ecommerce
DB_USERNAME=admin_hieu
DB_PASSWORD=Password123
Trong tệp config/database.php:
PHP
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'read' => [
'host' => env('DB_READ_HOST', env('DB_HOST')),
],
'write' => [
'host' => env('DB_HOST'),
],
'sticky' => true, // Quan trọng: Đảm bảo sau khi write, các request đọc tiếp theo trong cùng request HTTP sẽ đọc từ Writer để tránh độ trễ replication lag ngay lập tức
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::ATTR_PERSISTENT => false, // Tránh dùng persistent connection cố định gây lỗi khi failover
PDO::ATTR_TIMEOUT => 5,
]) : [],
],
4. Cấu hình kết nối trong Node.js (Prisma / TypeORM / mysql2)
Đối với Node.js, khi sử dụng thư viện mysql2 hoặc các ORM như Prisma, việc cấu hình pool kết nối đi kèm cơ chế tự động reconnect rất quan trọng:
JavaScript
const mysql = require('mysql2');
// Tạo Pool cho Writer (Cluster Endpoint)
const writePool = mysql.createPool({
host: 'hieu-aurora-cluster.cluster-xxx.us-east-1.rds.amazonaws.com',
user: 'admin_hieu',
password: 'Password123',
database: 'hieu_ecommerce',
waitForConnections: true,
connectionLimit: 20,
queueLimit: 0,
enableKeepAlive: true,
keepAliveInitialDelay: 10000
});
// Tạo Pool cho Reader (Reader Endpoint)
const readPool = mysql.createPool({
host: 'hieu-aurora-cluster.cluster-ro-xxx.us-east-1.rds.amazonaws.com',
user: 'admin_hieu',
password: 'Password123',
database: 'hieu_ecommerce',
waitForConnections: true,
connectionLimit: 50,
queueLimit: 0,
enableKeepAlive: true
});
module.exports = { writePool, readPool };
5. Góc nhìn vận hành cho Backend Engineer
-
Tính năng
stickytrong Laravel: Hãy luôn bật cấu hình'sticky' => truenếu dùng Laravel Read/Write splitting. Tính năng này giúp khi một user thực hiện hành động Ghi (ví dụ: đăng ký tài khoản, cập nhật giỏ hàng), các câu lệnh Đọc ngay sau đó trong cùng một phiên làm việc sẽ được điều hướng tạm thời sang Writer, ngăn chặn hoàn toàn việc người dùng vừa bấm lưu xong tải lại trang mà chưa thấy dữ liệu do lệch pha vài mili-giây. -
Tránh Persistent Connections mù quáng: Không nên lạm dụng kết nối bền vững (
persistent connection) ở mức cực đoan vì khi Aurora thực hiện failover chuyển đổi IP backend, các kết nối cũ bị kẹt sẽ gây tràn lỗi kết nối (Too many connections).
All rights reserved