Những thăng trầm với bộ nhớ đệm

Qua nhiều năm xây dựng dịch vụ tại Amazon, chúng tôi đã trải qua nhiều phiên bản khác nhau của tình huống sau: Chúng tôi xây dựng một dịch vụ mới và dịch vụ này cần thực hiện một số lệnh gọi mạng để đáp ứng các yêu cầu của mình. Các lệnh gọi này có thể gọi đến cơ sở dữ liệu quan hệ, dịch vụ AWS như Amazon DynamoDB hoặc một dịch vụ nội bộ khác. Dịch vụ sẽ hoạt động tốt trong các kiểm thử đơn giản hoặc với tốc độ yêu cầu thấp, nhưng chúng tôi nhận thấy một vấn đề trước mắt. Vấn đề có thể là các lệnh gọi đến dịch vụ khác bị chậm hoặc cơ sở dữ liệu quá đắt đỏ để có thể mở rộng khi lượng lệnh gọi tăng lên. Chúng tôi cũng nhận thấy rằng nhiều yêu cầu đang sử dụng cùng một tài nguyên xuôi chiều hoặc cùng kết quả truy vấn, vì vậy chúng tôi nghĩ rằng việc lưu trữ dữ liệu này trong bộ nhớ đệm có thể là giải pháp cho các vấn đề của mình. Chúng tôi bổ sung một bộ nhớ đệm và dịch vụ đã cho thấy sự cải thiện đáng kể. Chúng tôi nhận thấy độ trễ của yêu cầu và chi phí giảm xuống, đồng thời hiện tượng sụt giảm khả dụng dòng xuôi chiều nhẹ cũng giảm bớt. Sau một thời gian, cuộc sống khi chưa có bộ nhớ đệm trở thành dĩ vãng. Quy mô nhóm các thành phần phụ thuộc cũng giảm theo đó và cơ sở dữ liệu được thu nhỏ. Khi mọi chuyện dường như đang diễn ra tốt đẹp, dịch vụ vẫn có thể hứng chịu thảm họa. Đó có thể là các thay đổi về mẫu lưu lượng, lỗi nhóm bộ nhớ đệm hoặc các trường hợp không mong muốn khác khiến bộ nhớ đệm nguội hoặc không khả dụng. Điều này có thể khiến lưu lượng tăng vọt đối với các dịch vụ xuôi chiều, từ đó dẫn đến trạng thái ngừng hoạt động trên cả các thành phần phụ thuộc lẫn dịch vụ của chúng tôi.

Chúng tôi vừa mô tả một dịch vụ đã trở nên phụ thuộc vào bộ nhớ đệm. Bộ nhớ đệm đã vô tình được nâng tầm từ yếu tố bổ sung hữu ích cho dịch vụ thành một phần quan trọng và cần thiết đối với khả năng hoạt động. Trọng tâm của vấn đề này là hành vi thể thức mà bộ nhớ đệm đưa vào, hành vi sẽ khác nhau tùy thuộc vào việc đối tượng nhất định có được lưu trữ trong bộ nhớ đệm hay không. Một thay đổi ngoài dự kiến trong việc phân phối hành vi thể thức này sẽ có khả năng dẫn đến thảm họa.

Chúng tôi đã trải nghiệm những lợi ích và thách thức của việc lưu trữ vào bộ nhớ đệm trong quá trình xây dựng và vận hành các dịch vụ tại Amazon. Phần còn lại của bài viết này mô tả những bài học mà chúng tôi rút ra, các biện pháp thực hành tốt nhất và những lưu ý khi sử dụng bộ nhớ đệm.

Khi chúng tôi sử dụng cách lưu trữ vào bộ nhớ đệm

