Các sự cố nghiêm trọng khiến một dịch vụ không thể cung cấp kết quả hữu ích. Ví dụ: trong một trang web thương mại điện tử, nếu một truy vấn thông tin sản phẩm trong cơ sở dữ liệu gặp lỗi, thì trang web không thể hiển thị thành công trang sản phẩm. Các dịch vụ của Amazon phải xử lý phần lớn các lỗi nghiêm trọng để hoạt động ổn định. Có bốn loại chiến lược chính để xử lý các lỗi nghiêm trọng:

Thử lại: Thực hiện lại hoạt động bị lỗi, ngay lập tức hoặc sau một khoảng thời gian.
Chủ động thử lại: Thực hiện hoạt động nhiều lần cùng một lúc và sử dụng lần đầu tiên hoàn tất.
Chuyển đổi dự phòng: Thực hiện lại hoạt động bằng một bản sao điểm cuối khác hoặc tốt nhất là thực hiện nhiều bản sao song song của hoạt động để tăng cơ hội thành công của ít nhất một bản sao.
Dự phòng: Dùng một cơ chế khác để đạt được cùng một kết quả.

Bài viết này đề cập đến các chiến lược dự phòng và lý do chúng tôi gần như không bao giờ dùng chiến lược dự phòng ở Amazon. Bạn có thể thấy ngạc nhiên. Xét cho cùng thì các kỹ sư thường dựa vào thế giới thật để làm điểm bắt đầu cho thiết kế của họ. Và trong thế giới thật, người ta phải lên kế hoạch trước cho chiến lược dự phòng và sử dụng khi cần thiết. Giả sử các bảng thông báo của một sân bay bị mất điện. Sân bay phải có kế hoạch dự phòng (chẳng hạn như viết tay thông tin về chuyến bay lên bảng trắng) để xử lý tình huống này vì hành khách vẫn cần tìm cửa khởi hành của họ. Nhưng hãy xem kế hoạch dự phòng này đáng sợ đến thế nào nhé! Thứ nhất là đọc thông tin trên bảng trắng đâu có dễ, rồi cập nhật những thông tin ấy cũng khó và còn có khả năng viết sai thông tin nữa chứ. Vậy là chiến lược dự phòng bằng bảng trắng là cần thiết nhưng lại kéo theo nhiều vấn đề.

Trong thế giới hệ thống phân tán, chiến lược dự phòng thuộc những thách thức khó xử lý nhất, đặc biệt là với dịch vụ nhạy cảm về thời gian. Đâu chỉ có khó khăn này, chiến lược dự phòng không hiệu quả còn mất nhiều thời gian (thậm chí tính bằng năm) để xóa nhòa tiếng xấu, trong khi rất khó phân định sự khác biệt giữa chiến lược hiệu quả và không hiệu quả. Trong bài viết này, chúng tôi sẽ tập trung lý giải vì sao chiến lược dự phòng có thể gây ra nhiều vấn đề hơn là khắc phục sự cố. Chúng tôi sẽ lồng ghép các ví dụ cho thấy Amazon đã gặp rắc rối với chiến lược dự phòng ra sao. Cuối cùng, chúng tôi sẽ thảo luận về các biện pháp thay thế cho chiến lược dự phòng mà Amazon sử dụng.

Chúng tôi sẽ không phân tích chiến lược dự phòng cho dịch vụ vì nó khó hiểu và khó có thể lường trước hiệu ứng lan tỏa của chiến lược này trong hệ thống phân tán. Do đó, hãy xem xét chiến lược dự phòng trong ứng dụng máy đơn trước.

Dự phòng máy đơn

Hãy xem xét đoạn mã C minh họa một kiểu thường gặp khi xử lý lỗi phân bổ bộ nhớ trong nhiều ứng dụng sau đây. Mã này phân bổ bộ nhớ bằng hàm malloc() rồi sao chép bộ đệm hình ảnh sang bộ nhớ đó trong khi thực hiện một số loại chuyển đổi:
pixel_ranges = malloc(image_size); // allocates memory
if (pixel_ranges == NULL) {
  // On error, malloc returns NULL
  exit(1);
}
for (i = 0; i < image_size; i++) {
  pixel_ranges[i] = xform(original_image[i]);
}

