Tôi đã làm vài năm trong nhóm Framework dịch vụ tại Amazon. Nhóm của chúng tôi viết các công cụ giúp chủ sở hữu của các dịch vụ AWS như Amazon Route 53 và Elastic Load Balancing xây dựng dịch vụ của mình nhanh hơn và giúp máy khách dịch vụ gọi dịch vụ dễ dàng hơn. Các nhóm Amazon khác cung cấp cho chủ sở hữu dịch vụ các chức năng như đo lường, xác thực, giám sát, tạo thư viện máy khách và tạo tài liệu. Thay vì để từng nhóm dịch vụ tích hợp thủ công các tính năng này vào dịch vụ của mình, nhóm Framework dịch vụ tích hợp một lần và cung cấp chức năng cho từng dịch vụ bằng cách đặt cấu hình.

Một thách thức chúng tôi gặp phải là xác định cách cung cấp các giá trị mặc định phù hợp, đặc biệt đối với các tính năng liên quan đến hiệu năng hoặc tính khả dụng. Ví dụ: chúng tôi không thể dễ dàng thiết lập thời gian chờ mặc định phía máy khách vì framework của chúng tôi không biết các đặc điểm về độ trễ của lệnh gọi API. Chủ sở hữu dịch vụ hoặc máy khách cũng sẽ chẳng thể tự mình giải quyết vấn đề này một cách dễ dàng hơn, do đó chúng tôi tiếp tục cố gắng và đã có được một số thông tin chuyên sâu hữu ích trong quá trình này.

Một câu hỏi phổ biến mà chúng tôi gặp phải là việc xác định số lượng kết nối mặc định mà máy chủ sẽ để mở cho máy khách tại cùng một thời điểm. Thiết lập này được thiết kế để ngăn chặn máy chủ thực hiện quá nhiều công việc và trở nên quá tải. Cụ thể hơn, chúng tôi muốn đặt cấu hình cài đặt kết nối tối đa cho máy chủ tỷ lệ với số kết nối tối đa cho cân bằng tải. Đó là thời kỳ trước khi Elastic Load Balancing xuất hiện nên thiết bị cân bằng tải vẫn được sử dụng rộng rãi.

Chúng tôi bắt đầu giúp chủ sở hữu dịch vụ của Amazon và máy khách dịch vụ tìm ra giá trị lý tưởng cho số kết nối tối đa để thiết lập trên cân bằng tải, cũng như giá trị tương ứng để thiết lập trong framework mà chúng tôi cung cấp. Chúng tôi quyết định rằng nếu có thể tìm ra cách sử dụng phán đoán của con người để đưa ra lựa chọn, thì chúng tôi cũng có thể viết phần mềm để mô phỏng phán đoán này.

Việc xác định giá trị lý tưởng hóa ra lại đầy thử thách. Nếu đặt số kết nối tối đa quá thấp, thì cân bằng tải có thể ngừng tăng số lượng yêu cầu, ngay cả khi dịch vụ vẫn còn nhiều khả năng tiếp nhận. Nếu đặt số kết nối tối đa quá cao, thì máy chủ sẽ trở nên chậm chạp và không phản hồi. Nếu đặt số kết nối tối đa chỉ chính xác cho một khối lượng công việc, khối lượng công việc này sẽ thay đổi hoặc hiệu năng phụ thuộc sẽ thay đổi. Từ đó, các giá trị sẽ lại sai, dẫn đến sự cố ngừng hoạt động hoặc quá tải không cần thiết.

Cuối cùng, chúng tôi thấy rằng khái niệm số kết nối tối đa vô cùng mơ hồ để cung cấp câu trả lời hoàn chỉnh cho vấn đề này. Trong bài viết này, chúng tôi sẽ mô tả các cách tiếp cận khác như biện pháp giảm tải mà chúng tôi thấy rằng đã hoạt động hiệu quả.

Bản chất của hiện tượng quá tải

Tại Amazon, chúng tôi hạn chế sự quá tải bằng cách thiết kế cho các hệ thống của mình chủ động thay đổi quy mô trước khi chúng gặp phải tình huống quá tải. Tuy nhiên, việc bảo vệ hệ thống bao gồm bảo vệ theo lớp. Quá trình này bắt đầu với việc tự động thay đổi quy mô nhưng cũng bảo gồm các cơ chế giúp giảm tải quá mức có kiểm soát, khả năng giám sát các cơ chế này, và quan trọng nhất là kiểm thử liên tục.
 
Khi kiểm thử độ chịu tải của dịch vụ, chúng tôi thấy rằng độ trễ của máy chủ ở mức sử dụng thấp thấp hơn độ trễ ở mức sử dụng cao. Khi máy chủ tải nặng, các hiện tượng tranh chấp luồng (thread contention), chuyển ngữ cảnh (context switching), thu gom rác (garbage collection) và tranh chấp I/O (I/O contention) trở nên rõ ràng hơn. Cuối cùng, các dịch vụ đạt đến điểm uốn mà tại đó hiệu năng bắt đầu suy giảm nhanh hơn.
 
Lý thuyết nền tảng của quan sát này được gọi là Định luật khả năng mở rộng phổ quát (Universal Scalability Law), được rút ra từ Định luật Amdahl. Lý thuyết này chỉ rõ rằng mặc dù thông lượng của hệ thống có thể tăng lên bằng biện pháp song song hóa, nhưng cuối cùng vẫn sẽ bị giới hạn bởi thông lượng của các điểm trong quá trình nối tiếp hóa (nghĩa là, bởi các tác vụ không thể song song hóa).
 
Thật không may, thông lượng không chỉ bị giới hạn bởi tài nguyên của hệ thống mà còn thường suy giảm khi hệ thống bị quá tải. Khi một hệ thống được giao nhiều công việc hơn khả năng tài nguyên có thể hỗ trợ, thì hệ thống sẽ trở nên chậm chạp. Máy tính tiếp nhận công việc ngay cả khi chúng bị quá tải, nhưng chúng tiêu tốn ngày càng nhiều thời gian để chuyển ngữ cảnh và không còn hữu ích khi đã quá chậm chạp.
 
