Hàng đợi xử lý: vì sao 'đang xử lý' thường là lựa chọn đúng
Một nút bấm trả kết quả ngay và một nút bấm nói 'đang xử lý' không phải là hai mức chất lượng phần mềm. Đó là hai đánh đổi khác nhau, và cái thứ hai thường được chọn có lý do.
Bấm “xuất báo cáo” và nhận lại một dòng chữ: “Yêu cầu đã được ghi nhận, chúng tôi sẽ gửi email khi xong.” Phản ứng thường gặp là cho rằng hệ thống chậm, hoặc đang quá tải. Thường thì ngược lại: đó là dấu hiệu hệ thống được thiết kế để chịu được lúc đông người, và cơ chế làm việc đó gọi là hàng đợi.
Hai việc bị gộp làm một
Công việc không đến đều. Có phút không ai bấm gì, có phút hàng trăm người cùng xuất báo cáo: sau giờ họp, đầu giờ sáng, cuối tháng khi ai cũng cần số liệu chốt sổ. Một hệ thống xử lý mọi yêu cầu ngay tại chỗ phải có đủ năng lực cho đúng cái phút đông nhất đó, và giữ năng lực ấy quanh năm. Phần lớn thời gian nó nằm không, chỉ để chờ vài giờ cao điểm.
Cách còn lại là tách “nhận yêu cầu” khỏi “làm yêu cầu”. Nhận thì luôn nhanh, vì hệ thống chỉ ghi lại rằng có một yêu cầu vừa đến. Làm thì diễn ra sau đó, ở tốc độ hệ thống chịu được, bất kể đang có một người hay một nghìn người xếp hàng. Danh sách chờ giữa hai bước đó là hàng đợi.
Người dùng nhận phản hồi gần như tức thì, dù báo cáo có thể mất vài phút mới xong. Thời gian chờ không biến mất; nó chuyển từ chỗ người dùng ngồi nhìn màn hình sang chỗ hệ thống xử lý phía sau.
Cái mất và cái được
Hàng đợi không làm việc nhanh hơn. Với đa số trường hợp nó còn chậm hơn một chút. Đổi lại là hai thứ mà hệ thống “làm ngay bằng mọi giá” đánh mất đúng vào lúc cần nhất.
Thứ nhất, yêu cầu không mất. Đã vào hàng đợi thì nó nằm đó chờ tới lượt, kể cả khi phải chờ lâu hơn dự kiến. Hệ thống cố xử lý ngay và hết thời gian chờ giữa chừng thì rơi vào tình trạng tệ hơn nhiều: người dùng không biết yêu cầu của mình đã được ghi nhận hay chưa, và thường bấm lại, làm hệ thống đang quá tải phải gánh thêm.
Thứ hai, hỏng hóc không lan. Đây là phần hay bị bỏ qua khi bàn về tốc độ. Khi gặp đợt dồn dập, hệ thống không có hàng đợi thường phản ứng theo kiểu tất cả cùng chậm rồi cùng đứng: mỗi yêu cầu mới đến lại kéo những yêu cầu đang chạy chậm thêm, cho tới khi không cái nào kịp hoàn tất và tất cả cùng báo lỗi. Có hàng đợi thì hàng đợi dài ra, còn phần xử lý phía sau vẫn chạy đúng nhịp của nó.
flowchart TB
S[Đợt yêu cầu dồn dập] --> N[Không hàng đợi]
S --> Q[Có hàng đợi]
N --> N1[Mọi yêu cầu cùng chậm lại]
N1 --> N2[Quá hạn chờ<br/>tất cả cùng báo lỗi]
Q --> Q1[Hàng đợi dài ra]
Q1 --> Q2[Phần xử lý giữ nguyên nhịp]
Q2 --> Q3[Chờ lâu hơn<br/>kết quả vẫn đúng]
Khác biệt nằm ở hình dạng của cái xấu nhất có thể xảy ra. Một bên là chờ lâu hơn. Bên kia là hỏng toàn bộ cùng lúc.
Chỗ nào hợp, chỗ nào không
Ranh giới khá rõ: kết quả này có cần thay đổi ngay màn hình người dùng đang nhìn hay không. Gõ một ký tự và thấy nó hiện ra, bấm thích và thấy số đếm tăng: những việc đó chỉ có nghĩa khi phản hồi tức thì, nên không đi qua hàng đợi. Còn lại thì hàng đợi thường là lựa chọn tốt hơn.
Gửi email xác nhận sau khi đăng ký. Tổng hợp báo cáo từ dữ liệu lớn. Xử lý ảnh và video vừa tải lên. Cập nhật trạng thái đơn hàng sau khi cổng thanh toán xác nhận, việc gần như luôn chạy nền vì bản thân cổng thanh toán cũng cần thời gian.
Các tính năng AI tạo sinh gần như luôn đi qua hàng đợi, vì thời gian xử lý dao động nhiều theo độ dài yêu cầu và theo tải tại thời điểm đó. Một sản phẩm cam kết trả kết quả trong một khoảng thời gian cố định, bất kể yêu cầu ngắn hay dài, thường phải cắt bớt chất lượng để giữ đúng cam kết. Cam kết “sẽ báo khi xong” giữ được chất lượng ổn định hơn, đổi lại thời gian chờ không cố định.
Phân biệt hàng đợi bình thường với sự cố
Với người ra quyết định, phần dùng được không phải là định nghĩa hàng đợi, mà là cách phân biệt hai tình huống nhìn bên ngoài giống hệt nhau: một tính năng “đang xử lý” vì nó được thiết kế như vậy, và một tính năng “đang xử lý” vì đang hỏng.
Dấu hiệu không nằm ở chỗ có phải chờ hay không, mà ở chỗ thời gian chờ có nằm trong khoảng quen thuộc của nó và có kết thúc bằng một tín hiệu rõ ràng hay không. Hàng đợi chạy đúng thiết kế thì thời gian chờ dao động trong một khoảng đoán được, và luôn khép lại bằng email, thông báo, hoặc một trạng thái đổi trên màn hình. Hệ thống đang hỏng thì thời gian chờ mất quy luật, dài bất thường so với mọi lần trước, hoặc im lặng không có tín hiệu kết thúc nào.
Nên khi một tính năng chạy lâu hơn thường lệ, câu hỏi hữu ích không phải “sao chậm vậy” mà là “khoảng chờ này có bất thường so với chính nó không, và có phải mọi yêu cầu khác cũng đang chậm như vậy không”. Câu trả lời tách được một hệ thống đang làm đúng việc nó được thiết kế để làm khỏi một hệ thống thật sự có vấn đề, và hai tình huống đó cần hai phản ứng hoàn toàn khác nhau.