Khi malloc gặp lỗi, khôi phục mã này rất khó. Trong thực tế, các lệnh gọi malloc hiếm khi gặp lỗi. Do đó, nhà phát triển thường bỏ qua lỗi của hàm này trong mã. Vì sao chiến lược này lại phổ biến đến vậy? Lý do là vì, trên máy đơn, nếu hàm malloc gặp lỗi, thì có khả năng là máy bị hết bộ nhớ. Do đó, không chỉ một lệnh gọi malloc gặp lỗi mà vấn đề lớn hơn ở đây là có thể máy cũng sớm gặp lỗi. Và thông thường, điều đó nghe có vẻ hợp lý trên máy đơn. Nhiều ứng dụng không quan trọng đến mức phải khiến nhà phát triển tốn sức xử lý vấn đề hóc búa như vậy. Nhưng nếu bạn thực sự muốn xử lý lỗi này thì sao? Thử làm điều gì đó hữu ích trong tình huống đó khá là khoai đấy. Giả sử chúng tôi triển khai một phương pháp thứ hai gọi là malloc2 để phân bổ bộ nhớ theo cách khác và chúng tôi sẽ gọi malloc2 nếu việc triển khai malloc mặc định không thành công:

pixel_ranges = malloc(image_size);
if (pixel_ranges == NULL) {
  pixel_ranges = malloc2(image_size);
}

Thoạt đầu, có vẻ như mã này có thể hoạt động hiệu quả, nhưng nó cũng đi kèm với vấn đề, một số vấn đề khó phát hiện ra hơn những vấn đề khác. Đầu tiên là khó kiểm thử lô-gic dự phòng. Chúng tôi có thể chặn lệnh gọi malloc và đưa lỗi vào nhưng điều đó có thể mô phỏng không chính xác tình huống sẽ xảy ra trong môi trường sản xuất. Trong môi trường sản xuất, nếu malloc gặp lỗi, thì máy rất có khả năng bị hết hoặc sắp hết bộ nhớ. Bạn mô phỏng những vấn đề nghiêm trọng hơn về bộ nhớ đó bằng cách nào? Ngay cả khi có thể tạo một môi trường bộ nhớ thấp để kiểm thử (trong bộ chứa Docker chẳng hạn), thì bạn định thời gian cho điều kiện bộ nhớ thấp bằng cách nào để nó trùng với việc thực thi mã dự phòng malloc2?

Một vấn đề khác là bản thân chiến lược dự phòng cũng có thể gặp lỗi. Mã dự phòng trước đó không xử lý được lỗi malloc2. Do đó, chương trình không cung cấp nhiều lợi ích như bạn có thể đã nghĩ. Chiến lược dự phòng có thể giúp giảm khả năng xảy ra lỗi hoàn toàn nhưng điều đó không phải là không thể xảy ra. Ở Amazon, chúng tôi thấy rằng việc dành nguồn lực kỹ thuật để làm cho mã chính (không phải dự phòng) hoạt động ổn định hơn luôn giúp tăng cơ hội thành công hơn là đầu tư vào chiến lược dự phòng ít khi sử dụng.

Hơn nữa, nếu độ sẵn sàng là vấn đề ưu tiên cao nhất của chúng tôi thì chiến lược dự phòng có thể không đáng để đổi lấy rủi ro. Vì sao phải bận tâm đến malloc khi malloc2 có cơ hội thành công cao hơn? Về lô-gic, malloc2 phải đánh đổi để có độ sẵn sàng cao hơn. Có thể hàm này phân bổ bộ nhớ trong bộ lưu trữ dựa trên SSD có độ trễ cao hơn nhưng dung lượng lớn hơn. Nhưng điều đó đặt ra câu hỏi, vì sao malloc2 đánh đổi thì lại được? Hãy xem xét một chuỗi biến cố tiềm ẩn có khả năng xảy đến với chiến lược dự phòng này. Đầu tiên, khách hàng đang sử dụng ứng dụng. Đột nhiên (vì malloc gặp lỗi), malloc2 hoạt động và ứng dụng bị chậm lại. Điều đó thật tệ: Việc chạy chậm hơn có ổn không? Và vấn đề không dừng lại ở đó. Nhớ là máy rất có khả năng bị hết (hoặc sắp hết) bộ nhớ. Lúc này, khách hàng gặp phải hai vấn đề (ứng dụng chậm hơn và máy chậm hơn) chứ không phải một nữa. Tác dụng phụ của việc chuyển đổi sang malloc2 còn có thể khiến vấn đề tổng thể trở nên trầm trọng. Ví dụ: các hệ thống phụ khác cũng có thể bị tranh giành cho cùng một bộ lưu trữ dựa trên SSD.

