Scalability for Dummies

Phần thứ 4 của loạt bài này bắt đầu bằng một hình ảnh: hãy tưởng tượng bạn muốn mua bánh mì ở tiệm bánh yêu thích. Bạn bước vào tiệm, hỏi mua một ổ bánh mì, nhưng… không có bánh! Thay vào đó, bạn được yêu cầu quay lại sau 2 tiếng nữa khi bánh đã nướng xong. Thật phiền phức, đúng không?

Để tránh tình huống kiểu “vui lòng đợi một lát” như vậy, cần phải áp dụng xử lý bất đồng bộ (asynchronous processing). Và nếu điều đó tốt cho một tiệm bánh, thì cũng có thể tốt cho dịch vụ web hoặc ứng dụng web của bạn.


Nói chung, có hai cách / mô hình chính để thực hiện bất đồng bộ:


Async #1: Làm trước – Bán sau

Tiếp tục với ví dụ tiệm bánh: Cách bất đồng bộ đầu tiên là kiểu “nướng bánh từ đêm và bán vào buổi sáng”. Không có thời gian chờ tại quầy và khách hàng thì vui vẻ.
Áp dụng vào web app: điều này có nghĩa là thực hiện các công việc tốn thời gian trước và phục vụ thành phẩm với thời gian phản hồi rất thấp.

Cách làm này thường được dùng để chuyển nội dung động thành nội dung tĩnh. Ví dụ: các trang web được xây dựng bằng framework hoặc CMS nặng sẽ được render sẵn và lưu thành các file HTML tĩnh mỗi khi có thay đổi. Các tác vụ tính toán này có thể được thực hiện định kỳ, ví dụ bằng một script được gọi mỗi giờ qua cronjob.

Việc tính toán trước dữ liệu tổng quát như vậy sẽ giúp website và ứng dụng web trở nên hiệu quả, có khả năng mở rộng cao và rất nhanh.
Hãy tưởng tượng khả năng mở rộng của website bạn nếu các file HTML render sẵn này được upload lên AWS S3, CloudFront hoặc các mạng phân phối nội dung (CDN) khác. Website của bạn sẽ cực kỳ mượt và có thể xử lý hàng triệu lượt truy cập mỗi giờ!


Async #2: Làm theo yêu cầu – Trả kết quả sau

Quay lại tiệm bánh. Đôi khi khách hàng lại có những yêu cầu đặc biệt như một chiếc bánh sinh nhật với dòng chữ “Chúc mừng sinh nhật Steve!”. Tiệm bánh không thể đoán trước những yêu cầu như vậy nên phải bắt đầu làm khi khách hàng đến, và hẹn họ quay lại vào ngày hôm sau.

Đối với web service, điều này có nghĩa là xử lý tác vụ bất đồng bộ theo yêu cầu người dùng.


Một quy trình xử lý điển hình:

  1. Người dùng truy cập website và khởi động một tác vụ nặng (ví dụ: tạo báo cáo, render video) mất vài phút để hoàn thành.
  2. Frontend gửi một job vào hàng đợi (job queue), và ngay lập tức phản hồi rằng “Tác vụ đang được xử lý, bạn có thể tiếp tục sử dụng trang web”.
  3. Hàng đợi job được một nhóm worker kiểm tra liên tục.
  4. Khi phát hiện job mới, một worker sẽ xử lý nó, và sau vài phút, gửi tín hiệu rằng job đã xong.
  5. Frontend, vốn đang liên tục kiểm tra xem job đã hoàn thành chưa, phát hiện tín hiệu và thông báo lại cho người dùng.

Tôi biết ví dụ trên là cách đơn giản hóa, nhưng đó là mô hình nền tảng.


Nếu bạn muốn đi sâu hơn vào thiết kế kỹ thuật, tôi khuyên bạn nên đọc 3 bài hướng dẫn đầu tiên trên website của RabbitMQ.

RabbitMQ là một trong nhiều hệ thống hỗ trợ xử lý bất đồng bộ. Ngoài ra bạn có thể dùng ActiveMQ hoặc đơn giản là một danh sách trong Redis. Ý tưởng chính là có một hàng đợi các tác vụ, và các worker lần lượt xử lý chúng.

Bất đồng bộ nghe có vẻ phức tạp, nhưng nó rất đáng để bạn học và triển khai.
Backend sẽ gần như có thể mở rộng vô hạn, còn frontend thì phản hồi cực nhanh – điều đó nâng cao trải nghiệm người dùng tổng thể.


👉 Nếu bạn làm điều gì đó tốn thời gian, hãy cố gắng luôn thực hiện nó một cách bất đồng bộ.

Code Toàn Bug

Code nhiều bug nhưng biết cách giấu!

Leave a Reply

Your email address will not be published. Required fields are marked *