Một số yếu tố khiến chúng tôi cân nhắc việc thêm bộ nhớ đệm vào hệ thống. Rất nhiều lần điều này bắt nguồn khi chúng tôi quan sát độ trễ hoặc hiệu suất của một thành phần phụ thuộc ở tốc độ yêu cầu nhất định. Ví dụ: Điều này có thể xảy ra khi chúng tôi xác định một thành phần phụ thuộc phải bắt đầu điều tiết, nếu không sẽ không thể theo kịp tải dự kiến. Việc cân nhắc lưu trữ vào bộ nhớ đệm trở nên hữu dụng khi chúng tôi gặp phải các mẫu yêu cầu không đồng đều dẫn đến việc phải điều tiết phím tắt/phân vùng nhanh. Dữ liệu từ thành phần phụ thuộc này là một ứng cử viên tốt cho việc lưu trữ vào bộ nhớ đệm nếu bộ nhớ đệm đó có tỷ lệ khớp bộ nhớ đệm tốt trên các yêu cầu. Tức là, có thể sử dụng kết quả của các lệnh gọi thành phần phụ thuộc trên nhiều yêu cầu hoặc thao tác vận hành. Nếu mỗi yêu cầu thường cần một truy vấn đặc thù đến dịch vụ phụ thuộc với kết quả đặc thù cho mỗi yêu cầu thì bộ nhớ đệm sẽ có tỷ lệ khớp không đáng kể và không đem lại kết quả tốt. Lưu ý thứ hai là mức độ chấp nhận của dịch vụ nhóm và máy khách đối với độ nhất quán cuối. Theo thời gian, dữ liệu được lưu trong bộ nhớ đệm sẽ có mức tăng khác so với mức tăng của nguồn, do đó, việc lưu trữ vào bộ nhớ đệm chỉ có thể thành công nếu cả dịch vụ và máy khách chịu bù đắp tương ứng. Mức độ thay đổi của dữ liệu nguồn cũng như chính sách bộ nhớ đệm đối với việc làm mới dữ liệu sẽ xác định mức độ không nhất quán của dữ liệu. Hai điều này có liên hệ với nhau. Ví dụ: Dữ liệu tương đối tĩnh hoặc thay đổi chậm có thể được lưu trữ vào bộ nhớ đệm trong thời gian dài hơn.

Các bộ nhớ đệm cục bộ

Các bộ nhớ đệm dịch vụ có thể được triển khai trong bộ nhớ hoặc ra dịch vụ ở bên ngoài. Các bộ nhớ đệm on-box, thường được triển khai trong bộ nhớ quy trình, tương đối nhanh, dễ triển khai và có thể cung cấp các điểm cải tiến đáng kể với phần việc tối thiểu. Các bộ nhớ đệm on-box thường là cách tiếp cận đầu tiên được triển khai và đánh giá một khi nhu cầu về bộ nhớ đệm được xác định. Trái ngược với bộ nhớ đệm ngoài, bộ nhớ đệm on-box không tốn chi phí vận hành bổ sung, vì vậy, mức rủi ro khi tích hợp vào một dịch vụ hiện có là khá thấp. Chúng tôi thường triển khai bộ nhớ đệm on-box dưới dạng bảng băm trong bộ nhớ được quản lý thông qua logic ứng dụng (ví dụ: bằng cách đặt kết quả vào bộ nhớ đệm sau khi hoàn thành các lệnh gọi dịch vụ) hoặc được nhúng trong máy khách dịch vụ (ví dụ: sử dụng máy khách HTTP lưu vào bộ nhớ đệm).

Dù sở hữu những lợi ích và sự đơn giản đầy cám dỗ, nhưng các bộ nhớ đệm trong bộ nhớ vẫn có một số nhược điểm. Một trong số đó là dữ liệu được lưu trữ trong bộ nhớ đệm sẽ không nhất quán giữa các máy chủ trong danh mục, đây là biểu hiện của vấn đề tính nhất quán của bộ nhớ đệm. Nếu một máy khách thực hiện các lệnh gọi lặp lại đến dịch vụ, thì máy khách đó có thể nhận được dữ liệu mới hơn được sử dụng trong lệnh gọi đầu tiên và dữ liệu cũ hơn trong lệnh gọi thứ hai, tùy thuộc vào máy chủ nào sẽ xử lý yêu cầu.

Một điểm hạn chế khác là tải xuôi chiều hiện tỷ lệ thuận với kích cỡ nhóm của dịch vụ, do đó, khi số lượng máy chủ tăng lên thì vẫn có thể áp đảo các dịch vụ phụ thuộc. Chúng tôi nhận thấy cách hiệu quả để giám sát việc này là phát hành các số liệu về số lần khớp/trượt bộ nhớ đệm và số lượng yêu cầu chuyển đến các dịch vụ xuôi chiều.

Bộ nhớ đệm trong bộ nhớ cũng dễ bị ảnh hưởng bởi các sự cố “khởi động nguội”. Những sự cố này xảy ra khi một máy chủ mới khởi chạy cùng một bộ nhớ đệm trống hoàn toàn, từ đó kéo theo một loạt các yêu cầu đến dịch vụ phụ thuộc trong quá trình lấp đầy bộ nhớ đệm. Đây có thể là một sự cố lớn trong quá trình triển khai hoặc trong các trường hợp khác, khi mà bộ nhớ đệm bị đẩy vào nhóm lớn. Tính nhất quán của bộ nhớ đệm và các sự cố bộ nhớ đệm trống thường có thể được giải quyết bằng cách sử dụng hợp nhất yêu cầu, như được mô tả chi tiết ở phần sau của bài viết này.