Trong hệ thống phân tán nơi máy khách làm việc với máy chủ, máy khách thường trở nên thiếu kiến nhẫn và dừng chờ đợi máy chủ phản hồi sau một khoảng thời gian. Chúng ta biết đến khoảng thời gian này với tên gọi thời gian chờ. Khi máy chủ quá tải đến mức độ trễ của nó vượt quá thời gian chờ của máy khách, các yêu cầu bắt đầu không thành công. Đồ thị dưới đây cho thấy thời gian phản hồi của máy chủ tăng lên như thế nào khi thông lượng được cung cấp (trong các giao dịch mỗi giây) tăng lên, và cuối cùng thời gian phản hồi đạt đến điểm uốn mà mọi thứ giảm đi nhanh chóng.

Trong biểu đồ trước đó, khi thời gian phản hồi vượt quá thời gian chờ của máy khách, thì rõ ràng rằng mọi thứ đều tồi tệ, nhưng biểu đồ không chỉ ra mức độ tồi tệ. Để minh họa điều này, chúng ta có thể vẽ biểu đồ tính khả dụng của máy khách cùng với độ trễ. Thay vì sử dụng cách tính thời gian phản hồi chung, chúng tôi có thể chuyển sang dùng thời gian phản hồi trung vị. Thời gian phản hồi trung vị có nghĩa là 50% số yêu cầu nhanh hơn giá trị trung vị. Nếu độ trễ trung vị của dịch vụ bằng với thời gian chờ của máy khách, thì một nửa số yêu cầu đang hết thời gian, do đó tính khả dụng là 50%. Đó là khi sự tăng độ trễ biến vấn đề về độ trễ thành vấn đề về tính khả dụng. Đây là đồ thị của những gì đã xảy ra:

Tiếc rằng đồ thị này khá khó đọc. Một cách đơn giản hơn để mô tả vấn đề về tính khả dụng là phân biệt goodput với thông lượng. Thông lượng là tổng số yêu cầu mỗi giây được gửi tới máy chủ. Goodput là thành phần của thông lượng được xử lý không có lỗi và có độ trễ đủ thấp để máy khách sử dụng phản hồi.

Vòng lặp phản hồi tích cực

Khả năng lan truyền âm thầm của trường hợp quá tải nằm ở cách nó tự khuếch đại trong vòng lặp phản hồi. Khi máy khách hết thời gian chờ, tình huống đủ tệ là khi máy khách gặp lỗi. Tình huống tệ hơn là khi toàn bộ tiến độ mà máy chủ đã thực hiện cho yêu cầu tính đến thời điểm đó đều bị lãng phí. Và điều cuối cùng một hệ thống nên làm trong trường hợp quá tải, với khả năng tiếp nhận hạn chế, là loại bỏ công việc.

Điều làm mọi thứ tệ hại hơn nữa là máy khách thường thử yêu cầu lại. Điều này khiến lượng tải cung cấp trên hệ thống tăng lên nhiều lần. Và nếu có đồ thị cuộc gọi đủ sâu trong một kiến trúc hướng dịch vụ (khi máy khách gọi một dịch vụ, dịch vụ đó lại gọi các dịch vụ khác và cứ thế tiếp diễn), và nếu mỗi lớp thực hiện nhiều lần thử lại, thì sự quá tải ở lớp dưới cùng gây ra các thử lại phân tầng khuếch đại khối lượng tải được cung cấp theo cấp số nhân.

Khi các yếu tố này được kết hợp, tình trạng quá tải sẽ tạo ra vòng lặp phản hồi của riêng mình, dẫn đến quá tải như một trạng thái ổn định.

Ngăn chặn lãng phí công việc

Thoạt nhìn, biện pháp giảm tải có vẻ đơn giản. Khi sắp quá tải, máy chủ nên bắt đầu từ chối yêu cầu vượt mức để có thể tập trung vào các yêu cầu đã được tiếp nhận. Mục đích của giảm tải là nhằm giữ độ trễ thấp đối với các yêu cầu mà máy chủ chấp nhận để dịch vụ trả lời trước khi máy khách hết thời gian chờ. Với cách tiếp cận này, máy chủ duy trì được tính khả dụng cao cho các yêu cầu được tiếp nhận và chỉ có tính khả dụng của lưu lượng vượt mức bị ảnh hưởng.

Kiểm soát được độ trễ bằng cách giảm tải vượt mức sẽ tăng tính khả dụng của hệ thống. Nhưng rất khó để trực quan hóa lợi ích của phương pháp này trong đồ thị trước. Đường biểu thị tính khả dụng tổng thể vẫn đi xuống, và đó không phải là tín hiệu tốt. Điều quan trọng là các yêu cầu mà máy chủ quyết định tiếp nhận vẫn khả dụng vì chúng được phản hồi nhanh chóng.
Giảm tải cho phép máy chủ duy trì phần thông lượng không bị lỗi (goodput) và hoàn tất nhiều yêu cầu nhất có thể, ngay cả khi tăng thông lượng cung cấp. Tuy nhiên, việc giảm tải vẫn không hoàn hảo, do đó cuối cùng máy chủ vẫn phải tuân theo định luật Amdahl và goodput giảm.

Kiểm thử

Khi trao đổi với các kỹ sư về phương pháp giảm tải, tôi muốn chỉ ra rằng nếu họ chưa kiểm thử độ chịu tải của dịch vụ đến thời điểm dịch vụ gặp sự cố và xa hơn cả thời điểm đó, thì họ nên giả định rằng dịch vụ sẽ gặp trục trặc theo cách họ không mong muốn nhất có thể. Tại Amazon, chúng tôi dành rất nhiều thời gian để kiểm tra độ chịu tải của các dịch vụ. Việc tạo các biểu đồ như ở phần trước của bài viết giúp chúng tôi vạch ra đường cơ sở cho hiệu năng khi quá tải của mình và theo dõi hiệu quả của những thay đổi đối với dịch vụ theo thời gian.

Có nhiều loại kiểm thử độ chịu tải. Một số kiểm thử độ chịu tải đảm bảo rằng nhóm sẽ tự động tăng quy mô khi lượng tải tăng, trong khi các kiểm thử khác sử dụng kích thước nhóm cố định. Nếu trong một kiểm thử độ chịu tải, tính khả dụng của dịch vụ giảm nhanh về 0 khi thông lượng tăng, đó là dấu hiệu tốt cho thấy dịch vụ cần cơ chế giảm tải bổ sung. Kết quả kiểm thử độ chịu tải lý tưởng là goodput ở trạng thái bình ổn sau khi tăng khi dịch vụ gần như đạt đến công suất cao nhất và vẫn giữ nguyên ngay cả khi có thêm thông lượng.