Lô-gic dự phòng cũng có thể đặt tải khó dự đoán lên hệ thống. Thậm chí lô-gic đơn giản, thông thường như ghi thông báo lỗi vào nhật ký với một theo dõi ngăn xếp tưởng như vô hại, nhưng nếu điều gì đó đột ngột thay đổi để khiến lỗi đó xảy ra với tốc độ cao, thì ứng dụng hướng CPU có thể bất ngờ biến thành ứng dụng hướng I/O. Và nếu không cung cấp ổ đĩa để xử lý tác vụ ghi ở tốc độ đó hoặc để lưu trữ lượng dữ liệu đó, thì ứng dụng có thể gặp lỗi hoặc chạy chậm.

Chiến lược dự phòng không chỉ khiến vấn đề thêm nghiêm trọng mà nó còn có khả năng xảy ra dưới dạng một lỗi ngầm. Phát triển chiến lược dự phòng hiếm khi kích hoạt trong môi trường sản xuất thì dễ. Có khi một máy chủ của khách hàng phải hoạt động vài năm mới bị hết bộ nhớ vào đúng thời điểm để kích hoạt dòng mã cụ thể với chiến lược dự phòng malloc2 trình bày ở trên. Nếu có lỗi trong lô-gic dự phòng hoặc một số loại tác dụng phụ khiến vấn đề tổng thể thêm trầm trọng, thì có khả năng là kỹ sư viết mã không còn nhớ mã này hoạt động ra sao và sẽ khó sửa mã hơn. Đối với ứng dụng máy đơn, đây có thể là một sự đánh đổi chấp nhận được trong công việc, nhưng trong hệ thống phân tán, thì hệ quả lại nghiêm trọng hơn nhiều. Chúng ta sẽ thảo luận về các hệ quả trong phần sau.

Tất cả những vấn đề này đều hóc búa và theo kinh nghiệm của mình, thì chúng thường bị bỏ qua trong ứng dụng máy đơn mà không ảnh hưởng đến sự an toàn. Giải pháp phổ biến nhất là giải pháp đã đề cập ở trên: Cứ để lỗi phân bổ bộ nhớ khiến ứng dụng gặp lỗi. Mã phân bổ bộ nhớ cũng chung số phận với phần còn lại của máy và có nhiều khả năng là phần còn lại của máy cũng sẽ gặp lỗi trong trường hợp này. Ngay cả khi không cùng chung số phận, thì ứng dụng lúc đó cũng sẽ ở trạng thái khó lường và như vậy thì sớm gặp lỗi lại là một chiến lược hợp lý. Việc đánh đổi trong công việc là điều dễ hiểu.

Đối với các ứng dụng máy đơn quan trọng phải hoạt động trong trường hợp xảy ra lỗi phân bổ bộ nhớ, thì phân bổ trước toàn bộ bộ nhớ khi khởi động và không bao giờ phụ thuộc vào malloc nữa, ngay cả trong các điều kiện lỗi, là một giải pháp. Amazon đã triển khai chiến lược này nhiều lần. Chẳng hạn như để theo dõi các daemon chạy trên máy chủ sản xuất và daemon Amazon Elastic Compute Cloud (Amazon EC2) sẽ giám sát lỗi CPU của khách hàng.

Dự phòng phân tán