Bộ nhớ đệm ngoài

Bộ nhớ đệm ngoài có thể giúp giải quyết nhiều vấn đề mà chúng tôi vừa thảo luận. Bộ nhớ đệm ngoài lưu trữ dữ liệu bộ nhớ đệm trong một danh mục riêng biệt, ví dụ như sử dụng Memcached hoặc Redis Các vấn đề về tính nhất quán của bộ nhớ đệm được giảm bớt vì bộ nhớ đệm ngoài lưu giữ giá trị mà mọi máy chủ trong nhóm đều sử dụng. (Lưu ý rằng những vấn đề này không được loại bỏ hoàn toàn vì có thể xảy ra các trường hợp lỗi khi cập nhật bộ nhớ đệm.) Tải tổng thể trên các dịch vụ xuôi chiều giảm xuống so với bộ nhớ đệm trong bộ nhớ và không có tỷ lệ thuận với quy mô nhóm. Các vấn đề khởi động nguội trong các sự kiện như triển khai sẽ không xuất hiện do bộ nhớ đệm ngoài liên tục được ghi trong quá trình triển khai. Cuối cùng, bộ nhớ đệm ngoài cung cấp nhiều dung lượng lưu trữ hơn bộ nhớ đệm trong bộ nhớ, do đó hạn chế việc thu hồi bộ nhớ đệm do thiếu dung lượng.

Tuy nhiên, bộ nhớ đệm ngoài cũng có những yếu điểm riêng mà bạn cần xem xét. Đầu tiên là tăng thêm sự phức tạp cho toàn bộ hệ thống và tải hoạt động do phải giám sát, quản lý và mở rộng một nhóm bổ sung. Các đặc điểm khả dụng của nhóm bộ nhớ đệm sẽ khác với dịch vụ phụ thuộc mà nó hỗ trợ với vai trò bộ nhớ đệm. Nhóm bộ nhớ đệm thường có thể kém khả dụng hơn, chẳng hạn như khi nhóm bộ nhớ đệm không hỗ trợ nâng cấp không gián đoạn và yêu cầu thời gian bảo trì.

Để tránh làm giảm tính khả dụng của dịch vụ do bộ nhớ đệm ngoài, chúng tôi nhận thấy phải thêm mã dịch vụ để xử lý tình trạng nhóm bộ nhớ đệm không khả dụng, lỗi nút bộ nhớ đệm hoặc lỗi đặt/tải bộ nhớ đệm. Một lựa chọn là quay về với lệnh gọi dịch vụ phụ thuộc dự phòng nhưng sẽ phải cẩn thận khi thực hiện phương pháp này. Việc bộ nhớ đệm ngoài ngừng hoạt động sẽ gây ra sự gia tăng bất thường trong lưu lượng của dịch vụ xuôi tuyến, dẫn đến điều tiết hoặc sụt giảm hiệu năng trong dịch vụ phụ thuộc và cuối cùng làm giảm độ sẵn sàng. Chúng tôi thích dùng bộ nhớ đệm ngoài kết hợp với bộ nhớ đệm trong bộ nhớ để có thể dự phòng nếu bộ nhớ đệm ngoài không khả dụng hoặc sử dụng phương pháp giảm tải và giới hạn tốc độ tối đa của các yêu cầu được gửi đến dịch vụ xuôi tuyến. Chúng tôi kiểm thử hành vi dịch vụ với bộ nhớ đệm bị vô hiệu hóa để xem các biện pháp bảo vệ đã áp dụng nhằm ngăn chặn sự sụt giảm hiệu năng của các thành phần phụ thuộc có thực sự hiệu quả hay không.

Yếu tố cần xem xét thứ hai là mức độ mở rộng và tính co giãn của nhóm bộ nhớ đệm. Khi nhóm bộ nhớ đệm bắt đầu đạt đến giới hạn tốc độ yêu cầu hoặc giới hạn bộ nhớ, các nút sẽ cần được thêm vào. Chúng tôi xác định những số liệu giữ vai trò là chỉ số hàng đầu của các giới hạn này để có thể thiết lập trình giám sát và báo động tương ứng. Ví dụ: Trên một dịch vụ mà gần đây tôi đang thực hiện, nhóm chúng tôi nhận thấy mức sử dụng CPU đã tăng rất cao khi tốc độ yêu cầu của Redis đạt đến giới hạn. Chúng tôi đã sử dụng kiểm thử tải với các mẫu lưu lượng thực để xác định giới hạn và tìm ngưỡng báo động phù hợp.