Các công cụ như Chaos Monkey giúp thực hiện kiểm thử kỹ thuật mô phỏng trạng thái rối loạn (chaos engineering) trên dịch vụ. Ví dụ: các công cụ này có thể làm CPU quá tải hoặc làm mất gói dữ liệu để mô phỏng các tình trạng xảy ra khi quá tải. Một kỹ thuật kiểm thử khác chúng tôi sử dụng là thực hiện kiểm thử tạo tải có sẵn (còn gọi là canary), dẫn hướng tải được duy trì liên tục (thay vì tăng khối lượng tải) đến môi trường kiểm thử, nhưng bắt đầu loại bỏ máy chủ khỏi môi trường kiểm thử đó. Điều này tăng thông lượng cung cấp ở mỗi phiên bản, từ đó giúp chúng tôi kiểm thử thông lượng phiên bản. Kỹ thuật tăng lượng tải phi tự nhiên bằng cách giảm kích thước nhóm hữu ích để kiểm thử riêng biệt một dịch vụ, nhưng không phải là giải pháp thay thế hoàn hảo cho kiểm thử độ chịu tải toàn diện. Một kiểm thử độ chịu tải toàn diện, bao quát cũng sẽ tăng lượng tải lên phần phụ thuộc của dịch vụ, từ đó có thể phơi bày các khả năng gây cản trở khác.

Trong quá trình kiểm thử, chúng tôi không quên đo đạc tính khả dụng và độ trễ của máy khách bên cạnh các dữ liệu tương tự của máy chủ. Khi tính khả dụng của máy khách bắt đầu giảm, chúng tôi tăng lượng tải vượt xa giá trị tải tương ứng tại thời điểm đó. Nếu biện pháp giảm tải có hiệu quả, goodput sẽ giữ nguyên trạng thái ổn định ngay cả khi thông lượng cung cấp vượt quá khả năng tương ứng theo tỷ lệ của dịch vụ.

Kiểm thử quá tải là vô cùng quan trọng trước khi khám phá cơ chế để tránh quá tải. Mỗi cơ chế đều có sự phức tạp riêng. Ví dụ: hãy xem xét tất cả lựa chọn cấu hình trong framework dịch vụ mà tôi đã nhắc đến trong phần đầu của bài viết và sự khó khăn trong việc có được các giá trị mặc định chính xác. Mỗi cơ chế tránh quá tải đều thêm các biện pháp bảo vệ khác nhau và đều có hiệu quả hạn chế. Bằng cách kiểm thử, một nhóm có thể phát hiện các điểm gây cản trở trong hệ thống của mình và quyết định kết hợp các biện pháp bảo vệ nào cần thiết để xử lý tình trạng quá tải.

Khả năng hiển thị thông tin chi tiết

Tại Amazon, bất kể với kỹ thuật nào chúng tôi sử dụng để bảo vệ dịch vụ của mình khỏi tình trạng quá tải, chúng tôi đều suy nghĩ cẩn thận về các chỉ số và thông tin chi tiết mà chúng tôi cần khi các biện pháp đối phó quá tải này có hiệu lực.

Khi biện pháp bảo vệ bằng giảm hiệu năng (brownout) từ chối yêu cầu, thì điều này làm giảm tính khả dụng của dịch vụ. Khi dịch vụ hiểu nhầm và từ chối yêu cầu cho dù vẫn còn khả năng tiếp nhận (ví dụ như khi số lượng kết nối tối đa bị đặt quá thấp), thì sẽ tạo ra báo động giả. Chúng tôi cố gắng giữ tỷ lệ báo động giả của dịch vụ ở mức 0. Nếu một nhóm thấy rằng tỷ lệ báo động giả của dịch vụ thường xuyên lớn hơn 0, thì dịch vụ đó hoặc bị điều chỉnh quá nhạy cảm, hoặc máy chủ riêng lẻ thường xuyên quá tải và có thể có vấn đề về tăng giảm quy mô hoặc cân bằng tải. Trong những trường hợp như vậy, chúng tôi có thể thực hiện một vài điều chỉnh hiệu năng ứng dụng hoặc chuyển sang loại phiên bản lớn hơn để dịch vụ có thể xử lý tình trạng mất cân bằng tải trong tầm kiểm soát.

Về thông tin chi tiết, khi biện pháp giảm tải từ chối yêu cầu, chúng tôi đảm bảo rằng mình có công cụ phù hợp để biết máy khách là ai, họ đang gọi hoạt động nào và bất kỳ thông tin nào khác sẽ giúp chúng tôi điều chỉnh các biện pháp bảo vệ. Chúng tôi cũng sử dụng cảnh báo để phát hiện xem các biện pháp phòng chống có đang từ chối một lượng lớn lưu lượng hay không. Trong trường hợp giảm hiệu năng, ưu tiên của chúng tôi là tăng khả năng tiếp nhận và xác định điểm gây cản trở hiện tại.

Có một điều đáng cân nhắc tuy nhỏ nhưng rất quan trọng xung quanh khả năng hiển thị thông tin chi tiết trong biện pháp giảm tải. Chúng tôi phát hiện ra rằng việc không làm nhiễu các chỉ sổ độ trễ của dịch vụ bởi độ trễ của dịch vụ không thành công là rất quan trọng. Dù sao thì độ trễ của một yêu cầu giảm tải phải cực thấp so với các yêu cầu khác. Ví dụ: nếu một dịch vụ đang giảm tải 60% lưu lượng, độ trễ trung vị của dịch vụ có thể trông rất tuyệt ngay cả khi độ trễ của yêu cầu thành công rất tệ vì độ trễ đang bị báo cáo dưới mức do ảnh hưởng của các yêu cầu nhanh chóng thất bại.

Ảnh hưởng của biện pháp giảm tải đến khả năng tự động thay đổi quy mô và sự cố tại Vùng sẵn sàng

Nếu bị đặt cấu hình sai, biện pháp giảm tải có thể vô hiệu hóa khả năng tự động thay đổi quy mô đang hoạt động. Hãy xem xét ví dụ sau: một dịch vụ được đặt cấu hình để thay đổi quy mô theo CPU và cũng được đặt cấu hình giảm tải để từ chối yêu cầu tại một mức CPU mục tiêu tương tự. Trong trường hợp này, hệ thống giảm tải sẽ giảm số lượng yêu cầu để giữ lượng tải của CPU ở mức thấp, và khả năng thay đổi quy mô đang hoạt động sẽ không bao giờ nhận hoặc nhận tín hiệu bị trễ để khởi chạy phiên bản mới.

