Shopify đã xử lý 1,27 triệu request/giây trong Black Friday như thế nào?
Black Friday và Cyber Monday (BFCM) là thời điểm khắc nghiệt nhất của nhiều nền tảng thương mại điện tử. Với cửa hàng, đây là cơ hội tăng doanh số. Với nền tảng vận hành phía sau, đây là bài kiểm tra về khả năng chịu tải trong một khoảng thời gian rất ngắn.
Bài này được biên soạn lại từ bài tổng hợp về BFCM 2022 của Tom Smykowski, xuất bản ngày 2/12/2022. Câu chuyện cho thấy quy mô của bài toán: Shopify phải xử lý khoảng 1,27 triệu request mỗi giây, tương đương gần 4,3 petabyte dữ liệu truyền tải mỗi ngày. Nhưng con số request không phải toàn bộ câu chuyện. Thử thách lớn hơn là bảo vệ những thành phần có thể trở thành điểm nghẽn, đặc biệt là database, khi hàng triệu người cùng tìm sản phẩm, thêm hàng vào giỏ, checkout và thanh toán.
1. Black Friday là bài kiểm tra sức chịu đựng của hạ tầng
Traffic trong BFCM không chỉ cao mà còn thay đổi rất nhanh. Một chương trình khuyến mãi, một sản phẩm được quan tâm hoặc thời điểm mở bán có thể tạo ra một burst lớn chỉ trong vài giây.
Ở quy mô nền tảng, hệ thống phải giữ được hoạt động cho rất nhiều cửa hàng cùng lúc. Điều đó buộc mọi tầng, từ network, application cho tới data layer, phải được chuẩn bị cho peak traffic thay vì chỉ vận hành tốt ở mức tải trung bình.
Điểm quan trọng là nhìn vào toàn bộ chuỗi xử lý. Thêm năng lực ở một tầng không tự động giải quyết giới hạn ở tầng khác.
2. Database thường là điểm nghẽn khó nhất
Application server có thể scale ngang khá trực tiếp: thêm instance, đặt load balancer phía trước và phân phối request.
Sơ đồ vừa khung
Vấn đề xuất hiện khi các application server cùng dồn request xuống một database. Có thể thêm rất nhiều server xử lý business logic, nhưng nếu database không xử lý được số query tương ứng, toàn bộ hệ thống vẫn bị giới hạn tại đó.
Sơ đồ vừa khung
Trong BFCM 2022, fleet MySQL của Shopify xử lý khoảng 14 triệu query mỗi giây. Con số này nhắc một điều cơ bản trong system design: database, cache, queue và các dependency có trạng thái thường khó mở rộng hơn web tier. Vì vậy, scale không thể chỉ bắt đầu bằng việc tăng số lượng application server.
3. Một triệu request mỗi giây không đi vào một server duy nhất
Không có một server đơn lẻ xử lý toàn bộ 1,27 triệu request mỗi giây. Ở quy mô này, workload được chia qua nhiều tầng, mỗi tầng có một trách nhiệm riêng:
- Load balancer phân phối traffic.
- Application servers xử lý business logic.
- Cache services phục vụ các dữ liệu được đọc lặp lại.
- Service chuyên biệt xử lý từng loại workload.
- Data layer lưu và xử lý dữ liệu lâu dài.
- MySQL nhận các query cần chạm tới dữ liệu có trạng thái.
Sơ đồ vừa khung
Mục tiêu không phải để mọi request đi tới MySQL. Mục tiêu là để chỉ những request thật sự cần dữ liệu gốc hoặc cần thay đổi trạng thái mới đi xuống tầng dữ liệu.
4. Cache là lớp phòng vệ quan trọng
Hãy hình dung một trang sản phẩm đang được đọc một triệu lần nhưng chỉ thay đổi vài lần trong một phút. Nếu mỗi lượt xem đều query database, database phải làm lại cùng một công việc rất nhiều lần.
Cache giải quyết phần lớn tình huống đó:
- Cache hit: trả kết quả ngay, không cần query database.
- Cache miss: request mới cần đi xuống database để lấy dữ liệu.
Nhờ vậy, cache giúp giảm database CPU, database I/O, network traffic và query latency. Nó cũng giúp hệ thống chịu burst tốt hơn khi nhiều người cùng đọc catalog, thông tin sản phẩm, cấu hình cửa hàng hoặc các dữ liệu ít thay đổi.
Tuy nhiên cache không thay thế database. Những thao tác cần dữ liệu chính xác hoặc tạo thay đổi trạng thái vẫn phải được xử lý cẩn thận ở tầng dữ liệu.
5. Không phải request nào cũng quan trọng như nhau
Một hệ thống chịu tải lớn không thể đối xử mọi request theo cùng một cách.
Những request đọc như xem sản phẩm, tải cấu hình cửa hàng hoặc tải ảnh thường phù hợp với cache hay CDN. Ngược lại, checkout, tạo đơn hàng và thanh toán là thao tác có side effect. Chúng không thể được cache đơn giản như một lượt đọc.
Vì vậy cần phân biệt rõ:
- Read-heavy workload và write-heavy workload.
- Stateless request và state-changing request.
- Tác vụ cần phản hồi ngay và tác vụ có thể xử lý bất đồng bộ.
Việc tách các workload ít quan trọng hoặc có thể trì hoãn giúp dành năng lực cho các luồng cần bảo vệ nhất.
6. Scale không chỉ là tăng server
Giả sử một hệ thống bắt đầu với 10 application server và một database. Tăng lên 100 application server không đem lại nhiều giá trị nếu database vẫn chỉ chịu được một lượng query nhất định.
Scale cần được nhìn theo pipeline, từ client qua CDN và load balancer, tới application, cache, async processing rồi database.
Mỗi tầng cần có năng lực phù hợp với phần việc mà nó nhận. Câu hỏi thiết kế đúng không chỉ là server còn bao nhiêu CPU hoặc RAM, mà là bottleneck tiếp theo nằm ở đâu và cần giảm áp lực cho nó như thế nào.
7. Peak traffic phải được chuẩn bị trước
BFCM có một lợi thế: ngày diễn ra đã biết trước. Điều đó cho phép chuẩn bị capacity planning, load testing, monitoring, alerting, database capacity, infrastructure capacity và disaster recovery từ sớm.
Hệ thống không nên đợi traffic đạt đỉnh rồi mới bắt đầu phản ứng. Chuẩn bị trước tạo cơ hội tìm bottleneck, đặt ngưỡng cảnh báo và kiểm tra những luồng quan trọng trong điều kiện tải cao trước khi sự kiện thật diễn ra.
8. Nguy hiểm nhất là traffic cùng lúc
Một hệ thống có thể xử lý một triệu request mỗi giây ở điều kiện bình thường nhưng vẫn có thể sập khi một triệu request đó xảy ra cùng một lúc. Điểm nguy hiểm nằm ở hình dạng của traffic, không chỉ ở tổng số request.
Hãy hình dung một chương trình khuyến mãi bắt đầu đúng lúc 00:00:00. Ở 23:59:59, traffic còn thấp. Chỉ một giây sau, rất nhiều người cùng bấm truy cập, làm traffic tăng vọt và cùng dồn vào những tài nguyên giống nhau. Burst đồng thời này có thể nguy hiểm hơn nhiều so với cùng lượng request được phân bố đều theo thời gian.
Sơ đồ vừa khung
Một ví dụ điển hình là cache vừa hết hạn. Nhiều request cùng cache miss, sau đó cùng query database. Database bị quá tải, latency tăng, request timeout và client bắt đầu retry. Retry lại tạo thêm request, khiến hệ thống rơi vào vòng lặp xấu.
Sơ đồ vừa khung
Do đó, bài toán không chỉ là đủ capacity. Hệ thống còn cần kiểm soát cách request được phân phối và ngăn hàng triệu request cùng lúc chạm vào một dependency giới hạn.
9. Hệ thống cần biết giảm tải một cách có kiểm soát
Khi traffic vượt quá capacity, hệ thống không nhất thiết chỉ có hai trạng thái: hoạt động hoàn hảo hoặc sập hoàn toàn.
Graceful degradation là khả năng giảm hoặc tạm tắt những tính năng không quan trọng, giới hạn một số loại request, ưu tiên traffic quan trọng nhất và cuối cùng bảo vệ database. Trong thương mại điện tử, giữ checkout và tạo đơn hàng hoạt động thường có giá trị hơn việc duy trì tất cả tính năng phụ ở cùng mức độ.
Mục tiêu của cách tiếp cận này là bảo vệ database và các luồng có side effect, đồng thời duy trì phần quan trọng nhất của trải nghiệm người dùng khi hệ thống chịu áp lực.
10. Bài học có thể áp dụng
Điểm đáng học từ BFCM không chỉ là con số 1,27 triệu request mỗi giây. Đó là cách một hệ thống lớn phân chia workload và không để toàn bộ tải dồn vào cùng một bottleneck.
Khi thiết kế cho traffic cao, hãy:
- Scale ngang application layer khi phù hợp.
- Dùng cache cho dữ liệu đọc nhiều, thay đổi ít.
- Phân biệt rõ read, write, stateless và state-changing workload.
- Bảo vệ database và những dependency khó scale.
- Lập kế hoạch capacity trước peak traffic.
- Theo dõi bottleneck bằng observability, không chỉ CPU và RAM.
- Thiết kế graceful degradation cho tình huống quá tải.
Kết luận
Câu chuyện BFCM cho thấy scale không đơn giản là thêm server. Scale là xác định điểm nghẽn thực sự, rồi thiết kế để workload không dồn vào điểm nghẽn đó.
Application server có thể scale ngang tương đối dễ. Nhưng database, cache, network, queue và các hệ thống stateful mới thường quyết định giới hạn thực tế. Với Shopify, bài toán còn khó hơn vì phải để hàng triệu merchant tiếp tục vận hành cửa hàng trong thời điểm quan trọng nhất năm. Khi thiết kế cho hàng triệu request, câu hỏi nên bắt đầu là: bottleneck tiếp theo sẽ nằm ở đâu?