Khi thêm dung lượng cho nhóm bộ nhớ đệm, chúng tôi cẩn thận thực hiện để không gây sự cố ngừng hoạt động hoặc tổn thất nặng nề cho dữ liệu bộ nhớ đệm. Các công nghệ lưu trữ bộ nhớ đệm khác nhau có các lưu ý đặc thù tương ứng. Ví dụ: Một số máy chủ bộ nhớ đệm không hỗ trợ thêm nút vào cụm mà không có thời gian ngừng hoạt động, cũng như không phải mọi thư viện máy khách bộ nhớ đệm đều cung cấp chức năng băm nhất quán cần thiết để thêm nút vào nhóm bộ nhớ đệm và phân phối lại dữ liệu được lưu trữ trong bộ nhớ đệm. Do sự biến động trong hoạt động triển khai máy khách của chức năng băm nhất quán và sự phát hiện các nút trong nhóm bộ nhớ đệm, chúng tôi đều kiểm thử kỹ lưỡng việc thêm và xóa máy chủ bộ nhớ đệm trước khi bước vào sản xuất.

Với bộ nhớ đệm ngoài, chúng tôi còn cẩn thận hơn nữa để đảm bảo độ vững chắc khi định dạng lưu trữ bị thay đổi. Dữ liệu được lưu trữ trong bộ nhớ đệm được xử lý như khi chúng được lưu trữ lâu dài. Chúng tôi đảm bảo phần mềm đã cập nhật luôn có thể đọc được dữ liệu mà phiên bản trước ghi và các phiên bản cũ hơn có thể xử lý một cách dễ dàng khi gặp các định dạng/trường mới (ví dụ: trong quá trình triển khai khi nhóm có sự pha trộn giữa mã cũ và mã mới). Ngăn chặn các trường hợp ngoại lệ chưa được phát hiện khi gặp định dạng bất thường là điều cần thiết để ngăn ngừa chiến lược thuốc độc. Tuy nhiên, thao tác này không thể ngăn hết toàn bộ các vấn đề liên quan đến định dạng. Việc phát hiện định dạng phiên bản không khớp và loại bỏ dữ liệu được lưu trữ trong bộ nhớ đệm có thể khiến làm mới hàng loạt bộ nhớ đệm, từ đó kéo theo việc điều tiết hoặc giảm hiệu năng dịch vụ phụ thuộc. Các vấn đề về định dạng chuỗi hóa được đề cập sâu hơn trong bài viết Đảm bảo trở về phiên bản trước an toàn trong quá trình triển khai.

Cuối cùng, bạn cần cân nhắc xem các bộ nhớ đệm ngoài có được cập nhật bởi các nút riêng lẻ trong nhóm dịch vụ không. Bộ nhớ đệm thường không sở hữu các tính năng như đặt và giao dịch có điều kiện nên chúng tôi cần cẩn thận để đảm bảo rằng mã cập nhật bộ nhớ đệm là chính xác và không bao giờ được để bộ nhớ đệm ở trạng thái không hợp lệ hoặc không nhất quán.

Bộ nhớ đệm nội tuyến so với bộ nhớ đệm bên

Ngoài ra, khi đánh giá các phương pháp tiếp cận lưu trữ bộ nhớ đệm khác, chúng tôi còn phải đưa ra quyết định về việc chọn bộ nhớ đệm nội tuyến hay bộ nhớ đệm bên. Các bộ nhớ đệm nội tuyến hay bộ nhớ đệm đọc/ghi thẳng, kết hợp quản lý bộ nhớ đệm vào API truy cập dữ liệu chính, biến việc quản lý bộ nhớ đệm trở thành một chi tiết triển khai của API đó. Các ví dụ bao gồm hoạt động triển khai theo từng ứng dụng như Amazon DynamoDB Accelerator (DAX) và triển khai dựa trên tiêu chuẩn như lưu trữ vào bộ nhớ đệm HTTP (với máy khách lưu trữ vào bộ nhớ đệm cục bộ hoặc máy chủ bộ nhớ đệm ngoài như Nginx hoặc Varnish). Ngược lại, bộ nhớ đệm bên là kho đối tượng chung, như kho đối tượng mà Amazon ElastiCache (Memcached và Redis) hoặc các thư viện như Ehcache và Google Guava cung cấp cho bộ nhớ đệm trong bộ nhớ. Với các bộ nhớ đệm bên, mã ứng dụng sẽ trực tiếp tác động đến bộ nhớ đệm trước và sau lệnh gọi nguồn dữ liệu, kiểm tra đối tượng được lưu trữ vào bộ nhớ đệm trước khi thực hiện lệnh gọi xuôi tuyến và đặt đối tượng vào bộ nhớ đệm sau khi hoàn thành những lệnh gọi này.