Ở Amazon, chúng tôi không để hệ thống phân tán, đặc biệt là những hệ thống cung cấp phản hồi trong thời gian thực, phải đánh đổi như ứng dụng máy đơn. Một trong các lý do khiến chúng tôi làm vậy là hậu quả mà chúng tôi gặp phải không giống khách hàng. Chúng tôi có thể giả định rằng các ứng dụng đang chạy trên máy được đặt trước khách hàng. Nếu ứng dụng hết bộ nhớ, thì có lẽ khách hàng không hy vọng nó sẽ tiếp tục chạy. Các dịch vụ lại không chạy trên máy mà khách hàng đang trực tiếp sử dụng nên họ lại có kỳ vọng khác. Hơn thế nữa, khách hàng thường sử dụng dịch vụ chính xác bởi vì chúng có tính khả dụng cao hơn so với việc chạy một ứng dụng trên một máy chủ. Do đó, chúng tôi cần đáp ứng nhu cầu của họ. Về lý thuyết, điều này sẽ khiến chúng tôi triển khai chiến lược dự phòng để giúp dịch vụ ổn định hơn. Nhưng không may là dự phòng phân tán cũng gặp tất cả các vấn đề tương tự, thậm chí nhiều hơn khi xét đến các lỗi hệ thống nghiêm trọng.

Khó kiểm thử chiến lược dự phòng phân tán hơn. Dự phòng dịch vụ phức tạp hơn trường hợp ứng dụng máy đơn vì nhiều máy và dịch vụ xuôi tuyến cũng góp phần tạo ra lỗi. Rất khó tái tạo các chế độ lỗi, chẳng hạn như trường hợp quá tải, trong khi kiểm thử, ngay cả khi đã có sẵn bộ kiểm thử trên nhiều máy. Toán học tổ hợp cũng làm tăng số lượng tuyệt đối các trường hợp kiểm thử. Do đó, bạn cần kiểm thử nhiều hơn và chúng khó thiết lập hơn rất nhiều.

Chính các chiến lược dự phòng phân tán cũng có thể gặp lỗi. Mặc dù chiến lược dự phòng có thể đảm bảo sự thành công, nhưng theo kinh nghiệm của chúng tôi, các chiến lược này chỉ cải thiện cơ hội thành công mà thôi.

Chiến lược dự phòng phân tán thường khiến sự cố trở nên trầm trọng. Theo kinh nghiệm của chúng tôi, chiến lược dự phòng làm tăng phạm vi ảnh hưởng của sự cố cũng như tăng thời gian khắc phục.

Chiến lược dự phòng phân tán thường không đáng để đánh đổi lấy rủi ro. Như với malloc2, chiến lược dự phòng thường thực hiện một số loại đánh đổi; nếu không thì chúng ta đã sử dụng nó rồi. Vì sao lại phải sử dụng một chiến lược dự phòng không hiệu quả trong khi điều gì đó đã gặp lỗi?

Chiến lược dự phòng phân tán thường có lỗi tiềm ẩn chỉ xuất hiện khi xảy ra một loạt sự trùng hợp tưởng như không thể, thường là nhiều tháng hoặc năm sau khi sử dụng.
Sự cố mất điện nghiêm trọng trong thế giới thực do cơ chế dự phòng trên trang web bán lẻ Amazon kích hoạt sẽ minh họa toàn bộ những vấn đề này. Sự cố mất điện xảy ra vào khoảng năm 2001 do một tính năng mới gây ra. Tính năng này cung cấp tốc độ giao hàng cập nhật cho toàn bộ sản phẩm hiển thị trên trang web. Tính năng mới này trông như sau:

Hồi đó, kiến trúc trang web chỉ có hai bậc và vì dữ liệu này được lưu trữ trong một cơ sở dữ liệu chuỗi cung ứng, nên các máy chủ web cần trực tiếp truy vấn cơ sở dữ liệu. Thế nhưng cơ sở dữ liệu không thể đáp ứng khối lượng yêu cầu từ trang web. Trang web có lưu lượng cao và một số trang sẽ hiển thị 25 sản phẩm trở lên cùng với tốc độ giao hàng cho từng sản phẩm hiển thị nội tuyến. Do đó, chúng tôi đã thêm một lớp đệm chạy như một quy trình riêng trên mỗi máy chủ web (có thể gọi là Memcached):

