Tối ưu hóa Hiệu suất Backend: Biến API Chậm Thành Siêu Tốc
Hãy tưởng tượng API của bạn phản hồi chậm như một chú rùa, trong khi người dùng mong đợi tốc độ của một chiếc xe đua. Với 2 tỷ bản ghi và yêu cầu hiển thị dữ liệu phức tạp, đã đối mặt với thách thức lớn. Dưới đây là hành trình tối ưu hóa backend, từ phân tích đến triển khai, với kết quả ấn tượng và kế hoạch mở rộng sử dụng Redis caching với cơ chế LRU cho ~150,000 khách hàng ưu tiên, được cá nhân hóa để tối ưu RAM.
Tóm tắt
- Vấn đề: API trả dữ liệu khách hàng chậm, ảnh hưởng trải nghiệm người dùng.
- Giải pháp: Tối ưu database, migrate dữ liệu sang bảng mới với phân vùng, sử dụng export/import CSV, và tích hợp Redis caching với LRU cho nhóm khách hàng ưu tiên.
- Kết quả: Giảm thời gian migrate từ 42 giờ xuống 25.5 giờ cho 1 tỷ bản ghi, cải thiện tốc độ API đáng kể.
1. Yêu cầu từ Frontend
Ứng dụng cần hiển thị dữ liệu khách hàng theo ngày, với biểu đồ so sánh mức độ sử dụng và giá tiền (dạng số) với cùng ngày của tháng trước. Dữ liệu được lấy qua API dựa trên ID khách hàng.
Thách thức: Giảm thời gian phản hồi API để nâng cao trải nghiệm người dùng.
2. Hiện trạng hệ thống
2.1. Tình trạng hạ tầng
- Server:
- RAM: 64GB, sử dụng ~64% (~41GB) trong giờ cao điểm, còn ~23GB trống.
- Disk: 2TB, đã sử dụng 600GB, còn trống ~1.4TB.
- Tốc độ disk:
- Ghi: 46.9 MB/s.
- Đọc: 149 MB/s.
- Database: MariaDB 10.4.24.
- Tình trạng: Slow query log cho thấy truy vấn vào bảng dữ liệu chậm, dù đã tối ưu index trên cặp (mã khách hàng, ngày tháng năm).
2.2. Quy mô dữ liệu
- Người dùng: 1.5 triệu khách hàng, mỗi khách hàng có 1 bản ghi/ngày.
- Dữ liệu: ~2 tỷ bản ghi từ 2021, cập nhật hàng ngày qua hai job (mức độ sử dụng và giá tiền).
- Kết luận: Cần tối ưu database để tăng tốc API.
3. Phân tích và giải pháp
3.1. Đánh giá dữ liệu
Phát hiện:
- Chỉ cần dữ liệu 2 năm gần nhất (~1 tỷ bản ghi) cho hiển thị và so sánh, trong khi bảng hiện tại lưu 4 năm dữ liệu, gây lãng phí tài nguyên.
- Bảng bị phân mảnh nghiêm trọng (data_free/data_length > 0.5, trong khi mức an toàn là ≤ 0.2).
Giải pháp:
- Partitioning: Chia bảng theo tháng/năm, mỗi partition chứa ~41.7 triệu bản ghi (1/24 tổng dữ liệu). Điều này giảm kích thước dữ liệu truy vấn, tăng tốc API.
- Tạo bảng mới: Thay vì tối ưu bảng cũ (rủi ro khóa bảng), tạo bảng mới với phân vùng từ đầu. Lệnh
OPTIMIZE TABLE
không khả thi do dữ liệu lớn và thời gian khóa bảng dài.
3.2. Tính toán tài nguyên
- Dung lượng:
- 1 tỷ bản ghi × 480 bytes = 480GB (raw data).
- InnoDB overhead (~30%): 624GB.
- Temporary space (~20%): Tổng ~748.8GB.
- Disk trống (~1.4TB) đủ cho dữ liệu và file tạm.
- Thời gian lý thuyết:
- Đọc: 480GB / 149MB/s ≈ 55 phút.
- Ghi: 624GB / 47MB/s ≈ 3.9 giờ.
- Tổng: ~5-6 giờ (thực tế có overhead).
- Batch size: Sử dụng 50% tốc độ ghi (~23MB/s) → ~48,000 bản ghi/batch để tránh quá tải (~23GB RAM trống đủ cho buffer pool và Redis).
3.3. So sánh các phương án migrate
Chúng tôi thử nghiệm ba phương án để migrate 1 tỷ bản ghi, với mục tiêu tối ưu thời gian và giảm tải hệ thống.
a. Stored Procedure
- Cách làm: Migrate theo batch, tối ưu bằng điều kiện
WHERE
trênid
vàdate
để tránh quét toàn bảng. - Kết quả:
- Test 1 ngày (~1.4 triệu bản ghi): 2m10s với batch 100,000.
- 1 tháng (~42 triệu bản ghi): ~1h15p.
- 2 năm: ~30h.
- Ưu điểm: Linh hoạt, kiểm soát tốt, tận dụng tài nguyên DB (64GB RAM, 149MB/s đọc).
- Nhược điểm: Chậm hơn CSV do xử lý từng batch.
b. Mysqldump
- Cách làm: Dump dữ liệu ra file SQL và import vào bảng mới.
- Kết quả: 1.4 triệu bản ghi trong 3m27s → 2 năm: ~42h.
- Nhược điểm: Chậm hơn CSV, không tối ưu cho dữ liệu lớn.
c. Export/Import CSV
- Cách làm: Export dữ liệu ra file CSV (nén thành .gz), import vào bảng mới theo partition.
- Kết quả:
- Export: 7.245s cho 1.4 triệu bản ghi → 2 năm: ~1h26p.
- Import: 1m58s cho 1.4 triệu bản ghi → 2 năm: ~24h.
- Tổng: ~25.5h.
- Cải tiến: Nén file thành .gz để tiết kiệm dung lượng (~1.4TB disk trống đủ chứa).
- Quy trình:
- Export 24 tháng thành 24 file CSV (chia 4 lần, mỗi lần 6 tháng).
- Import từng file vào bảng mới theo partition.
- Kết luận: CSV nhanh nhất, phù hợp nhất cho dữ liệu lớn.
Các bước quy trình:
- Bước 1: Tạo bảng mới(partition theo tháng)
- Bước 2: Export CSV(24 tháng, chia làm 4 lần)
- Bước 3: Import CSV(vào bảng mới)"
- Bước 4: Rebuild partition
- Bước 5: Trỏ service vào bảng mới
- Bước 6: Backup & xóa dữ liệu cũ
3.4. Tối ưu cấu hình MySQL
- Mục tiêu: Tận dụng 64GB RAM (~23GB trống) và tốc độ disk (149MB/s đọc, 46.9MB/s ghi) để tăng hiệu quả đọc/ghi và giảm tranh chấp lock.
- Cải tiến:
- Tăng
innodb_buffer_pool_size
lên 20GB để lưu trữ dữ liệu và index trong RAM, giảm I/O disk. - Đặt
innodb_io_capacity = 2000
vàinnodb_io_capacity_max = 4000
để tối ưu hóa I/O song song, phù hợp với tốc độ ghi 46.9MB/s. - Sử dụng
innodb_flush_log_at_trx_commit = 1
để đảm bảo mỗi transaction được flush vào disk ngay lập tức, tăng tính toàn vẹn dữ liệu. - Bật/tắt kiểm tra khóa (
ENABLE KEYS
/DISABLE KEYS
) khi import để tăng tốc, sau đó bật lại để đảm bảo toàn vẹn index. - Đặt
autocommit = 1
,unique_checks = 1
,foreign_key_checks = 1
mặc định để đảm bảo tính toàn vẹn dữ liệu sau khi hoàn tất migrate. - Sử dụng các lệnh
SET GLOBAL
để thiết lập các tham số mà không cần sửa file cấu hình, cho phép áp dụng ngay lập tức mà không cần restart server.
- Tăng
- Lợi ích: Tăng hiệu suất đọc/ghi, giảm thời gian import, đảm bảo an toàn dữ liệu, và tăng tính linh hoạt khi điều chỉnh cấu hình.
3.5. Xử lý dữ liệu
- Dữ liệu mới: Trỏ service ghi vào bảng mới.
- Dữ liệu cũ (>2 năm):
- Backup ra file .gz, lưu trữ trên server khác (~1.4TB disk trống đủ chứa).
- Xóa dần theo batch, tương tự quy trình migrate.
- Giám sát: Sử dụng Prometheus/Grafana để theo dõi I/O, CPU, RAM, với cảnh báo khi RAM vượt 80% (~51GB).
4. Mở rộng: Sử dụng Redis Caching
Để tăng tốc API hơn nữa, chúng tôi đề xuất tích hợp Redis caching cho các truy vấn lặp lại từ frontend, với cơ chế LRU áp dụng cho ~150,000 khách hàng ưu tiên.
4.1. Tại sao chọn Redis?
- Tốc độ: Redis lưu trữ dữ liệu trong RAM (~23GB trống đủ sức chứa cache).
- Giảm tải database: Các truy vấn so sánh dữ liệu khách hàng (theo ngày, tháng trước, năm trước) được cache, giảm truy vấn MariaDB.
- Khả năng mở rộng: Redis hỗ trợ cluster, phù hợp nếu dữ liệu tăng.
4.2. Chiến lược caching
- Dữ liệu cache:
- Kết quả API cho từng mã khách hàng, ngày cụ thể, và so sánh với tháng/năm trước.
- Ví dụ: Cache key
customer:{customer_id}:date:{yyyy-mm-dd}
chứa mức độ sử dụng và giá tiền.
- TTL (Time To Live): ~24 giờ, vì dữ liệu cập nhật hàng ngày.
- Cơ chế invalidate: Xóa cache khi job cập nhật dữ liệu chạy (dùng
DEL
hoặc pattern matching vớiKEYS customer:{customer_id}*
). - Dung lượng cache:
- Tập trung vào ~150,000 khách hàng ưu tiên (10% của 1.5 triệu khách hàng).
- 150,000 khách hàng × 1KB/cache ≈ 150MB.
- Sử dụng ~200MB RAM (~0.9% của 23GB trống).
4.3. Quy trình
- Kiểm tra Redis cache trước khi query database.
- Nếu cache miss, query MariaDB, lưu kết quả vào Redis với TTL (chỉ cho khách hàng ưu tiên).
- Job cập nhật dữ liệu sẽ invalidate cache liên quan.
4.4. Lợi ích dự kiến
- Tăng tốc API: Giảm thời gian phản hồi từ hàng giây xuống mili-giây cho các khách hàng ưu tiên.
- Giảm tải database: Redis sử dụng ~200MB RAM, gần như không ảnh hưởng đến tài nguyên hệ thống (~41GB RAM sử dụng giờ cao điểm).
- Dễ triển khai: Redis nhẹ, dễ tích hợp với server hiện tại.
4.5. Lưu ý triển khai
- Giám sát: Dùng Redis Sentinel hoặc Prometheus để theo dõi hit/miss ratio và RAM usage.
- Xử lý lỗi: Thêm fallback để query database nếu Redis gặp sự cố.
4.6. Cân nhắc sử dụng LRU Cache
- Mục tiêu: Tối ưu hóa sử dụng RAM (~23GB trống) bằng cách áp dụng cơ chế LRU (Least Recently Used) để chỉ cache dữ liệu của ~150,000 khách hàng ưu tiên (10% của 1.5 triệu khách hàng).
- Cách xác định khách hàng ưu tiên:
-
Dựa trên tần suất truy cập (ví dụ: khách hàng có truy vấn API trong 30 ngày gần nhất).
-
Sử dụng truy vấn phân tích từ MariaDB để chọn nhóm khách hàng tích cực:
SELECT customer_id FROM access_log WHERE access_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY customer_id HAVING COUNT(*) > 5;
-
Danh sách khách hàng ưu tiên được cập nhật định kỳ (ví dụ: hàng ngày qua job).
-
- Cách hoạt động:
- Redis tự động loại bỏ các key ít được truy cập nhất khi RAM đạt giới hạn (
maxmemory
). - Ví dụ: Chỉ cache key
customer:{customer_id}:date:{yyyy-mm-dd}
cho 150,000 khách hàng ưu tiên, ưu tiên dữ liệu của những khách hàng truy cập thường xuyên (ví dụ: khách hàng có giao dịch hàng ngày).
- Redis tự động loại bỏ các key ít được truy cập nhất khi RAM đạt giới hạn (
- Cấu hình LRU:
- Sử dụng chính sách
allkeys-lru
: Loại bỏ key ít được sử dụng nhất trong toàn bộ key set. - Cấu hình:
CONFIG SET maxmemory-policy allkeys-lru
vàCONFIG SET maxmemory 200m
.
- Sử dụng chính sách
- Lợi ích:
- Giảm RAM sử dụng: Chỉ cần ~200MB (~0.9% của 23GB trống), so với 2GB cho 1.5 triệu khách hàng, tiết kiệm đáng kể tài nguyên cho MySQL buffer pool (~20GB).
- Tối ưu hiệu suất: Tăng tỷ lệ cache hit bằng cách tập trung vào khách hàng tích cực, đảm bảo API phản hồi nhanh cho nhóm người dùng quan trọng.
- Tính linh hoạt: Nếu số khách hàng ưu tiên tăng (ví dụ: lên 300,000), chỉ cần điều chỉnh
maxmemory
lên ~400MB, vẫn trong khả năng của RAM trống.
- Lưu ý triển khai:
- Theo dõi tỷ lệ cache hit/miss qua
INFO STATS
để đánh giá hiệu quả LRU. - Đặt
maxmemory
hợp lý (~200MB) để cân bằng giữa Redis và MySQL buffer pool. - Định kỳ cập nhật danh sách khách hàng ưu tiên để đảm bảo cache luôn tập trung vào dữ liệu quan trọng.
- Nếu tỷ lệ cache miss cao, xem xét tăng
maxmemory
(ví dụ: lên 300MB) hoặc mở rộng nhóm khách hàng ưu tiên.
- Theo dõi tỷ lệ cache hit/miss qua
4.7. Áp dụng LRU trong Source Code Kết Hợp với Redis
- Mục tiêu: Cá nhân hóa cơ chế LRU cache bằng cách tích hợp logic kiểm tra khách hàng ưu tiên trong source code của ứng dụng backend, đảm bảo chỉ cache dữ liệu của ~150,000 khách hàng tích cực để tối ưu hiệu suất và RAM.
- Cách thực hiện:
- Xác định khách hàng ưu tiên:
- Truy vấn bảng
access_log
trong MariaDB để lấy danh sách ~150,000 khách hàng có tần suất truy cập cao (>5 lần trong 30 ngày gần nhất), như đã mô tả trong mục 4.6. - Lưu danh sách này trong bộ nhớ ứng dụng (ví dụ: một hash map hoặc cấu trúc dữ liệu tương tự) hoặc trong Redis dưới dạng một set (
SADD priority_customers {customer_id}
) để kiểm tra nhanh. - Cập nhật danh sách định kỳ (hàng ngày hoặc hàng giờ) qua một job riêng, đảm bảo danh sách luôn phản ánh đúng nhóm khách hàng tích cực.
- Truy vấn bảng
- Quản lý cache trong source code:
- Khi API nhận yêu cầu dữ liệu cho một khách hàng (với
customer_id
vàdate
), kiểm tra xemcustomer_id
có trong danh sách ưu tiên không. - Nếu không phải khách hàng ưu tiên, bỏ qua Redis và query trực tiếp MariaDB để lấy dữ liệu (mức độ sử dụng, giá tiền).
- Nếu là khách hàng ưu tiên:
- Tạo cache key theo định dạng
customer:{customer_id}:date:{yyyy-mm-dd}
. - Kiểm tra Redis xem key này có tồn tại không (sử dụng lệnh
GET
). - Nếu cache hit, trả về dữ liệu từ Redis ngay lập tức.
- Nếu cache miss, query MariaDB, serialize kết quả thành JSON, và lưu vào Redis với TTL 24 giờ (sử dụng
SETEX
).
- Tạo cache key theo định dạng
- Dữ liệu cache chỉ chiếm ~200MB RAM, nhờ giới hạn ở ~150,000 khách hàng và cơ chế LRU của Redis tự động loại bỏ key ít truy cập khi bộ nhớ đầy.
- Khi API nhận yêu cầu dữ liệu cho một khách hàng (với
- Invalidation cache:
- Khi job cập nhật dữ liệu khách hàng chạy (hàng ngày), xóa các cache liên quan đến khách hàng đó.
- Sử dụng pattern matching với lệnh
KEYS customer:{customer_id}:date:*
hoặcSCAN
để tìm và xóa tất cả key liên quan (vớiDEL
). - Để tối ưu, có thể dùng Lua script trong Redis để thực hiện xóa hàng loạt, giảm số lần gọi mạng.
- Tích hợp với LRU của Redis:
- Ứng dụng không cần tự triển khai thuật toán LRU, mà tận dụng cơ chế
allkeys-lru
của Redis (đã cấu hình trong mục 6.11). - Redis tự động theo dõi tần suất truy cập các key và loại bỏ key ít dùng nhất khi bộ nhớ đạt
maxmemory
(~200MB). - Source code chỉ cần đảm bảo key được tạo đúng định dạng và chỉ lưu cho khách hàng ưu tiên.
- Ứng dụng không cần tự triển khai thuật toán LRU, mà tận dụng cơ chế
- Xử lý lỗi:
- Nếu Redis không khả dụng, ứng dụng fallback về query MariaDB trực tiếp, đảm bảo API vẫn hoạt động.
- Log lỗi Redis (ví dụ: timeout, connection refused) để giám sát và xử lý sau.
- Đảm bảo ứng dụng xử lý trường hợp danh sách khách hàng ưu tiên không tải được (ví dụ: dùng danh sách cũ hoặc query MariaDB tạm thời).
- Xác định khách hàng ưu tiên:
- Lợi ích:
- Cá nhân hóa: Chỉ cache dữ liệu của khách hàng tích cực, tăng tỷ lệ cache hit và giảm thời gian phản hồi API cho nhóm người dùng quan trọng.
- Tối ưu RAM: Giới hạn ~200MB (~0.9% của 23GB trống), để lại nhiều tài nguyên cho MySQL buffer pool (~20GB).
- Hiệu quả: Tận dụng LRU của Redis giúp quản lý bộ nhớ tự động, giảm phức tạp trong source code.
- Tích hợp dễ dàng: Logic kiểm tra ưu tiên và quản lý cache có thể triển khai trong bất kỳ ngôn ngữ nào (Golang, Python, Java, v.v.) với thư viện Redis phù hợp.
- Lưu ý triển khai:
- Đảm bảo Redis được cấu hình với
maxmemory 200m
vàallkeys-lru
(xem mục 6.11). - Giám sát tỷ lệ cache hit/miss qua lệnh
INFO STATS
để đánh giá hiệu quả. - Cập nhật danh sách khách hàng ưu tiên định kỳ, tránh để danh sách lỗi thời làm giảm hiệu quả cache.
- Nếu tỷ lệ cache miss cao, xem xét tăng
maxmemory
(ví dụ: lên 300MB) hoặc điều chỉnh tiêu chí ưu tiên (ví dụ: giảm ngưỡng từ >5 xuống >3 truy vấn). - Kiểm tra hiệu suất truy vấn
access_log
để lấy danh sách ưu tiên, tối ưu index nếu cần. - Sử dụng connection pooling cho cả Redis và MariaDB để giảm overhead kết nối.
- Đảm bảo Redis được cấu hình với
5. Kết quả và bài học kinh nghiệm
- Kết quả:
- Migrate 1 tỷ bản ghi trong ~25.5 giờ (CSV).
- API nhanh hơn đáng kể nhờ partitioning và cấu hình MySQL.
- Redis caching với LRU cho ~150,000 khách hàng ưu tiên, tích hợp logic cá nhân hóa trong source code, hứa hẹn giảm thời gian phản hồi API và tối ưu RAM.
- Bài học:
- Partitioning là chìa khóa cho dữ liệu lớn.
- CSV hiệu quả nhất cho migrate dữ liệu.
- Backup, giám sát, và caching (đặc biệt với LRU cá nhân hóa) là yếu tố sống còn.
6. Các Command Sử dụng
6.1. Kiểm tra phân mảnh
SELECT table_schema, table_name, data_length/1024/1024 AS data_MB, index_length/1024/1024 AS index_MB, data_free/1024/1024 AS free_MB
FROM information_schema.TABLES
WHERE table_schema='schema' AND engine='InnoDB' AND data_free/data_length > 0.2;
6.2. Partition Schema
ALTER TABLE my_table
PARTITION BY RANGE COLUMNS(`date`) ( PARTITION p202305 VALUES LESS THAN ('2023-06-01'), PARTITION p202306 VALUES LESS THAN ('2023-07-01'), ... PARTITION p202504 VALUES LESS THAN ('2025-05-01'), PARTITION p_future VALUES LESS THAN MAXVALUE
) ENGINE = InnoDB;
6.3. Stored Procedure Migrate (Test 1 ngày)
DELIMITER //
CREATE PROCEDURE test_clone_1d()
BEGIN DECLARE i BIGINT DEFAULT 0; DECLARE batch_size INT DEFAULT 100000; DECLARE max_id BIGINT; SET SESSION autocommit = 0; SET SESSION unique_checks = 0; SET SESSION foreign_key_checks = 0; SELECT MAX(id) INTO max_id FROM old_table WHERE `date` BETWEEN '2025-05-29' AND '2025-05-30'; WHILE i < max_id DO START TRANSACTION; INSERT INTO new_table (SELECT * FROM old_table WHERE `date` BETWEEN '2025-05-29' AND '2025-05-30' AND id > i AND id <= i + batch_size) ON DUPLICATE KEY UPDATE id = DEFAULT; SET i = i + batch_size; COMMIT; DO SLEEP(0.05); END WHILE; SET SESSION autocommit = 1; SET SESSION unique_checks = 1; SET SESSION foreign_key_checks = 1;
END //
DELIMITER ;
6.4. Mysqldump
mysqldump -u dev_point -p schema old_table --where="id <= 1400000" --no-create-info --skip-triggers --compact > old_table.sql
mysql -u dev_point -p schema -e "SET autocommit=0; SET unique_checks=0; SET foreign_key_checks=0; SOURCE old_table.sql; COMMIT;"
6.5. Export CSV
SELECT * INTO OUTFILE '/var/lib/mysql/data.csv.gz'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\' LINES TERMINATED BY '\n'
FROM schema.old_table WHERE id <= 1400000;
6.6. Import CSV
LOAD DATA INFILE '/var/lib/mysql/data.csv.gz' INTO TABLE schema.new_table
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\' LINES TERMINATED BY '\n';
6.7. Stored Procedure Export CSV theo tháng
DELIMITER //
CREATE PROCEDURE export_last_24_months_data()
BEGIN DECLARE i INT DEFAULT 0; DECLARE current_month_start_date DATE; DECLARE export_year VARCHAR(4); DECLARE export_month VARCHAR(2); DECLARE file_name VARCHAR(255); DECLARE sql_query TEXT; SET @base_export_path = '/var/lib/mysql/'; SET @secure_file_priv = (SELECT @@secure_file_priv); IF @secure_file_priv IS NOT NULL AND @base_export_path NOT LIKE CONCAT(@secure_file_priv, '%') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Export path does not match secure_file_priv'; END IF; WHILE i < 24 DO SET current_month_start_date = DATE_SUB(CURDATE(), INTERVAL i MONTH); SET export_year = YEAR(current_month_start_date); SET export_month = LPAD(MONTH(current_month_start_date), 2, '0'); SET file_name = CONCAT('old_table_', export_year, '_', export_month, '.csv.gz'); SET sql_query = CONCAT( 'SELECT * INTO OUTFILE \'', @base_export_path, file_name, '\' ', 'FIELDS TERMINATED BY \',\' OPTIONALLY ENCLOSED BY \'"\' ESCAPED BY \'\\\\\' LINES TERMINATED BY \'\\n\' ', 'FROM old_table ', 'WHERE YEAR(day) = ', export_year, ' AND MONTH(day) = ', export_month, ';' ); PREPARE stmt FROM sql_query; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET i = i + 1; END WHILE;
END //
DELIMITER ;
6.8. Cấu hình MySQL
[mysqld]
innodb_buffer_pool_size = 20G
innodb_log_buffer_size = 1G
innodb_buffer_pool_instances = 8
innodb_read_io_threads = 16
innodb_write_io_threads = 16
innodb_adaptive_flushing = ON
innodb_io_capacity = 2000
innodb_io_capacity_max = 4000
innodb_flush_log_at_trx_commit = 1
max_allowed_packet = 1G
bulk_insert_buffer_size = 1G
autocommit = 1
unique_checks = 1
foreign_key_checks = 1
6.9. Bật kiểm tra khóa sau import
ALTER TABLE new_table ENABLE KEYS;
6.10. Thiết lập tham số MySQL qua SET GLOBAL
SET GLOBAL innodb_io_capacity = 2000;
SET GLOBAL innodb_io_capacity_max = 4000;
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
SET GLOBAL autocommit = 1;
SET GLOBAL unique_checks = 1;
SET GLOBAL foreign_key_checks = 1;
6.11. Cấu hình Redis
# Thiết lập giới hạn bộ nhớ tối đa cho Redis (~200MB cho ~150,000 khách hàng ưu tiên)
CONFIG SET maxmemory 200m # Thiết lập chính sách loại bỏ key theo LRU (Least Recently Used)
CONFIG SET maxmemory-policy allkeys-lru # Kiểm tra trạng thái cache (hit/miss ratio, bộ nhớ sử dụng)
INFO STATS
7. Kết luận
Từ một API chậm chạp, chúng tôi đã xây dựng một hệ thống backend hiệu suất cao với partitioning, tối ưu MySQL, và phương án CSV. Kế hoạch tích hợp Redis caching với cơ chế LRU cho ~150,000 khách hàng ưu tiên, được cá nhân hóa trong logic ứng dụng, sẽ đưa hiệu suất lên tầm cao mới, đồng thời tối ưu RAM. Chỉ bằng các cách tiếp cận tương tự – như partitioning, migrate dữ liệu hiệu quả, và caching thông minh – rất nhiều service khác đã được tối ưu, từ các hệ thống phân tích dữ liệu lớn đến các API thời gian thực. Nếu bạn đang vật lộn với dữ liệu lớn, hãy thử quy trình này – chỉ cần nhớ backup, giám sát, và tận dụng caching!