Chúng tôi cũng cẩn thận xem xét logic giảm tải khi đặt giới hạn cho khả năng tự động điều chỉnh quy mô để xử lý sự cố trong Vùng sẵn sàng. Các dịch vụ được điều chỉnh quy mô đến một mức độ mà khả năng tiếp nhận của Vùng sẵn sàng có thể trở nên không khả dụng trong khi duy trì các mục tiêu về độ trễ. Các nhóm Amazon thường xem xét chỉ số hệ thống như CPU để ước tính một dịch vụ ở gần mức giới hạn khả năng tiếp nhận đến đâu. Tuy nhiên với biện pháp giảm tải, một nhóm có thể chạy gần đến mức mà các yêu cầu sẽ bị từ chối hơn mức mà chỉ số hệ thống chỉ ra, và có thể không có khả năng tiếp nhận vượt mức được cung cấp để xử lý sự cố tại Vùng sẵn sàng. Với biện pháp giảm tải, chúng tôi cần phải đặc biệt chắc chắn để kiểm thử dịch vụ của mình bằng cách chia nhỏ nhằm hiểu được khả năng tiếp nhận và khả năng tối đa của nhóm tại mọi thời điểm.

Thực tế, chúng tôi có thể sử dụng biện pháp giảm tải để tiết kiệm chi phí bằng cách định hình lưu lượng không quan trọng ngoài thời điểm cao điểm. Ví dụ: nếu một nhóm xử lý lưu lượng trang web cho amazon.com, nhóm này có thể quyết định rằng lưu lượng trình thu thập dữ liệu tìm kiếm không đáng để tăng quy mô nhằm đạt được khả năng dự phòng đầy đủ cho Vùng sẵn sàng. Tuy nhiên chúng tôi vô cùng cẩn trọng với cách tiếp cận này. Không phải tất cả các yêu cầu đều có chi phí như nhau và việc chứng minh rằng một dịch vụ cần phải cung cấp khả năng dự phòng cho Vùng sẵn sàng để vừa dành cho lưu lượng truy cập của con người và vừa để loại bỏ lưu lượng thu thập dữ liệu vượt mức yêu cầu thiết kế cẩn thận, kiểm thử liên tục và cân nhắc thận trọng từ doanh nghiệp. Và nếu máy khách của một dịch vụ không biết rằng dịch vụ được đặt cấu hình theo cách này, hành vi của dịch vụ trong quá trình xảy ra sự cố tại Vùng sẵn sàng có thể giống như sự sụt giảm nghiêm trọng tính khả dụng thay vì một tính năng giảm tải không quan trọng. Vì lý do này, trong một kiến trúc hướng dịch vụ, chúng tôi cố gắng thúc đẩy kiểu định hình này càng sớm càng tốt (chẳng hạn như trong dịch vụ nhận được yêu cầu ban đầu từ máy khách) thay vì cố gắng đưa ra quyết định ưu tiên trong toàn bộ hệ thống.

Cơ chế giảm tải

Khi thảo luận về biện pháp giảm tải và các kịch bản không thể lường trước, việc tập trung vào các điều kiện có thể dự đoán có thể dẫn đến suy giảm hiệu năng cũng rất quan trọng. Tại Amazon, các dịch vụ duy trì khả năng tiếp nhận vượt mức đủ để xử lý sự cố trong Vùng sẵn sàng mà không cần thêm khả năng tiếp nhận. Các dịch vụ này dùng biện pháp điều chỉnh lưu lượng (throttling) để đảm bảo không có sự khác biệt giữa tất cả máy khách.

Tuy nhiên, bất chấp các biện pháp bảo vệ và vận hành này, một dịch vụ chỉ có một khả năng tiếp nhận nhất định tại một thời điểm bất kỳ, do đó có thể trở nên quá tải vì nhiều lý do. Những lý do này bao gồm lưu lượng truy cập tăng đột ngột, khả năng tiếp nhận của nhóm bị mất đột ngột (do triển khai kém hoặc lý do khác), máy khách chuyển từ thực hiện các yêu cầu giá rẻ (như đọc bộ nhớ đệm) sang các yêu cầu đắt tiền (như yêu cầu xử lý bởi thành phần không có trong bộ nhớ đệm (cache miss) hoặc ghi bộ nhớ đệm). Khi trở nên quá tải, dịch vụ phải hoàn thành các yêu cầu đã tiếp nhận. Đó là điều mà các dịch vụ phải làm để tự bảo vệ khỏi việc suy giảm hiệu năng. Trong phần còn lại của phần này, chúng ta sẽ thảo luận về một số cân nhắc và kỹ thuật mà chúng tôi đã sử dụng trong nhiều năm để quản lý vấn đề quá tải.

Hiểu rõ chi phí của việc ngừng xử lý yêu cầu

Chúng tôi đảm bảo kiểm thử độ chịu tải vượt xa thời điểm goodput ổn định sau khi tăng. Một trong những lý do chính cho phương pháp này là để đảm bảo rằng khi chúng tôi ngừng xử lý yêu cầu trong khi giảm tải, chi phí của hành động này cần phải nhỏ nhất có thể. Chúng tôi thấy rằng thật dễ dàng bỏ lỡ một câu lệnh ghi nhật ký tình cờ hoặc một cài đặt socket. Điều này có thể khiến việc ngừng xử lý yêu cầu có chi phí đắt đỏ hơn nhiều sơ với yêu cầu.

Trong những trường hợp hiếm hoi, việc nhanh chóng ngừng xử lý yêu cầu có thể đắt đỏ hơn việc giữ lại yêu cầu. Trong trường hợp này, chúng tôi sẽ làm chậm các yêu cầu bị từ chối để khớp với độ trễ (ở mức nhỏ nhất) của các phản hồi thành công. Tuy nhiên, điều quan trọng là phải làm điều này khi chi phí của việc giữ lại yêu cầu thấp nhất có thể, ví dụ như khi các yêu cầu không liên kết với luồng ứng dụng.

Ưu tiên yêu cầu

Khi bị quá tải, máy chủ có cơ hội để phân loại các yêu cầu đến để quyết định xem nên chấp nhận và từ chối yêu cầu nào. Yêu cầu quan trọng nhất mà máy chủ sẽ nhận là yêu cầu ping từ cân bằng tải. Nếu máy chủ không đáp ứng kịp thời các yêu cầu ping, cân bằng tải sẽ ngừng gửi các yêu cầu mới đến máy chủ đó trong một khoảng thời gian và máy chủ sẽ không hoạt động. Và trong kịch bản giảm công suất, điều cuối cùng chúng ta mong đợi là giảm kích thước nhóm. Ngoài các yêu cầu ping, các lựa chọn ưu tiên yêu cầu khác nhau tùy theo dịch vụ.