Cách này hoạt động hiệu quả nhưng nhóm cũng thử xử lý trường hợp bộ nhớ đệm (một quy trình riêng) gặp lỗi vì lý do nào đó. Trong tình huống này, các máy chủ web sẽ trở lại để trực tiếp truy vấn cơ sở dữ liệu. Trong mã giả, chúng tôi đã viết như sau:

if (cache_healthy) {
  shipping_speed = get_speed_via_cache(sku);
} else {
  shipping_speed = get_speed_from_database(sku);
}

Dự phòng để chuyển hướng truy vấn cơ sở dữ liệu là một giải pháp trực quan có hiệu quả trong nhiều tháng. Nhưng cuối cùng thì các bộ nhớ đệm đều gặp lỗi gần như cùng một lúc, điều đó có nghĩa là mỗi máy chủ web sẽ trực tiếp truy vấn cơ sở dữ liệu. Điều này tạo ra tải đủ để khóa hoàn toàn cơ sở dữ liệu. Toàn bộ trang web bị sập vì tất cả quy trình máy chủ web đã bị chặn trên cơ sở dữ liệu. Cơ sở dữ liệu về chuỗi cung ứng này cũng rất quan trọng đối với các trung tâm thực hiện đơn hàng. Do đó, sự cố này còn lan tỏa rộng hơn nữa và toàn bộ trung tâm thực hiện đơn hàng trên thế giới dần bị chững lại cho đến khi khắc phục xong sự cố.

Mọi vấn đề chúng ta đã thấy trong trường hợp máy đơn đều bộc lộ ở trường hợp phân tán với nhiều hậu quả nghiêm trọng hơn. Rất khó để kiểm thử trường hợp dự phòng phân tán; ngay cả khi đã mô phỏng lỗi bộ nhớ đệm, chúng tôi vẫn không tìm ra vấn đề, khiến hệ thống chỉ kích hoạt lỗi khi nhiều máy gặp lỗi. Và trong trường hợp này, chiến lược dự phòng đã tự chứng minh vấn đề và tệ hơn cả việc không dùng đến chiến lược dự phòng. Dự phòng biến sự cố trên một phần trang web (không thể hiển thị tốc độ giao hàng) thành một sự cố trên toàn trang web (không tải được trang nào) và khiến toàn bộ mạng thực hiện đơn hàng của Amazon bị đình trệ.

Tư duy đằng sau chiến lược dự phòng của chúng tôi trong trường hợp này đã không có tính lô-gic. Nếu trực tiếp truy vấn cơ sở dữ liệu là cách đáng tin cậy hơn là thông qua bộ nhớ đệm, thì vì sao phải sử dụng bộ nhớ đệm ngay từ đầu? Chúng tôi đã sợ rằng việc không sử dụng bộ nhớ đệm sẽ khiến cơ sở dữ liệu quá tải, nhưng vì sao phải sử dụng mã dự phòng nếu nó tiềm ẩn nhiều nguy cơ đến vậy? Đáng lẽ chúng tôi phải nhận ra lỗi ngay từ đầu, nhưng lỗi này là tiềm ẩn và tình huống gây ra lỗi xảy ra sau nhiều tháng sử dụng.

Cách Amazon tránh sử dụng chiến lược dự phòng

Với những cạm bẫy gặp phải trong chiến lược dự phòng phân tán, giờ đây, chúng tôi gần như luôn ưu tiên các phương án khác thay cho dự phòng. Những phương án ấy được nêu trong phần dưới đây.

Cải thiện độ ổn định của các trường hợp không sử dụng dự phòng