Lợi ích chính của bộ nhớ đệm nội tuyến là mô hình API thống nhất cho máy khách. Có thể được thêm, xóa hoặc điều chỉnh hoạt động lưu trữ vào bộ nhớ đệm mà không thay đổi bất cứ gì đối với logic máy khách. Ngoài ra, bộ nhớ đệm nội tuyến còn rút logic quản lý bộ nhớ đệm ra khỏi mã ứng dụng, nhờ vậy, loại bỏ một nguồn lỗi tiềm ẩn. Bộ nhớ đệm HTTP đặc biệt hấp dẫn bởi các lựa chọn có sẵn dồi dào, chẳng hạn như thư viện trong bộ nhớ, các proxy HTTP độc lập như proxy được đề cập trước đó và các dịch vụ được quản lý như mạng phân phối nội dung (CDN).

Tuy nhiên, tính minh bạch của các bộ nhớ đệm nội tuyến cũng có thể là nhược điểm về tính khả dụng. Giờ các bộ nhớ đệm ngoài là một phần của phương trình tính khả dụng của thành phần phụ thuộc này. Máy khách không có cơ hội bù đắp cho bộ nhớ đệm tạm thời không khả dụng. Ví dụ: Nếu bạn có nhóm Varnish lưu trữ yêu cầu từ dịch vụ REST bên ngoài vào bộ nhớ đệm thì khi nhóm lưu trữ bộ nhớ đệm đó ngừng hoạt động, từ quan điểm dịch vụ của bạn, việc này sẽ không khác gì chính thành phần phụ thuộc ngừng hoạt động. Bộ nhớ đệm nội tuyến còn có một nhược điểm nữa là cần được tích hợp vào giao thức hoặc dịch vụ mà nó đang thực hiện lưu trữ vào bộ nhớ đệm. Nếu không có sẵn bộ nhớ đệm nội tuyến cho giao thức thì sẽ không có tùy chọn lưu trữ vào bộ nhớ đệm nội tuyến này, trừ khi bạn muốn tự mình xây dựng một dịch vụ proxy hoặc máy khách tích hợp.

Thời hạn của bộ nhớ đệm

Một số chi tiết thách thức nhất trong quá trình triển khai bộ nhớ đệm là chọn kích thước, chính sách hết hạn và chính sách thu hồi phù hợp cho bộ nhớ đệm. Chính sách hết hạn sẽ xác định thời gian lưu giữ một mục trong bộ nhớ đệm. Chính sách phổ biến nhất sử dụng cách tính ngày hết hạn hoàn toàn dựa trên thời gian (nghĩa là liên kết thời gian tồn tại (TTL) với từng đối tượng khi đối tượng được tải). TTL được chọn dựa trên yêu cầu của máy khách, chẳng hạn như khả năng chấp nhận dữ liệu cũ của máy khách và mức độ tĩnh của dữ liệu, vì dữ liệu thay đổi chậm có thể được lưu trữ vào bộ nhớ đệm một cách chủ động hơn. Kích thước bộ nhớ đệm lý tưởng được xác định dựa trên mô hình khối lượng yêu cầu dự kiến và cách phân phối đối tượng được lưu trữ vào bộ nhớ đệm trong các yêu cầu đó. Từ đó, chúng tôi ước tính kích thước bộ nhớ đệm để đảm bảo tỷ lệ khớp bộ nhớ đệm cao với các mẫu lưu lượng này. Chính sách thu hồi kiểm soát cách xóa các mục khỏi bộ nhớ đệm khi bộ nhớ đệm đạt đến công suất của mình. Chính sách thu hồi phổ biến nhất là thuật toán Gần đây ít được dùng nhất (LRU).

Cho đến nay, đây vẫn chỉ là một bài tập tư duy. Các mẫu lưu lượng trong thực tế có thể khác với mẫu của chúng tôi nên chúng tôi cần theo dõi hiệu suất thực tế của bộ nhớ đệm. Cách thức yêu thích để thực hiện điều này của chúng tôi là phát hành số liệu dịch vụ về những lần khớp và trượt của bộ nhớ đệm, tổng kích thước bộ nhớ đệm và số yêu cầu với dịch vụ xuôi chiều.

Chúng tôi đã hiểu được rằng cần phải cẩn trọng trong việc chọn kích thước bộ nhớ đệm và các giá trị trong chính sách hết hạn. Chúng tôi muốn tránh trường hợp nhà phát triển tùy ý chọn một số kích thước bộ nhớ đệm và giá trị TTL trong quá trình triển khai ban đầu, rồi sau đó không quay lại và xác thực xem giá trị có phù hợp không. Chúng tôi đã thấy các ví dụ thực tế về sự thiếu theo dõi này dẫn đến việc ngừng dịch vụ tạm thời và làm trầm trọng hơn tình trạng ngừng hoạt động liên tục