Hãy xem xét một dịch vụ web cung cấp dữ liệu để kết xuất amazon.com. Một cuộc gọi dịch vụ hỗ trợ kết xuất trang web cho trình thu thập chỉ mục tìm kiếm có thể ít quan trọng hơn so với yêu cầu từ con người. Yêu cầu của trình thu thập thông tin rất quan trọng nhưng hoàn toàn có thể được chuyển sang khoảng thời gian thấp điểm. Tuy nhiên, trong một môi trường phức tạp như amazon.com nơi có một số lượng lớn các dịch vụ hợp tác với nhau, nếu các dịch vụ sử dụng phương pháp phỏng đoán ưu tiên bị xung đột, thì tính khả dụng trên toàn hệ thống có thể bị ảnh hưởng và công việc có thể bị lãng phí.

Chúng ta có thể sử dụng đồng thời biện pháp ưu tiên và điều chỉnh để tránh giới hạn điều chỉnh nghiêm ngặt trong khi vẫn bảo vệ dịch vụ khỏi quá tải. Tại Amazon, trong trường hợp chúng tôi cho phép máy khách vượt quá giới hạn điều chỉnh được đặt cấu hình, các yêu cầu vượt mức từ các máy khách này có thể ở mức ưu tiên thấp hơn so với yêu cầu trong hạn mức từ các máy khách khác. Chúng tôi dành nhiều thời gian tập trung vào các thuật toán phân bổ để giảm thiểu khả năng tiếp nhận vượt mức trở nên không khả dụng, nhưng sau khi cân nhắc thiệt hơn, chúng tôi ưu tiên khối lượng công việc được cung cấp có thể dự đoán thay vì khối lượng công việc không thể đoán trước.

Chú ý tới đồng hồ

Nếu một dịch vụ đang trong quá trình phân phối yêu cầu và nhận thấy rằng máy khách đã hết thời gian chờ, thì dịch vụ đó có thể bỏ qua phần còn lại của công việc và không thực hiện được yêu cầu tại thời điểm đó. Nếu không, máy chủ sẽ tiếp tục làm việc theo yêu cầu và phản hồi muộn từ máy chủ sẽ là vô nghĩa. Từ phía máy chủ, thì đó là một phản hồi thành công. Nhưng từ phía máy khách đã hết thời gian chờ, thì đó là một lỗi.

Một cách để tránh được việc làm vô nghĩa này là để máy khách đưa dấu hiệu về thời gian chờ vào mỗi yêu cầu và cho máy chủ biết mình có thể chờ bao lâu. Máy chủ có thể đánh giá các dấu hiệu này và ngừng xử lý các yêu cầu không thành công với chi phí thấp.

Gợi ý thời gian chờ này có thể được biểu thị dưới dạng thời gian tuyệt đối hoặc khoảng thời gian. Thật không may, máy chủ trong các hệ thống phân tán có tiếng là tệ trong việc thống nhất thời gian chính xác hiện tại. Bù lại, Amazon Time Sync Service sẽ đồng bộ hóa thời gian trong các phiên bản Amazon Elastic Compute Cloud (Amazon EC2) của bạn với một nhóm đồng hồ nguyên tử được điều khiển bởi vệ tinh trong mỗi Khu vực AWS. Các đồng hồ được đồng bộ hóa cũng rất quan trọng tại Amazon cho mục đích ghi nhật ký. So sánh hai tệp nhật ký trên các máy chủ có đồng hồ không được đồng bộ khiến việc khắc phục sự cố thậm chí còn khó hơn so với khi bắt đầu.

Cách còn lại để “xem đồng hồ” là đo khoảng thời gian trên một máy. Máy chủ đo chính xác khoảng thời gian trôi qua cục bộ vì không cần nhận được sự chấp thuận từ các máy chủ khác. Thật không may, việc biểu thị thời gian chờ theo khoảng thời gian cũng có những vấn đề riêng. Đầu tiên, bộ tính giờ bạn sử dụng phải được giám sát và không chạy lùi khi máy chủ đồng bộ với Giao thức đồng bộ thời gian mạng (NTP). Một vấn đề khó khăn hơn nhiều là để đo khoảng thời gian, máy chủ phải biết được khi nào cần khởi động đồng hồ bấm giờ. Trong một số trường hợp cực kỳ quá tải, khối lượng yêu cầu khổng lồ có thể xếp hàng trong bộ đệm Giao thức kiểm soát truyền tải (TCP), do đó, khi máy chủ đọc yêu cầu từ bộ đệm, máy khách đã hết thời gian.

Bất cứ khi nào hệ thống tại Amazon có dấu hiệu về thời gian chờ, chúng tôi sẽ cố gắng áp dụng các dấu hiệu này với đối tượng trực tiếp. Ở những nơi mà kiến trúc hướng dịch vụ bao gồm nhiều bước nhảy, chúng tôi truyền “thời gian còn lại” của thời hạn giữa mỗi bước nhảy để dịch vụ từ máy chủ đến máy khách ở cuối chuỗi cuộc gọi có thể nhận ra cần bao nhiêu thời gian để phản hồi thành công.

Khi máy chủ biết được thời hạn của máy khách, sẽ có một câu hỏi về vị trí thực thi thời hạn trong việc triển khai dịch vụ. Nếu dịch vụ có hàng đợi yêu cầu, chúng tôi sẽ sử dụng cơ hội đó để đánh giá thời gian chờ sau khi giải quyết từng yêu cầu. Nhưng điều này vẫn rất phức tập vì chúng tôi không biết được cần bao lâu để giải quyết yêu cầu. Một số hệ thống vẫn ước tính thời gian cần để xử lý yêu cầu API và các hệ thống này sẽ sớm ngừng xử lý yêu cầu nếu thời hạn mà máy khách báo cáo vượt quá độ trễ ước tính. Tuy nhiên, mọi thứ hiếm khi đơn giản như vậy. Ví dụ: thao tác xử lý bởi thành phần có trong bộ nhớ đệm (cache hit) diễn ra nhanh hơn so với thành phần không có trong bộ nhớ đệm (cache miss) và bộ ước tính không biết trước đó là cache hit hay cache miss. Hoặc các tài nguyên backend của dịch vụ có thể được phân vùng và có thể chỉ có một vài phân vùng bị chậm. Có rất nhiều cơ hội để thực hiện các biện pháp tài tình, nhưng chính sự tài tình này cũng có thể gây ra tác dụng ngược trong tình huống không lường trước.

