6 thuật toán Load Balancing mà dev nào cũng nên biết
Hầu hết developer không bao giờ chọn load balancing algorithm. Họ dùng mặc định cho đến khi hệ thống sập. Đây là 6 thuật toán bạn cần nắm.
Nguyễn Nhật Long
@nguyennhatlong1303

Mình từng debug một incident lúc 2 giờ sáng. Hệ thống 4 con server, CPU một con đang cháy 98%, ba con còn lại ngồi chơi ở mức 15%. Traffic không hề tăng đột biến. Nguyên nhân? Load balancer đang dùng Round Robin, nhưng một số request xử lý file upload nặng gấp 50 lần request thường. "Chia đều" không có nghĩa là "tải đều".
Chuyện này dạy mình một bài: hầu hết dev không bao giờ chủ động chọn load balancing algorithm. Chúng ta inherit cái default, deploy lên, rồi quên luôn — cho đến khi hệ thống gặp vấn đề.
Load balancer làm gì?
Đơn giản thôi: nó ngồi giữa user và server, quyết định request nào đi vào server nào. Thuật toán nó dùng quyết định cách ra quyết định đó.
Nghe thì đơn giản, nhưng chọn sai algorithm có thể biến hệ thống 10 server thành hệ thống 1 server — vì 9 con còn lại chẳng ai thèm gửi traffic tới.

Dưới đây là 6 thuật toán mà theo mình, mọi backend developer đều nên hiểu rõ.
Nhóm 1: Static — Chia theo luật cố định
Round Robin
Request đầu → Server A. Request tiếp → Server B. Tiếp nữa → Server C. Rồi quay lại A. Cứ thế xoay vòng.
Đây là algorithm đơn giản nhất, và cũng là default phổ biến nhất. Nginx mặc định dùng cái này.
Nó hoạt động tốt khi hai điều kiện thỏa mãn: các server có cấu hình giống nhau, và các request tốn chi phí xử lý tương đương nhau. Trả về một cái JSON response 200 bytes? Ổn. Nhưng nếu request A trả JSON còn request B download file 500MB thì Round Robin sẽ cho bạn cái cảm giác "chia đều" trong khi thực tế một con server đang gánh nặng gấp mấy lần.
Theo kinh nghiệm của mình, Round Robin chỉ thực sự phù hợp với stateless API đơn giản, nơi mỗi request xử lý dưới 100ms và không có request nào nặng hơn request nào quá nhiều.
Weighted Round Robin
Cùng logic xoay vòng, nhưng một số server xuất hiện nhiều hơn. Ví dụ bạn có một con 8 CPU và một con 2 CPU, set weight 4:1. Con lớn nhận 4 request thì con nhỏ nhận 1.
Điều mình thấy hay là Weighted Round Robin không chỉ dùng để cân tải theo cấu hình. Nó còn là công cụ tuyệt vời cho gradual rollout: set 90% traffic vào bản stable, 10% vào bản build mới. Canary deployment đơn giản nhất chính là thay đổi weight trên load balancer.
Nhóm 2: Dynamic — Chia theo tình hình thực tế
Least Connections
Thay vì chia đều theo lượt, nó nhìn vào số connection đang mở trên mỗi server, rồi gửi request mới tới con ít việc nhất.
Cái hay ở đây: nếu một server đang stuck vì slow query hoặc đang xử lý request nặng, nó tự động ngừng nhận thêm việc. Không cần ai can thiệp.
Least Connections đặc biệt phù hợp với WebSocket, streaming, hoặc bất kỳ hệ thống nào mà thời gian xử lý mỗi request khác nhau nhiều. Mình đã dùng cái này cho một hệ thống chat realtime và nó hoạt động rất ổn — những connection idle không đẩy tải sang server khác một cách vô lý.
Least Response Time
Tiến thêm một bước: không chỉ đếm connection, mà đo xem server nào đang trả lời nhanh nhất, rồi gửi traffic về đó.
Nghe thì hoàn hảo, nhưng có một cái bẫy kinh điển: mọi load balancer đều thấy Server A nhanh nhất → tất cả đổ traffic vào A → A chậm lại → traffic chuyển sang B → B chậm → quay lại A. Vòng lặp này gọi là oscillation, và nó gây ra latency spike liên tục.
Cách giải quyết? Smooth measurement over time — lấy trung bình response time trong 30 giây hoặc 1 phút thay vì dùng giá trị tức thời. HAProxy làm điều này khá tốt nếu bạn config đúng.