Như đã đề cập, các chiến lược dự phòng chỉ giảm khả năng xảy ra lỗi hoàn toàn. Một dịch vụ có thể khả dụng hơn rất nhiều nếu mã chính (không phải dự phòng) được tạo hiệu quả hơn. Ví dụ: thay vì triển khai lô-gic dự phòng giữa hai kho dữ liệu riêng biệt, đội ngũ có thể đầu tư vào việc sử dụng một cơ sở dữ liệu có độ sẵn sàng vốn dĩ cao hơn, chẳng hạn như Amazon DynamoDB. Chiến lược này thường được sử dụng thành công trên toàn Amazon. Ví dụ: bài nói chuyện này mô tả cách sử dụng DynamoDB để hỗ trợ amazon.com vào Prime Day năm 2017.

Để người gọi xử lý lỗi

Một giải pháp cho lỗi hệ thống nghiêm trọng là không dự phòng mà để hệ thống gọi tự xử lý lỗi (bằng cách thử lại chẳng hạn). Đây là chiến lược ưa dùng đối với các dịch vụ AWS, trong đó chúng tôi đã tích hợp sẵn lô-gic thử lại trong CLI và SDK. Khi có thể, chúng tôi ưu tiên sử dụng chiến lược này, đặc biệt trong những tình huống đã dành đủ nỗ lực để chia sẻ hệ quả và giảm khả năng gặp lỗi cho trường hợp chính (và khả năng cải thiện độ sẵn sàng của lô-gic dự phòng khá thấp). 

Chủ động đẩy dữ liệu

Một chiến thuật khác chúng tôi dùng để tránh phải sử dụng chiến lược dự phòng là giảm số thành phần di động khi phản hồi yêu cầu. Ví dụ: nếu dịch vụ cần dữ liệu để hoàn thành một yêu cầu và dữ liệu đó đã hiển thị cục bộ (không cần tìm nạp), thì không cần chiến lược chuyển đổi dự phòng. Một ví dụ thành công của chiến lược này là trong khi triển khai các vai trò AWS Identity and Access Management (IAM) cho Amazon EC2. Dịch vụ IAM cần cung cấp thông tin đăng nhập đã ký, luân phiên cho mã chạy trên phiên bản EC2. Để tránh phải dùng chiến lược dự phòng, thông tin đăng nhập được chủ động đẩy vào mọi phiên bản và có hiệu lực trong nhiều giờ. Điều này có nghĩa là những yêu cầu liên quan đến vai trò IAM vẫn hoạt động trong trường hợp cơ chế đẩy bị gián đoạn (dù hiếm khi xảy ra). 

Chuyển từ dự phòng sang chuyển đổi dự phòng

Một trong những điểm yếu nhất của chiến lược dự phòng là ít khi dùng đến và có khả năng gặp lỗi hoặc tăng phạm vi tác động nếu chiến lược này kích hoạt trong khi gặp sự cố. Các tình huống dẫn đến kích hoạt dự phòng có thể không tự nhiên xuất hiện trong nhiều tháng hay năm! Để giải quyết vấn đề lỗi tiềm ẩn của chiến lược dự phòng, điều quan trọng là bạn phải thường xuyên sử dụng chiến lược này trong môi trường sản xuất. Một dịch vụ phải liên tục chạy cả lô-gic dự phòng và lẫn bình thường. Dịch vụ vừa phải chạy trường hợp dự phòng, vừa phải coi dự phòng là nguồn dữ liệu có tính hợp lệ tương đương. Ví dụ: một dịch vụ có thể chọn ngẫu nhiên giữa phản hồi dự phòng và bình thường (khi nhận được cả hai) để đảm bảo cả hai đều hoạt động. Nhưng lúc này, không thể coi đây là chiến lược dự phòng nữa mà là chuyển đổi dự phòng.

Đảm bảo rằng chiến lược thử lại và thời gian chờ không trở thành chiến lược dự phòng