Theo kinh nghiệm của chúng tôi, việc thực thi thời gian chờ của máy khách trên máy chủ vẫn tốt hơn so với giải pháp thay thế, bất chấp sự phức tạp và đánh đổi. Thay vì các yêu cầu chồng chất và máy chủ có thể xử lý các yêu cầu không còn quan trọng đối với bất kỳ ai, chúng tôi thấy việc thực thi “thời gian tồn tại (time-to-live) theo yêu cầu” và bỏ đi các yêu cầu không thành công là có ích.

Kết thúc những gì chúng tôi đã bắt đầu

Chúng tôi không muốn các công việc có ích bị lãng phí, đặc biệt trong trường hợp quá tải. Việc bỏ đi công việc tạo ra vòng lặp phản hồi tích cực làm tăng tình trạng quá tải do máy khách thường thử yêu cầu lại nếu dịch vụ không phản hồi kịp thời. Khi điều này xảy ra, một yêu cầu tốn tài nguyên sẽ trở thành rất nhiều yêu cầu tốn tài nguyên, làm tăng khối lượng tải trên dịch vụ lên nhiều lần. Khi máy khách hết thời gian và thử lại, chúng thường thôi chờ đợi phản hồi trên kết nối đầu tiên trong khi lại tạo yêu cầu mới trên kết nối khác. Nếu máy chủ hoàn thành yêu cầu đầu tiên và phản hồi, máy khách có thể không tiếp nhận vì máy khách hiện đang chờ phản hồi từ yêu cầu thử lại.

Vấn đề của công việc bị lãng phí này là lý do chúng tôi cố gắng thiết kế dịch vụ để thực hiện công việc bị giới hạn. Ở những nơi chúng tôi đưa ra một API có thể trả về một bộ dữ liệu lớn (hoặc thực sự là bất kỳ danh sách nào), thì API đó sẽ có dạng như một API hỗ trợ phân trang. Các API này trả về một phần kết quả và mã thông báo mà khách hàng có thể sử dụng để yêu cầu thêm dữ liệu. Chúng tôi thấy rằng việc ước tính tải bổ sung trên dịch vụ dễ dàng hơn khi máy chủ xử lý yêu cầu có giới hạn trên với dung lượng bộ nhớ, CPU và băng thông mạng. Rất khó để thực hiên việc kiểm soát đầu vào khi máy chủ không biết phải tiếp nhận những gì để xử lý yêu cầu.

Một cơ hội tinh vi hơn để ưu tiên yêu cầu nằm ở cách máy khách sử dụng API của dịch vụ. Ví dụ: cho rằng dịch vụ có 2 API: start()end(). Để hoàn tất công việc, máy khách cần phải gọi được cả 2 API. Trong trường hợp đó, dịch vụ nên ưu tiên yêu cầu end() thay vì yêu cầu start(). Nếu ưu tiên start(), máy khách sẽ không thể hoàn thành công việc đã bắt đầu, dẫn đến tình trạng giảm hiệu năng.

Phân trang cũng là một nơi cần chú ý để không lãng phí công việc. Nếu máy khách phải tạo một vài yêu cầu theo trình tự để phân trang thông qua kết quả từ dịch vụ, và thấy sự cố sau trang N-1 rồi bỏ đi kết quả, thì các cuộc gọi dịch vụ N-2 cũng như tất cả những lần thử lại mà máy khách đã thực hiện trong suốt quá trình sẽ bị lãng phí. Điều này gợi ý rằng cũng như yêu cầu end(), yêu cầu của trang đầu tiên cũng nên được ưu tiên sau yêu cầu phân trang của các trang sau. Điều này cũng nhấn mạnh lý do tại sao chúng tôi thiết kế các dịch vụ để thực hiện công việc bị giới hạn và không phân trang vô tận thông qua một dịch vụ mà các máy khách gọi trong một hoạt động đồng bộ.

Chú ý tới hàng đợi

Việc xem xét thời lượng của yêu cầu khi quản lý hàng đợi nội bộ cũng có ích. Rất nhiều kiến trúc dịch vụ hiện đại sử dụng hàng đợi trong bộ nhớ để kết nối các tập hợp luồng để xử lý yêu cầu trong các giai đoạn khác nhau của công việc. Framework dịch vụ web có bộ thực thi thường sẽ có hàng đợi được đặt cấu hình phía trước. Với bất kỳ dịch vụ dựa trên TCP nào, hệ điều hành sẽ duy trì bộ đệm cho mỗi socket và những bộ đệm đó có thể chứa một khối lượng lớn các yêu cầu bị tích tụ.

Khi kéo công việc khỏi hàng đợi, chúng tôi sử dụng cơ hội đó để kiểm tra xem công việc đã ở trong hàng đợi bao lâu. Ít nhất, chúng tôi sẽ cố gắng ghi lại khoảng thời gian đó trong các chỉ số dịch vụ của mình. Ngoài việc giới hạn kích thước của hàng đợi, chúng tôi còn thấy việc đặt giới hạn trên vào khoảng thời gian mà yêu cầu đến nằm trên hàng đợi là vô cùng quan trọng, và chúng tôi sẽ yêu cầu ra khỏi hàng đợi nếu yêu cầu quá cũ. Việc này giải phóng máy chủ để làm việc trên các yêu cầu mới hơn có cơ hội thành công cao hơn. Khi áp dụng cực đoan phương thức tiếp cận này, chúng tôi tìm cách sử dụng hàng đợi vào sau, ra trước (LIFO), nếu giao thức hỗ trợ. (Đường ống HTTP/1.1 của yêu cầu trên kết nối TCP đã cho không hỗ trợ các hàng đợi LIFO, nhưng HTTP/2 thường lại có.)