Ngoài ra, chúng tôi còn sử dụng một mẫu khác để cải thiện khả năng phục hồi khi không có dịch vụ xuôi chiều bằng cách dùng hai TTL: một TTL mềm dẻo và một TTL cứng rắn. Máy khách sẽ cố gắng làm mới các mục được lưu trữ trong bộ nhớ đệm dựa trên TTL mềm dẻo, nhưng nếu dịch vụ xuôi chiều không có sẵn hoặc nếu không đáp ứng yêu cầu thì dữ liệu bộ nhớ đệm hiện tại sẽ tiếp tục được sử dụng cho đến khi đạt đến TTL cứng rắn. Ví dụ về mẫu này được dùng trong máy khách AWS Identity and Access Management (IAM).

Chúng tôi cũng sử dụng phương pháp tiếp cận TTL mềm dẻo và cứng rắn với áp lực ngược để giảm tác động của tình trạng giảm hiệu năng dịch vụ xuôi chiều. Dịch vụ xuôi chiều có thể phản hồi với sự kiện áp lực ngược khi giảm hiệu năng, điều này báo hiệu rằng dịch vụ gọi nên sử dụng dữ liệu được lưu trữ trong bộ nhớ đệm cho đến khi đạt TTL cứng rắn và chỉ thực hiện các yêu cầu đối với dữ liệu không nằm trong bộ nhớ đệm của mình. Chúng tôi vẫn sẽ tiếp tục cho đến khi dịch vụ xuôi chiều loại bỏ áp lực ngược. Mẫu này cho phép dịch vụ xuôi chiều phục hồi từ tình trạng giảm hiệu năng trong khi vẫn duy trì tính khả dụng của các dịch vụ ngược chiều.

Những điểm cần cân nhắc khác

Quan trọng: Bạn cũng cần cân nhắc đến hành vi của bộ nhớ đệm khi nhận được lỗi từ dịch vụ xuôi chiều. Một cách để xử lý vấn đề này là trả lời máy khách bằng cách sử dụng giá trị tốt cuối cùng được lưu trữ trong bộ nhớ đệm, ví dụ: tận dụng mẫu TTL mềm dẻo/cứng rắn được mô tả trước đó. Cách khác mà chúng tôi sử dụng là lưu trữ phản hồi về lỗi vào bộ nhớ đệm (nghĩa là chúng tôi sử dụng "bộ nhớ đệm tiêu cực") bằng một TTL khác với các mục nhập bộ nhớ đệm tích cực và truyền lỗi đến máy khách. Chúng tôi chọn phương pháp tiếp cận cho một tình huống nhất định dựa trên các chi tiết của dịch vụ và bằng cách đánh giá xem khi nào nên để máy khách gặp dữ liệu cũ, khi nào nên gặp lỗi. Bất kể sử dụng phương pháp tiếp cận nào, chúng tôi đều phải đảm bảo có nội dung trong bộ nhớ đệm trong các trường hợp lỗi. Nếu không phải trường hợp này và dịch vụ xuôi chiều tạm thời không khả dụng hoặc không thể thực hiện một số yêu cầu nhất định (ví dụ: khi tài nguyên xuôi chiều bị xóa), dịch vụ ngược chiều sẽ tiếp tục tấn công dịch vụ xuôi chiều với lưu lượng truy cập và có thể gây ra sự cố ngừng hoạt động hoặc làm trầm trọng thêm tình trạng hiện tại. Chúng tôi đã thấy các ví dụ thực tế, trong đó việc không lưu trữ các phản hồi tiêu cực vào bộ nhớ đệm sẽ làm tăng tỷ lệ thất bại và lỗi.