Chiến lược thử lại và thời gian chờ được thảo luận trong bài viết Thời gian chờ, thử lại và dừng lại với độ trễ ngẫu nhiên. Bài viết này nói rằng thử lại là một cơ chế mạnh mẽ để cung cấp độ sẵn sàng cao khi gặp lỗi ngẫu nhiên và tạm thời. Nói cách khác, thử lại và thời gian chờ là chiến lược phù hợp với các trường hợp lỗi không thường xuyên xảy ra do các sự cố nhỏ như mất gói giả, lỗi máy đơn không tương quan, v.v. Tuy vậy, chiến lược thử lại và thời gian chờ cũng rất dễ gặp lỗi. Các dịch vụ thường có thể chạy trong nhiều tháng hoặc lâu hơn mà không cần thử lại nhiều lần, và cuối cùng, hoạt động thử lại này có thể xuất hiện trong những tình huống mà nhóm bạn chưa bao giờ kiểm thử. Vì lý do này, chúng tôi duy trì các chỉ số theo dõi tỷ lệ thử lại tổng thể và các báo động sẽ báo động cho nhóm bạn nếu thường xuyên diễn ra hoạt động thử lại.

Một cách khác để tránh biến chiến lược thử lại thành dự phòng là luôn chủ động thử lại (còn được gọi là yêu cầu song song hoặc đối xứng). Kỹ thuật này được tích hợp sẵn vào các hệ thống sẽ thực hiện số lần đọc hoặc ghi tối thiểu, trong đó, một hệ thống có thể yêu cầu câu trả lời từ hai trong ba máy chủ để phản hồi. Chủ động thử lại tuân theo mẫu thiết kế công việc không đổi. Vì luôn có những yêu cầu dư thừa nên hoạt động thử lại không tăng thêm tải lên hệ thống khi nhu cầu cho yêu cầu dư thừa tăng lên.

Kết luận

Ở Amazon, chúng tôi tránh dự phòng trong hệ thống vì chiến lược này khó chứng minh và khó kiểm thử tính hiệu quả. Trong chiến lược dự phòng, hệ thống chỉ chuyển sang chế độ vận hành dự phòng trong trường hợp bất ổn nhất, khi mọi thứ bắt đầu bị phá vỡ và việc chuyển sang chế độ này chỉ khiến sự bất ổn gia tăng. Thông thường, khoảng thời gian tính từ khi đưa chiến lược dự phòng vào môi trường sản xuất cho đến khi dùng đến chiến lược này là khá dài.

Cho nên, chúng tôi thích dùng các đường dẫn mã được sử dụng liên tục (chứ không phải hiếm khi sử dụng) trong môi trường sản xuất. Chúng tôi tập trung cải thiện độ sẵn sàng của các hệ thống chính bằng cách sử dụng các mẫu như đẩy dữ liệu vào hệ thống cần thiết thay vì thu thập dữ liệu và đối mặt với nguy cơ lệnh gọi từ xa gặp lỗi vào thời điểm quan trọng. Cuối cùng, chúng tôi theo dõi hành vi khó phát hiện trong mã có thể biến mã thành một chế độ vận hành giống như dự phòng, chẳng hạn như thử lại quá nhiều lần.

Nếu chiến lược dự phòng đóng vai trò quan trọng trong một hệ thống, thì chúng tôi sẽ thường xuyên sử dụng dự phòng nhất có thể trong môi trường sản xuất để chiến lược dự phòng hoạt động ổn định và có thể dự đoán như chế độ vận hành chính.


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

Jacob Gabrielson là Kỹ sư chính cấp cao tại Amazon Web Services. Ông đã làm việc tại Amazon trong 17 năm, chủ yếu về các nền tảng vi dịch vụ nội bộ. Trong 8 năm qua, ông đã làm việc về EC2 và ECS, bao gồm hệ thống triển khai phần mềm, dịch vụ mặt phẳng kiểm soát, thị trường Spot, Lightsail và gần đây nhất là bộ chứa. Đam mê của Jacob là lập trình hệ thống, ngôn ngữ lập trình và điện toán phân tán. Sở đoản lớn nhất của ông là hành vi hệ thống hai phương thức, đặc biệt là trong các điều kiện lỗi. Ông có bằng Cử nhân khoa học máy tính của trường đại học Washington ở Seattle.

Thời gian chờ, thử lại và rút lại với phương sai độ trễ Những thách thức và chiến lược lưu trữ bộ nhớ đệm