Cân bằng tải cũng có thể xếp hàng đợi các yêu cầu hoặc kết nối đến khi dịch vụ bị quá tải bằng tính năng được gọi là hàng đợi phát sinh. Các hàng đợi này có thể dẫn đến tình trạng giảm hiệu năng vì máy chủ, khi cuối cùng cũng nhận được yêu cầu, lại không biết yêu cầu đó đã ở trong hàng đợi bao lâu. Biện pháp mặc định an toàn thường là sử dụng cấu hình tràn, nhanh chóng ngừng xử lý thay vì cho vào hàng đợi các yêu cầu vượt mức. Tại Amazon, quá trình học này đã được đưa vào thế hệ dịch vụ Elastic Load Balancing (ELB) tiếp theo. Cân bằng tải cổ điển từng sử dụng hàng chờ phát sinh nhưng Cân bằng tải ứng dụng từ chối lưu lượng vượt mức. Bất kể cấu hình là gì, các nhóm tại Amazon đều giám sát các chỉ số cân bằng tải có liên quan như độ sâu hàng đợi phát sinh hoặc số lượng tràn cho các dịch vụ của họ.

Theo kinh nghiệm của chúng tôi, tầm quan trọng của chú ý tới hàng đợi không thể bị cường điệu hóa. Tôi thường ngạc nhiên khi thấy hàng đợi trong bộ nhớ nơi tôi thường không nghĩ sẽ tìm được chúng, trong các hệ thống và thư viện mà tôi dựa vào. Khi tôi đào sâu vào các hệ thống, tôi thấy rằng nó việc cho rằng có hàng đợi ở đâu đó mà mình không biết là rất hữu ích. Tất nhiên, việc kiểm thử tình trạng quá tải cung cấp nhiều thông tin hữu ích hơn là đào sâu vào mã, miễn là tôi có thể đưa ra các trường hợp kiểm thử thực tế và chính xác.

Bảo vệ khỏi tình trạng quá tải tại các lớp thấp hơn

Dịch vụ được tạo nên bởi nhiều lớp ─ từ cân bằng tải đến hệ điều hành với khả năng netfilteriptables, cho đến framework dịch vụ và mã — mỗi lớp cung cấp một số khả năng để bảo vệ dịch vụ.

Các proxy HTTP như NGINX thường hỗ trợ tính năng kết nối tối đa (max_conns) để giới hạn số lượng yêu cầu hoặc kết nối đang hoạt động mà proxy sẽ chuyển đến máy chủ backend. Đây có thể là một cơ chế hữu ích nhưng chúng tôi học cách sử dụng khả năng này như phương sách cuối cùng thay vì là lựa chọn bảo vệ mặc định. Với proxy, thật khó để ưu tiên lưu lượng quan trọng, và việc theo dõi số lượng yêu cầu thô đang diễn ra đôi khi cung cấp thông tin không chính xác về việc dịch vụ có thật sự quá tải hay không.

Trong phần đầu của bài viết này, tôi đã mô tả một thách thức trong thời gian làm việc của tôi tại nhóm Framework dịch vụ. Vào thời điểm đó, chúng tôi đang cố gắng cung cấp cho các nhóm Amazon một giá trị mặc định khuyến nghị cho số kết nối tối đa để đặt cấu hình trên cân bằng tải của họ. Cuối cùng, chúng tôi gợi ý rằng các nhóm này đặt số kết nối tối đa cao cho cân bằng tải và proxy rồi để máy chủ triển khai thuật toán giảm tải chính xác hơn bằng thông tin cục bộ. Tuy nhiên, giá trị kết nối tối đa không được vượt quá số luồng trình nghe, quy trình của trình nghe hoặc đặc tả tệp để máy chủ có tài nguyên nhằm xử lý yêu cầu kiểm tra trạng thái quan trọng từ cân bằng tải.

Các tính năng của hệ điều hành để hạn chế sử dụng tài nguyên máy chủ rất mạnh mẽ và có thể hữu ích để sử dụng trong trường hợp khẩn cấp. Và bởi vì chúng tôi biết rằng tình trạng quá tải có thể xảy ra, chúng tôi đảm bảo chuẩn bị cho trường hợp đó bằng cách sử dụng đúng tài liệu vận hành với các lệnh cụ thể sẵn sàng. Tiện ích iptables có thể đặt giới hạn trên cho số lượng kết nối mà máy chủ sẽ chấp nhận và có thể từ chối các kết nối vượt mức với chi phí thấp hơn nhiều so với bất kỳ quy trình máy chủ nào. Tiện ích này cũng có thể được cấu hình với các điều khiển tinh vi hơn, như cho phép các kết nối mới ở tốc độ giới hạn hoặc thậm chí cho phép tốc độ kết nối giới hạn hoặc số lượng giới hạn trên mỗi địa chỉ IP nguồn. Bộ lọc IP nguồn rất mạnh mẽ nhưng lại không áp dụng cho cân bằng tải truyền thống. Tuy nhiên, Network Load Balancer ELB bảo toàn IP nguồn của người gọi ngay cả ở lớp hệ điều hành thông qua ảo hóa mạng, làm cho các quy tắc iptables như bộ lọc IP nguồn hoạt động như mong đợi.

Bảo vệ theo lớp

Trong một số trường hợp, một máy chủ hết tài nguyên để thậm chí từ chối các yêu cầu mà không bị chậm lại. Với thực tế này, chúng tôi xem xét tất cả các bước nhảy giữa máy chủ và máy khách để xem cách chúng có thể hợp tác và giúp giảm tải quá mức. Ví dụ: một số dịch vụ AWS bao gồm các tùy chọn giảm tải theo mặc định. Khi chúng tôi đặt Amazon API Gateway trước một dịch vụ, chúng tôi có thể đặt cấu hình tốc độ yêu cầu tối đa mà bất kỳ API nào sẽ chấp nhận. Khi API Gateway, một Cân bằng tải ứng dụng hoặc Amazon CloudFront hậu thuẫn cho các dịch vụ của chúng tôi, chúng tôi có thể đặt cấu hình AWS WAF để giảm lưu lượng vượt mức trên một số chỉ số.

Khả năng hiển thị thông tin chi tiết gây ra chút căng thẳng. Việc từ chối sớm là rất quan trọng bởi vì đó là nơi có chi phí thấp nhất để giảm lưu lượng vượt mức, nhưng lúc đó chúng ta phải đánh đổi khả năng hiển thị thông tin chi tiết. Đó là lý do chúng tôi bảo vệ theo lớp: nhằm cho phép máy chủ tiếp nhận nhiều hơn khả năng nó có thể làm việc và ngừng xử lý những yêu cầu vượt mức, và ghi lại đủ thông tin để biết được lưu lượng nào đang bị ngừng xử lý. Do có quá nhiều lưu lượng mà máy chủ có thể ngừng xử lý, chúng tôi dựa vào lớp phía trước để bảo vệ máy chủ khỏi lưu lượng vượt mức.