Bảo mật là một khía cạnh quan trọng khác của việc lưu trữ vào bộ nhớ đệm. Khi đưa bộ nhớ đệm vào một dịch vụ, chúng tôi sẽ đánh giá và giảm thiểu mọi rủi ro bảo mật gia tăng do bộ nhớ đệm. Ví dụ: Các nhóm lưu trữ vào bộ nhớ đệm bên ngoài thường thiếu mã hóa cho dữ liệu tuần tự và bảo mật mức truyền vận. Điều này đặc biệt quan trọng nếu thông tin nhạy cảm của người dùng được lưu trữ lại bộ nhớ đệm. Vấn đề này có thể được hạn chế bằng cách sử dụng dịch vụ như Amazon ElastiCache for Redis giúp hỗ trợ mã hóa dữ liệu truyền và lưu trữ. Bộ nhớ đệm cũng dễ bị tấn công đầu độc, trong đó lỗ hổng ở giao thức xuôi chiều sẽ cho phép kẻ tấn công ghi giá trị vào bộ nhớ đệm dưới sự kiểm soát của chúng. Điều này khuếch đại tác động của cuộc tấn công vì tất cả các yêu cầu được thực hiện khi giá trị này vẫn còn trong bộ nhớ đệm sẽ gặp phải giá trị độc hại. Ngoài ra, bộ nhớ đệm cũng có thể bị tấn công thời gian kênh bên. Các giá trị được lưu trữ trong bộ nhớ đệm được trả về nhanh hơn các giá trị không được lưu trữ, vì vậy kẻ tấn công có thể lợi dụng thời gian phản hồi để lấy thông tin về những yêu cầu mà máy khách hoặc nguyên lý khác đang thực hiện.

Điều cần xem xét cuối cùng là “tác động bầy đàn”, khi mà nhiều máy khách đưa ra các yêu cầu cho cùng một nguồn tài nguyên xuôi chiều không được lưu trữ vào gần như cùng lúc. Việc này cũng có thể xảy ra khi một máy chủ xuất hiện và tham gia vào nhóm với bộ nhớ đệm cục bộ trống. Kết quả là một số lượng lớn các yêu cầu từ mỗi máy chủ đi đến thành phần phụ thuộc xuôi chiều, dẫn đến điều tiết/giảm hiệu năng. Để khắc phục vấn đề này, chúng tôi sử dụng biện pháp hợp nhất yêu cầu, trong đó các máy chủ hoặc bộ nhớ đệm ngoài đảm bảo rằng chỉ có một yêu cầu đang chờ xử lý được đưa ra cho các tài nguyên không được lưu trữ trong bộ nhớ đệm. Một số thư viện lưu trữ bộ nhớ đệm và bộ nhớ đệm nội tuyến ngoài (như Nginx hoặc Varnish) có cung cấp hỗ trợ đối với hợp nhất yêu cầu. Ngoài ra, cũng có thể triển khai hợp nhất yêu cầu trên bộ nhớ đệm sẵn có. 

Những cân nhắc và biện pháp tốt nhất của Amazon

Bài viết này đã đề cập đến một số biện pháp tốt nhất của Amazon cũng như sự đánh đổi và rủi ro liên quan đến lưu trữ bộ nhớ đệm. Dưới đây là tóm tắt về những cân nhắc và biện pháp tốt nhất của Amazon mà đội ngũ của chúng tôi sử dụng khi đưa ra bộ nhớ đệm:

• Hãy chắc chắn rằng bạn có nhu cầu chính đáng về một bộ nhớ đệm có chi phí, độ trễ và/hoặc khả năng cải thiện tính khả dụng phù hợp. Đảm bảo dữ liệu có thể được lưu trữ trong bộ nhớ đệm, nghĩa là dữ liệu có thể được sử dụng cho nhiều yêu cầu từ máy khách. Hãy hoài nghi về giá trị mà bộ nhớ đệm sẽ mang lại và đánh giá cẩn thận xem liệu các lợi ích có vượt trội hơn rủi ro tăng thêm do bộ nhớ đệm không.
• Lập kế hoạch vận hành bộ nhớ đệm với cùng một tiêu chuẩn và quy trình được sử dụng cho nhóm dịch vụ và cơ sở hạ tầng còn lại. Đừng đánh giá thấp việc này. Phát hành số liệu về mức độ sử dụng bộ nhớ đệm và tỉ lệ khớp để đảm bảo bộ nhớ đệm được điều chỉnh phù hợp. Giám sát các chỉ số chính (như CPU và bộ nhớ) để đảm bảo nhóm lưu trữ bộ nhớ đệm ngoài ở tình trạng tốt và có quy mô phù hợp. Thiết lập báo động cho các số liệu này. Đảm bảo nhóm lưu trữ bộ nhớ đệm có thể được mở rộng mà không yêu cầu thời gian ngừng hoạt động hoặc vô hiệu hóa bộ nhớ đệm hàng loạt (nghĩa là đảm bảo chức năng băm nhất quán đang hoạt động như mong đợi).
• Hãy cẩn trọng và dựa theo kinh nghiệm để lựa chọn kích thước bộ nhớ đệm, chính sách hết hạn và chính sách thu hồi. Thực hiện kiểm thử và sử dụng các số liệu được đề cập trong gạch đầu dòng trước để xác thực và điều chỉnh các lựa chọn này.
• Đảm bảo rằng dịch vụ của bạn có khả năng phục hồi khi bộ nhớ đệm không khả dụng, bao gồm nhiều tình huống dẫn đến việc không thể phục vụ các yêu cầu sử dụng dữ liệu được lưu trữ trong bộ nhớ đệm. Trong đó số này có khởi động nguội, nhóm lưu trữ bộ nhớ đệm ngừng hoạt động, thay đổi mẫu lưu lượng hoặc ngừng hoạt động xuôi chiều kéo dài. Trong nhiều trường hợp, điều này có nghĩa là bạn đang đánh đổi phần nào tính khả dụng để đảm bảo các máy chủ và dịch vụ phụ thuộc không bị giảm hiệu năng (ví dụ: bằng cách giảm tải, giới hạn yêu cầu đến các dịch vụ phụ thuộc hoặc phân phối dữ liệu cũ). Hãy chạy kiểm thử tải với bộ nhớ đệm bị vô hiệu hóa để xác thực điều này.
• Xem xét các khía cạnh bảo mật của việc duy trì dữ liệu được lưu trữ trong bộ nhớ đệm, bao gồm mã hóa, bảo mật vận chuyển khi trao đổi thông tin với một nhóm lưu trữ bộ nhớ đệm ngoài, tác động của các cuộc tấn công độc hại đến bộ nhớ đệm và các cuộc tấn công kênh bên.
• Thiết kế định dạng lưu trữ cho các đối tượng được lưu trữ trong bộ nhớ đệm để phát triển theo thời gian (ví dụ: sử dụng số phiên bản) và viết mã dạng tuần tự có khả năng đọc các phiên bản cũ. Cảnh giác với những viên thuốc độc trong logic về nối tiếp hóa bộ nhớ đệm của bạn.
• Đánh giá cách bộ nhớ đệm sẽ xử lý các lỗi xuôi chiều và xem xét việc duy trì bộ nhớ đệm tiêu cực bằng một TTL riêng biệt. Không tạo hay khuếch đại sự cố ngừng hoạt động bằng cách liên tục yêu cầu cùng một tài nguyên xuôi chiều và loại bỏ các phản hồi lỗi.

Nhiều nhóm dịch vụ tại Amazon sử dụng các kỹ thuật lưu trữ trong bộ đệm ẩn. Mặc dù các kỹ thuật này mang đến nhiều lợi ích, chúng tôi sẽ không coi nhẹ quyết định tích hợp chức năng lưu trữ trong bộ nhớ đệm vì nhược điểm của bộ nhớ đệm đó có thể vượt trội ưu điểm. Chúng tôi hy vọng bài viết này sẽ giúp bạn đánh giá được hoạt động lưu trữ bộ nhớ đệm trong các dịch vụ của mình.


Về tác giả

Matt là Kỹ sư chính của bộ phận Thiết bị mới tại Amazon, ông nghiên cứu phần mềm và dịch vụ cho các thiết bị tiêu dùng sắp ra mắt. Trước đây, ông từng làm việc tại AWS Elemental với vai trò trưởng nhóm phát hành MediaTailor – dịch vụ chèn quảng cáo được cá nhân hóa phía máy chủ cho video trực tiếp và theo nhu cầu. Trong thời gian đó, ông giúp ra mắt mùa đầu tiên phát trực tuyến NFL Saturday Night Football của PrimeVideo. Trước Amazon, Matt đã có 15 năm hoạt động trong ngành bảo mật – bao gồm khoảng thời gian làm việc tại McAfee, Intel và một vài công ty khởi nghiệp – chuyên về quản lý bảo mật doanh nghiệp, công nghệ chống phần mềm độc hại và ngăn ngừa khai thác, các biện pháp bảo mật hỗ trợ phần cứng và DRM.

Jas Chhabra là Kỹ sư chính tại AWS. Ông gia nhập AWS vào năm 2016 và đã làm về AWS IAM trong vài năm trước khi chuyển sang vị trí hiện nay tại AWS Machine Learning. Trước AWS, ông đã làm việc tại Intel với các vai trò kỹ thuật khác nhau trong lĩnh vực IoT, danh tính và bảo mật. Các mối quan tâm hiện nay của ông là Machine learning, bảo mật và hệ thống phân tán quy mô lớn. Trước đây, ông quan tâm đến IoT, bitcoin, danh tính và mật mã. Ông có bằng Thạc sĩ Khoa học Máy tính.

Tránh dự phòng trong hệ thống phân tán Sử dụng biện pháp giảm tải để tránh quá tải Đảm bảo trở về phiên bản trước an toàn trong quá trình triển khai