Concurrency – Muốn phục vụ 1 triệu người dùng, đừng chỉ mua CPU mạnh hơn!
Một website đang hoạt động bình thường.
Bỗng nhiên có 100.000 người truy cập cùng lúc.
Bạn sẽ làm gì?
Cách 1: Nâng cấp máy chủ từ 8 CPU lên 32 CPU, RAM từ 32 GB lên 128 GB.
Cách 2: Khởi động thêm nhiều instance của ứng dụng và phân phối lưu lượng đến tất cả các instance.
Ngày nay, hầu hết các doanh nghiệp đều chọn Cách 2.
Đó chính là tinh thần của Yếu tố thứ 8 trong 12-Factor App:
Hay nói đơn giản hơn:
Scaling là gì?
Khi số lượng người dùng hoặc khối lượng công việc tăng lên, ứng dụng cần được mở rộng để đáp ứng nhu cầu.
Có hai cách tiếp cận phổ biến. Vertical Scaling (Scale Up)
Đây là cách quen thuộc nhất.
Bạn tăng tài nguyên cho một máy chủ:
Ví dụ:
Server
4 CPU
8 GB RAM
│
Upgrade
▼
16 CPU
64 GB RAM
Cách này đơn giản nhưng luôn có giới hạn. Đến một thời điểm, bạn không thể nâng cấp phần cứng thêm nữa hoặc chi phí sẽ tăng rất cao.
Horizontal Scaling (Scale Out)
Thay vì làm một máy mạnh hơn, bạn tăng số lượng tiến trình hoặc instance.
Ví dụ:
Load Balancer
│
┌──────────┼──────────┐
▼ ▼ ▼
App 1 App 2 App 3
Lưu lượng sẽ được chia đều giữa các instance.
Đây là mô hình mà Kubernetes, Docker Swarm và hầu hết các nền tảng Cloud Native đang sử dụng.
Process là "công dân hạng nhất"
12-Factor App xem Process là đơn vị triển khai và mở rộng cơ bản.
Thay vì xây dựng một ứng dụng khổng lồ xử lý mọi việc, hệ thống được chia thành nhiều loại process khác nhau.
Ví dụ:
Web Process
│
Xử lý HTTP Request
Worker Process
│
Xử lý Background Job
Scheduler Process
│
Chạy tác vụ định kỳ
Mỗi loại process đảm nhận một nhóm công việc riêng và có thể được mở rộng độc lập theo nhu cầu.
Process Formation
Tập hợp các loại process cùng với số lượng instance của từng loại được gọi là Process Formation.
Ví dụ:
Web Process x 6
Worker Process x 3
Scheduler x 1
Nếu lượng truy cập web tăng đột biến, doanh nghiệp chỉ cần tăng số lượng Web Process mà không cần mở rộng Worker hay Scheduler.
Ngược lại, nếu hệ thống phải xử lý nhiều tác vụ nền như gửi email hoặc xử lý hàng đợi, chỉ cần tăng số lượng Worker Process.
Việc mở rộng đúng thành phần giúp sử dụng tài nguyên hiệu quả hơn.
Một Process vẫn có thể chạy nhiều Thread
Bên trong mỗi Process, ứng dụng vẫn có thể sử dụng:
để xử lý đồng thời nhiều công việc.
Tuy nhiên, Vertical Scaling luôn có giới hạn.
Khi lượng tải tiếp tục tăng, giải pháp bền vững là tạo thêm nhiều Process và phân phối công việc giữa chúng, thay vì chỉ tăng số lượng Thread trong một Process.
Stateless là điều kiện để Scale Out
Ở bài trước, chúng ta đã tìm hiểu về Stateless Processes.
Đây chính là nền tảng của Concurrency.
Nếu mỗi Process đều độc lập và không lưu trạng thái trong RAM, hệ thống có thể:
Load Balancer
│
┌────┼────┐
▼ ▼ ▼
P1 P2 P3
Mọi request đều có thể được chuyển đến bất kỳ Process nào.
Không cần biết người dùng trước đó đã truy cập vào đâu.
Đó là lý do Stateless và Horizontal Scaling luôn đi cùng nhau.
Hệ điều hành quản lý vòng đời Process
Theo mô hình 12-Factor App, ứng dụng không nên tự quản lý việc khởi động hay giám sát các Process.
Thay vào đó, nhiệm vụ này được giao cho Process Manager hoặc nền tảng điều phối.
Ví dụ:
Những nền tảng này có thể tự động:
Ứng dụng chỉ cần tập trung vào logic nghiệp vụ.
DevSecOps và Concurrency
Concurrency không chỉ giúp hệ thống phục vụ nhiều người dùng hơn.
Nó còn là nền tảng của:
Khi ứng dụng được thiết kế theo mô hình Process, Stateless và Scale Out, doanh nghiệp có thể mở rộng năng lực xử lý bằng cách bổ sung thêm các instance thay vì thay đổi mã nguồn hay nâng cấp một máy chủ duy nhất.
Đó cũng là triết lý của hạ tầng hiện đại: mở rộng bằng số lượng, không chỉ bằng cấu hình. Khi kết hợp với CI/CD, Container và Kubernetes, mô hình này giúp hệ thống dễ mở rộng, dễ tự phục hồi và sẵn sàng đáp ứng những đợt tăng tải đột biến với mức độ tự động hóa rất cao.
Một website đang hoạt động bình thường.
Bỗng nhiên có 100.000 người truy cập cùng lúc.
Bạn sẽ làm gì?
Cách 1: Nâng cấp máy chủ từ 8 CPU lên 32 CPU, RAM từ 32 GB lên 128 GB.
Cách 2: Khởi động thêm nhiều instance của ứng dụng và phân phối lưu lượng đến tất cả các instance.
Ngày nay, hầu hết các doanh nghiệp đều chọn Cách 2.
Đó chính là tinh thần của Yếu tố thứ 8 trong 12-Factor App:
Scale out via the process model.
Hay nói đơn giản hơn:
Đừng chỉ làm cho một máy mạnh hơn, hãy để nhiều tiến trình cùng làm việc.
Scaling là gì?
Khi số lượng người dùng hoặc khối lượng công việc tăng lên, ứng dụng cần được mở rộng để đáp ứng nhu cầu.
Có hai cách tiếp cận phổ biến. Vertical Scaling (Scale Up)
Đây là cách quen thuộc nhất.
Bạn tăng tài nguyên cho một máy chủ:
- Thêm CPU.
- Thêm RAM.
- Thêm ổ SSD nhanh hơn.
Ví dụ:
Server
4 CPU
8 GB RAM
│
Upgrade
▼
16 CPU
64 GB RAM
Cách này đơn giản nhưng luôn có giới hạn. Đến một thời điểm, bạn không thể nâng cấp phần cứng thêm nữa hoặc chi phí sẽ tăng rất cao.
Horizontal Scaling (Scale Out)
Thay vì làm một máy mạnh hơn, bạn tăng số lượng tiến trình hoặc instance.
Ví dụ:
Load Balancer
│
┌──────────┼──────────┐
▼ ▼ ▼
App 1 App 2 App 3
Lưu lượng sẽ được chia đều giữa các instance.
Đây là mô hình mà Kubernetes, Docker Swarm và hầu hết các nền tảng Cloud Native đang sử dụng.
Process là "công dân hạng nhất"
12-Factor App xem Process là đơn vị triển khai và mở rộng cơ bản.
Thay vì xây dựng một ứng dụng khổng lồ xử lý mọi việc, hệ thống được chia thành nhiều loại process khác nhau.
Ví dụ:
Web Process
│
Xử lý HTTP Request
Worker Process
│
Xử lý Background Job
Scheduler Process
│
Chạy tác vụ định kỳ
Mỗi loại process đảm nhận một nhóm công việc riêng và có thể được mở rộng độc lập theo nhu cầu.
Process Formation
Tập hợp các loại process cùng với số lượng instance của từng loại được gọi là Process Formation.
Ví dụ:
Web Process x 6
Worker Process x 3
Scheduler x 1
Nếu lượng truy cập web tăng đột biến, doanh nghiệp chỉ cần tăng số lượng Web Process mà không cần mở rộng Worker hay Scheduler.
Ngược lại, nếu hệ thống phải xử lý nhiều tác vụ nền như gửi email hoặc xử lý hàng đợi, chỉ cần tăng số lượng Worker Process.
Việc mở rộng đúng thành phần giúp sử dụng tài nguyên hiệu quả hơn.
Một Process vẫn có thể chạy nhiều Thread
Bên trong mỗi Process, ứng dụng vẫn có thể sử dụng:
- Thread
- Async I/O
- Event Loop
để xử lý đồng thời nhiều công việc.
Tuy nhiên, Vertical Scaling luôn có giới hạn.
Khi lượng tải tiếp tục tăng, giải pháp bền vững là tạo thêm nhiều Process và phân phối công việc giữa chúng, thay vì chỉ tăng số lượng Thread trong một Process.
Stateless là điều kiện để Scale Out
Ở bài trước, chúng ta đã tìm hiểu về Stateless Processes.
Đây chính là nền tảng của Concurrency.
Nếu mỗi Process đều độc lập và không lưu trạng thái trong RAM, hệ thống có thể:
Load Balancer
│
┌────┼────┐
▼ ▼ ▼
P1 P2 P3
Mọi request đều có thể được chuyển đến bất kỳ Process nào.
Không cần biết người dùng trước đó đã truy cập vào đâu.
Đó là lý do Stateless và Horizontal Scaling luôn đi cùng nhau.
Hệ điều hành quản lý vòng đời Process
Theo mô hình 12-Factor App, ứng dụng không nên tự quản lý việc khởi động hay giám sát các Process.
Thay vào đó, nhiệm vụ này được giao cho Process Manager hoặc nền tảng điều phối.
Ví dụ:
- systemd trên Linux.
- Foreman.
- Kubernetes.
- Docker Compose.
- Các dịch vụ điều phối trên Cloud.
Những nền tảng này có thể tự động:
- Khởi động Process.
- Khởi động lại khi Process bị lỗi.
- Tăng hoặc giảm số lượng Process theo tải.
- Phân phối công việc giữa các Process.
Ứng dụng chỉ cần tập trung vào logic nghiệp vụ.
DevSecOps và Concurrency
Concurrency không chỉ giúp hệ thống phục vụ nhiều người dùng hơn.
Nó còn là nền tảng của:
- High Availability.
- Auto Scaling.
- Load Balancing.
- Cloud Native.
- Kubernetes.
Khi ứng dụng được thiết kế theo mô hình Process, Stateless và Scale Out, doanh nghiệp có thể mở rộng năng lực xử lý bằng cách bổ sung thêm các instance thay vì thay đổi mã nguồn hay nâng cấp một máy chủ duy nhất.
Đó cũng là triết lý của hạ tầng hiện đại: mở rộng bằng số lượng, không chỉ bằng cấu hình. Khi kết hợp với CI/CD, Container và Kubernetes, mô hình này giúp hệ thống dễ mở rộng, dễ tự phục hồi và sẵn sàng đáp ứng những đợt tăng tải đột biến với mức độ tự động hóa rất cao.