Nghĩ khác đi về quá tải

Trong bài viết này, chúng ta đã thảo luận về cách nhu cầu giảm tải phát sinh từ thực tế là các hệ thống trở nên chậm hơn khi chúng được giao nhiều công việc đồng thời hơn, khi các yếu tố như giới hạn và tranh chấp tài nguyên xuất hiện. Vòng phản hồi của tình trạng quá tải được điều khiển bởi độ trễ, thứ cuối cùng sẽ gây ra lãng phí công việc, khuếch đại tốc độ yêu cầu và thậm chí quá tải hơn. Yếu tố này, được thúc đẩy bởi Định luật khả năng mở rộng phổ quát và Định luật Amdahl, là rất quan trọng để đi đường vòng bằng cách giảm tải vượt mức và duy trì hiệu năng ổn định, có thể dự đoán được trước trạng thái quá tải. Việc tập trung vào hiệu suất ổn định, có thể dự đoán được là một nguyên tắc thiết kế quan trọng làm nền tảng cho các dịch vụ tại Amazon.

Ví dụ: Amazon DynamoDB là một dịch vụ cơ sở dữ liệu cung cấp hiệu suất và tính khả dụng có thể dự đoán ở quy mô lớn. Ngay cả khi một khối lượng công việc tăng đột biến và vượt quá các tài nguyên được cung cấp, DynamoDB vẫn duy trì độ trễ goodput có thể dự đoán cho khối lượng công việc đó. Các yếu tố như khả năng tự động thay đổi quy mô của DynamoDB, khả năng tiếp nhận thích ứngtheo nhu cầu phản ứng nhanh để tăng tốc độ goodput nhằm thích nghi với khối lượng công việc tăng. Trong thời gian đó, goodput vẫn ổn định cũng như giữ cho dịch vụ trong các lớp trên DynamoDB hoạt động với hiệu năng có thể dự đoán được, và cải thiện tính ổn định của toàn hệ thống.

AWS Lambda cung cấp một ví dụ thậm chí còn rộng hơn về sự tập trung vào hiệu suất có thể dự đoán được. Khi chúng tôi sử dụng Lambda để triển khai dịch vụ, mỗi lệnh gọi API chạy trong môi trường thực thi riêng của mình với lượng tài nguyên điện toán ổn định được phân bổ cho từng lệnh, và vào từng thời điểm, môi trường thực thi đó chỉ hoạt động trên một yêu cầu cụ thể. Điều này khác với mô hình dựa trên máy chủ, nơi một máy chủ nhất định hoạt động trên nhiều API.

Việc cách ly mỗi lệnh gọi API với các tài nguyên độc lập của riêng lệnh gọi đó (tài nguyên điện toán, bộ nhớ, ổ đĩa, mạng) sẽ phá vỡ định luật Amdahl ở một mức độ nào đó, bởi vì tài nguyên của một lệnh gọi API sẽ không cạnh tranh với các tài nguyên của lệnh gọi API khác. Do đó, nếu thông lượng vượt quá goodput, goodput sẽ vẫn ổn định thay vì giảm xuống như trong môi trường dựa trên máy chủ truyền thống hơn. Đây không phải là thuốc chữa bách bệnh, vì phần phụ thuộc có thể chậm lại và khiến tính tương tranh tăng lên. Tuy nhiên, trong kịch bản này, ít nhất là các kiểu tranh chấp tài nguyên trên máy chủ mà chúng tôi đã thảo luận trong bài viết này sẽ không được áp dụng.

Sự cô lập tài nguyên này là một lợi ích nhỏ nhưng có ý nghĩa của các môi trường điện toán serverless hiện đại như AWS Fargate, Amazon Elastic Container Service (Amazon ECS) và AWS Lambda. Tại Amazon, chúng tôi đã thấy rằng cần làm rất nhiều việc để triển khai giảm tải, từ việc điều chỉnh tập hợp luồng, đến chọn cấu hình hoàn hảo cho các kết nối cân bằng tải tối đa. Rất khó hoặc không thể tìm thấy các giá trị mặc định hợp lý cho các loại cấu hình này bởi vì chúng phụ thuộc vào đặc điểm vận hành duy nhất của mỗi hệ thống. Các môi trường điện toán serverless mới hơn này cung cấp sự cách ly tài nguyên ở mức thấp hơn và hiển thị các nút ở mức cao hơn, như điều khiển điều chỉnh lưu lượng và tính tương tranh, để bảo vệ chống quá tải. Ở một mức độ nào đó, thay vì theo đuổi giá trị cấu hình mặc định hoàn hảo, chúng tôi có thể hoàn toàn bỏ qua cấu hình đó và bảo vệ khỏi các loại quá tải mà không cần bất kỳ cấu hình nào.

Đọc thêm

Định luật khả năng mở rộng phổ quát
Định luật Amdahl
Kiến trúc làm việc với sự kiện theo giai đoạn (SEDA)
Định luật Little (mô tả tính tương tranh trong hệ thống và cách xác định khả năng tiếp nhận của hệ thống phân tán)
Kể chuyện về Định luật Little, Blog của Marc
Elastic Load Balancing Deep Dive and Best Practices, bài thuyết trình tại re:Invent 2016 (mô tả quá trình phát triển của Elastic Load Balancing để dừng đưa yêu cầu vượt mức vào hàng đợi)
• Burgess, Thinking in Promises: Designing Systems for Cooperation (Suy nghĩ với tư duy Promise: Thiết kế hệ thống để hợp tác), O’Reilly Media, 2015



Giới thiệu về tác giả

David Yanacek là Kỹ sư chính cấp cao làm việc với AWS Lambda. David là nhà phát triển phần mềm tại Amazon từ năm 2006, trước đây đã làm việc với Amazon DynamoDB và AWS IoT, cũng như các khung dịch vụ web nội bộ và các hệ thống tự động hóa nghiệp vụ nhóm. Một trong những hoạt động yêu thích của David tại nơi làm việc là thực hiện phân tích nhật ký và sàng lọc các số liệu hoạt động để tìm cách làm cho hệ thống vận hành ngày càng trơn tru hơn.

Thời gian chờ, thử lại và rút lại với phương sai độ trễ Tiến hành kiểm tra tình trạng Đo lường hệ thống phân tán để hiểu rõ về hoạt động vận hành