Nhóm 3: Hai thuật toán đặc biệt
Power of Two Choices (P2C)
Đây là thuật toán mà mình thấy elegant nhất. Ý tưởng rất đơn giản: thay vì check tất cả server để tìm con tốt nhất (tốn kém), hoặc chọn random (may rủi), bạn chọn ngẫu nhiên 2 con, rồi gửi tới con ít bận hơn.
Nghe có vẻ "hời hợt", nhưng toán học chứng minh rằng cách này gần như tốt bằng việc check toàn bộ. Và quan trọng hơn, nó tránh được thundering herd problem — tình huống mà mọi load balancer trong hệ thống distributed đều thấy cùng một con server "tốt nhất" và đồng loạt đổ traffic vào đó.
P2C là default trong Envoy proxy và hầu hết service mesh hiện đại. Nếu bạn đang chạy Kubernetes, rất có thể traffic của bạn đang được route bằng P2C mà bạn không biết.
Theo kinh nghiệm của mình, P2C là lựa chọn tốt nhất cho hệ thống microservices với nhiều instance. Bạn không cần một central state để track tất cả server, mỗi load balancer tự quyết định locally mà kết quả vẫn tốt globally.
Consistent Hashing
Cái này khác hoàn toàn. Nó không cố gắng chia đều tải. Nó đảm bảo cùng một input luôn đi tới cùng một server.
User 42 luôn tới Server B. User 99 luôn tới Server D. Trừ khi Server D chết, lúc đó chỉ traffic của Server D được redistribute, các server khác không bị ảnh hưởng.
Bạn sẽ gặp consistent hashing ở khắp nơi: memcached ring, sharded database, sticky session, CDN edge routing. Bất kỳ đâu cần affinity — nghĩa là request từ cùng nguồn phải đáp xuống cùng đích — thì consistent hashing là câu trả lời.
Mình từng dùng consistent hashing cho một hệ thống cache phân tán. Khi thêm server mới, chỉ khoảng 1/N cache bị invalidate thay vì toàn bộ. Đó là sự khác biệt giữa "thêm server mượt mà" và "thêm server mà cache miss rate nhảy lên 100% trong 5 phút".

Chọn cái nào?
Đừng nhớ 6 cái rồi chọn random. Hãy nhớ theo nhóm:
- Static (Round Robin, Weighted RR): Server giống nhau, request giống nhau, hoặc cần kiểm soát tỷ lệ traffic chính xác. Đơn giản, dễ hiểu, dễ debug.
- Dynamic (Least Connections, Least Response Time): Request có thời gian xử lý khác nhau nhiều. Hệ thống cần tự adapt theo tình hình thực tế.
- Distributed (P2C): Nhiều load balancer instance, không muốn central coordination. Microservices, service mesh, Kubernetes. Cứ để default, đừng đổi trừ khi có lý do cụ thể.
- Affinity (Consistent Hashing): Cần request cùng nguồn luôn tới cùng đích. Cache, sharding, sticky session.
Một tip cuối: đừng chỉ chọn algorithm xong để đó. Hãy monitor distribution thực tế. Mình đã thấy nhiều hệ thống dùng đúng algorithm nhưng config sai weight, hoặc health check không chạy đúng, khiến traffic vẫn đổ vào server đang chết.
Load balancing không phải thứ bạn setup một lần rồi quên. Nhưng hiểu rõ 6 thuật toán này, bạn sẽ biết chính xác mình đang dùng gì, tại sao, và khi nào cần đổi — thay vì ngồi debug lúc 2 giờ sáng như mình ngày xưa.
Nguyễn Nhật Long
@nguyennhatlong1303Nguyễn Nhật Long is a Senior Frontend Engineer and Frontend Team Leader with 7 years of experience building real-time fintech platforms. Specializing in React, Next.js, TypeScript, and React Native, shipping 10+ products across Web, Mobile, Telegram Mini-Apps, and Web3.
Thấy hay? Chia sẻ cho bạn bè!
Bài viết liên quan
Có thể bạn cũng thích

Zero-Downtime Deployment: Deploy mà user không biết
Làm sao để deploy bản mới lên production mà không ai nhận ra? Cùng tìm hiểu các chiến lược Blue-Green, Rolling, Canary và cách áp dụng thực tế.
Floci: Giã từ LocalStack, chào đón AWS emulator miễn phí thực sự
LocalStack Community đã sunset. Floci là alternative mới — mã nguồn mở, không cần auth token, startup 24ms. Đây là lý do bạn nên thử ngay.

Next.js 16.2 Adapter API: Chạy ở đâu cũng được, không còn bị lock-in Vercel
Next.js 16.2 ra mắt Adapter API ổn định, cho phép deploy lên bất kỳ platform nào với cùng một contract. Cùng tìm hiểu chuyện gì đang xảy ra.