Dự án này là một mô hình backend e-commerce đơn giản, chạy theo kiến trúc:
- 2 API Node.js (
api-node-1,api-node-2) - 1 Nginx load balancer (
nginx-lb) - 1 MySQL Master (
db-master) - 1 MySQL Slave (
db-slave)
Backend được thiết kế theo hướng:
POST /productsghi vào MasterGET /productsđọc từ Slave
Mục tiêu: demo cách vận hành API đa node kết hợp database replication.
.
|-- docker-compose.yaml
|-- README.md
|-- backend/
| |-- app.js
| |-- server.js
| |-- package.json
| |-- Dockerfile
| |-- config/db.js
| |-- controllers/productController.js
| |-- services/productService.js
| |-- repositories/productRepositories.js
| `-- routes/productRoute.js
`-- infrastructure/
|-- nginx/nginx.conf
`-- mysql/
|-- setup-replication.sh
|-- master/
| |-- my.cnf
| `-- init.sql
`-- slave/
`-- my.cnf
Cần cài đặt sẵn:
- Docker Desktop (hoặc Docker Engine + Docker Compose plugin)
- Bash shell (macOS/Linux có sẵn)
Kiểm tra nhanh:
docker --version
docker compose versioncd e-commercedocker compose up -d --builddocker compose psbash infrastructure/mysql/setup-replication.shScript này sẽ tự động:
- Tạo snapshot nhất quán từ Master
- Trích replication coordinates
- Seed dữ liệu vào Slave
CHANGE REPLICATION SOURCE+START REPLICA- In thông tin verify
docker exec e-commerce-db-slave-1 mysql -uroot -proot_password -e "SHOW REPLICA STATUS\\G"Cần thấy:
Replica_IO_Running: YesReplica_SQL_Running: Yes
curl http://localhost/healthLấy danh sách sản phẩm:
curl http://localhost/productsTạo sản phẩm mới:
curl -X POST http://localhost/products \
-H "Content-Type: application/json" \
-d '{"name":"Product D","description":"Description for Product D","price":40.99,"quantity":50}'Gọi lại danh sách để kiểm tra:
curl http://localhost/products- Nginx lắng nghe cổng
80 - Round-robin đến 2 node backend:
api-node-1:3000api-node-2:3000
GET /health: trả về thông tin service/node đang xử lýGET /products: đọc từ MySQL SlavePOST /products: ghi vào MySQL Master
- Master có binary log (
log-bin) và userreplicator - Slave bật
read_only=1và nhận dữ liệu từ Master sau khi chạy script setup
Trong Docker Compose, backend sử dụng:
NODE_NAME=API_NODE_01hoặcAPI_NODE_02DB_MASTER_HOST=db-masterDB_SLAVE_HOST=db-slaveTZ=Asia/Ho_Chi_Minh
Giá trị DB mặc định trong code:
DB_USER=rootDB_PASSWORD=root_passwordDB_NAME=ecommerce-db
Start:
docker compose up -d --buildStop:
docker compose downXem logs tất cả:
docker compose logs -fXem logs riêng backend:
docker compose logs -f api-node-1 api-node-2Xem logs Nginx:
docker compose logs -f nginx-lbKhi cần test lại full flow từ đầu:
docker compose down -v
docker compose up -d --build
bash infrastructure/mysql/setup-replication.shdown -v sẽ xóa volume dữ liệu MySQL.
Chạy lại setup replication:
bash infrastructure/mysql/setup-replication.shNếu vẫn lỗi, xem chi tiết:
docker exec e-commerce-db-slave-1 mysql -uroot -proot_password -e "SHOW REPLICA STATUS\\G"Kiểm tra container:
docker compose psKiểm tra health backend:
docker compose logs -f api-node-1 api-node-2Kiểm tra Nginx:
docker compose logs -f nginx-lbKiểm tra logs MySQL:
docker compose logs -f db-master db-slaveMode này dùng khi cần debug Node.js nhanh trên máy local.
Lưu ý: docker-compose.yaml hiện tại không map cổng MySQL ra host. Vì vậy nếu chạy backend local, cần phải map cổng MySQL hoặc chỉnh compose cho phù hợp.
Lệnh trong backend/:
npm install
npm startResponse mẫu:
{
"status": "ok",
"service": "API_NODE_01",
"timestamp": "2026-04-27T10:00:00.000Z"
}Response mẫu:
{
"products": [
{
"id": 1,
"name": "Product A",
"description": "Description for Product A",
"price": "10.99",
"quantity": 100,
"created_at": "2026-04-27T10:00:00.000Z"
}
],
"metadata": {
"processed_by": "API_NODE_02",
"total_products": 1,
"timestamp": "2026-04-27T10:00:00.000Z"
}
}Request body:
{
"name": "Product X",
"description": "Description X",
"price": 99.99,
"quantity": 10
}Response mẫu:
{
"id": 4,
"name": "Product X",
"description": "Description X",
"price": 99.99,
"quantity": 10
}Nếu cần bổ sung endpoint, monitoring, hoặc CI/CD, có thể mở rộng từ khung dự án trên.