3.16 Cổng API và lưới dịch vụ
Tổng quan và động lực
Khoảnh khắc bạn tách một chương trình thành nhiều dịch vụ, một câu hỏi mới xuất hiện: ai phụ trách lưu lượng giữa chúng, và lưu lượng đến từ bên ngoài? Bạn có thể trả lời câu hỏi đó tồi bằng cách rải cùng các mối quan tâm (xác thực, thử lại, thời gian chờ, giới hạn tốc độ, ghi nhật ký) vào từng dịch vụ bằng tay, hoặc bạn có thể trả lời tốt bằng cách đẩy những mối quan tâm đó vào một tầng dùng chung mà mọi dịch vụ thừa hưởng miễn phí. Chương này nói về hai tầng như vậy. Một cổng API đứng ở cửa trước và quản lý lưu lượng đến từ máy khách. Một lưới dịch vụ đứng giữa các dịch vụ của bạn và quản lý lưu lượng chảy giữa chúng. Chúng giải quyết các vấn đề liên quan ở những nơi khác nhau, và nhầm lẫn hai thứ là một sai lầm phổ biến và tốn kém.
Ngành đặt tên hai hướng lưu lượng bằng một ẩn dụ la bàn. Lưu lượng bắc-nam là lưu lượng băng qua ranh giới của hệ thống bạn: một ứng dụng di động, một trình duyệt, hay một đối tác gọi vào. Lưu lượng đông-tây là lưu lượng ở lại bên trong hệ thống của bạn: dịch vụ A gọi dịch vụ B gọi dịch vụ C để thỏa mãn một yêu cầu. Một cổng API là chuyên gia cho bắc-nam. Một lưới dịch vụ là chuyên gia cho đông-tây. Giữ sự phân biệt đó sắc nét là ý tưởng hữu ích nhất của chương này, vì nó cho bạn biết công cụ nào sở hữu chính sách nào, và ngăn bạn làm cùng một việc hai lần.
Với các đội lớn, những tầng này là cách bạn thực thi một chính sách một lần thay vì một trăm lần. Khi xác thực, mã hóa khi truyền và giới hạn tốc độ sống trong một tầng dùng chung, một bản sửa bảo mật đến mọi dịch vụ vào ngày bạn triển khai tầng đó, thay vì chờ hàng trăm tồn đọng. Trong bối cảnh doanh nghiệp và chính phủ, sự tập trung hóa đó thường là mục đích: kiểm toán viên muốn một nơi duy nhất, chứng minh được nơi quyền truy cập được kiểm tra và lưu lượng được mã hóa, và một cổng hay lưới dùng chung cho họ chính xác điểm thực thi chính sách đó. Chương này xây trên các phong cách kiến trúc của chương 3.2, thực tế hệ thống phân tán của chương 3.3, và nguyên lý mạng cơ bản của chương 3.13, và biến chúng thành hướng dẫn cụ thể về ai xử lý lưu lượng của bạn.
Các nguyên tắc chính
- Tách bắc-nam (cổng) khỏi đông-tây (lưới); để mỗi bên sở hữu hướng của mình.
- Đẩy các mối quan tâm xuyên suốt vào một tầng dùng chung để bạn viết chúng một lần, không phải theo từng dịch vụ.
- Chỉ áp dụng lưới dịch vụ khi số lượng dịch vụ khiến việc đi dây theo từng dịch vụ là chi phí lớn hơn.
- Xác định một điểm thực thi chính sách cho mỗi mối quan tâm; đừng bao giờ để cổng và lưới cùng làm một việc.
- Giữ dịch vụ mỏng: nền tảng xử lý vận chuyển, dịch vụ xử lý logic nghiệp vụ.
- Ưu tiên mạng dựa trên danh tính, không tin cậy hơn là sự tin cậy dựa trên vị trí mạng.
- Mua độ phức tạp vận hành của một lưới với đôi mắt mở, và đo xem nó có hoàn vốn không.
Khuyến nghị
Hiểu cổng API làm gì
Một cổng API là điểm vào duy nhất đứng phía trước các dịch vụ của bạn và trung gian mọi yêu cầu từ thế giới bên ngoài. Ở mức đơn giản nhất nó là một proxy ngược thông minh (một máy chủ nhận yêu cầu của máy khách và chuyển tiếp chúng đến backend đúng), nhưng một cổng xứng với tên của nó bằng cách làm nhiều hơn chuyển tiếp rất nhiều. Nó định tuyến mỗi yêu cầu đến dịch vụ đúng dựa trên đường dẫn, máy chủ hoặc tiêu đề. Nó xác thực bên gọi (xác minh họ là ai) và cấp quyền cho yêu cầu (kiểm tra họ được làm gì), để một dịch vụ phía sau có thể tin rằng một yêu cầu đã qua cửa trước. Nó thực thi giới hạn tốc độ (giới hạn số yêu cầu mỗi máy khách theo thời gian) và hạn ngạch (giới hạn tổng mức dùng trong một cửa sổ dài hơn) để một máy khách ồn ào hay lạm dụng không thể bỏ đói những máy khác.
Một cổng cũng định hình lại lưu lượng. Biến đổi yêu cầu viết lại tiêu đề, dịch giữa các giao thức, hoặc điều chỉnh định dạng của máy khách cũ cho phù hợp kỳ vọng của một dịch vụ mới. Tổng hợp API cho phép cổng tỏa một yêu cầu đến thành nhiều dịch vụ và ghép phản hồi của chúng thành một, để máy khách thực hiện một lệnh gọi thay vì sáu. Hỗ trợ phiên bản cho phép bạn chạy v1 và v2 của một API cạnh nhau và định tuyến mỗi máy khách đến phiên bản nó mong đợi, mua cho bạn chỗ để tiến hóa mà không làm hỏng ai. Tập trung những mối quan tâm này ở rìa giữ cho các dịch vụ của bạn tập trung vào logic nghiệp vụ và cho bạn một nơi để quan sát, bảo mật và điều tiết mọi thứ đi vào. Thiết kế của các API mà cổng đứng trước là chủ đề của chương 2.3, và các kiểm tra danh tính nó thực hiện dựa vào chương 4.7.
Dùng mẫu backend-for-frontend cho các máy khách phân kỳ
Một API đa dụng duy nhất thường phục vụ cùng lúc ứng dụng web, ứng dụng di động và tích hợp đối tác, và phục vụ tất cả chúng hơi tồi. Máy khách di động muốn tải trọng nhỏ và ít vòng đi về vì băng thông và pin khan hiếm; máy khách web có thể xử lý các phản hồi lắm lời, phong phú hơn; đối tác muốn một hợp đồng ổn định không bao giờ làm họ bất ngờ. Mẫu backend cho frontend (BFF) giải quyết căng thẳng này bằng cách cho mỗi lớp máy khách một cổng mỏng riêng, được điều chỉnh theo nhu cầu của máy khách đó, đứng phía trước các dịch vụ dùng chung phía sau.
Một BFF là một cổng với đối tượng hẹp hơn. BFF di động tổng hợp và cắt tỉa phản hồi để ứng dụng thực hiện một lệnh gọi hiệu quả; BFF web phơi bày một hình dạng đầy đủ hơn; BFF đối tác giữ một hợp đồng thay đổi chậm, được đánh phiên bản cẩn thận. Mỗi đội có thể tiến hóa BFF của mình mà không chờ các đội khác, thường là thắng lợi thực sự, vì nó tách các đội máy khách khỏi nhau. Cái giá là nhiều bộ phận chuyển động hơn và một ít logic trùng lặp giữa các BFF, nên hãy dành mẫu này cho các trường hợp nhu cầu máy khách thực sự phân kỳ. Khi mọi máy khách muốn cùng một thứ, một cổng đơn giản và tốt hơn.
Hiểu lưới dịch vụ làm gì
Một lưới dịch vụ quản lý lưu lượng đông-tây giữa các dịch vụ của bạn, và làm vậy mà không yêu cầu các dịch vụ đó đổi mã. Lưới cổ điển hoạt động bằng cách triển khai một proxy sidecar (một tiến trình proxy nhỏ chạy cạnh mỗi thể hiện dịch vụ và chặn mọi lưu lượng mạng của nó). Dịch vụ của bạn nghĩ nó đang nói chuyện trực tiếp với một dịch vụ khác; thực ra nó nói chuyện với sidecar cục bộ của nó, nơi xử lý lệnh gọi mạng thật. Vì mọi yêu cầu giờ chảy qua một proxy mà nền tảng kiểm soát, lưới có thể thực thi hành vi đồng nhất qua mọi dịch vụ, ở mọi ngôn ngữ, không có thư viện dùng chung nào phải giữ đồng bộ.
Nó thực thi gì? Thứ nhất, TLS tương hỗ (mTLS), nơi cả hai phía của mỗi kết nối xuất trình chứng chỉ và mã hóa lưu lượng, để các lệnh gọi dịch vụ-với-dịch vụ được xác thực và riêng tư theo mặc định. Thứ hai, quản lý lưu lượng: lưới có thể chuyển một phần trăm nhỏ lưu lượng sang phiên bản mới cho một bản phát hành canary, chia lưu lượng theo tiêu đề để kiểm thử, hoặc phản chiếu lưu lượng sang một dịch vụ bóng. Thứ ba, khả năng phục hồi: thử lại, thời gian chờ và ngắt mạch (các mẫu của chương 2.20) được áp dụng ở tầng nền tảng, cấu hình bằng chính sách thay vì mã hóa vào từng dịch vụ. Thứ tư, khả năng quan sát: vì mọi yêu cầu đi qua một proxy, lưới phát ra các chỉ số, nhật ký và truy vết phân tán nhất quán cho mọi lưu lượng dịch vụ-với-dịch vụ, nuôi các thực hành quan sát của chương 9.2. Tác giả dịch vụ không viết gì trong số này mà nhận được tất cả.
Biết mẫu sidecar và các lựa chọn không sidecar
Mô hình sidecar thanh nhã nhưng không miễn phí. Mỗi thể hiện dịch vụ giờ chạy thêm một container proxy tiêu thụ bộ nhớ và CPU, và mỗi lệnh gọi tạo ra hai bước nhảy mạng thêm (vào sidecar cục bộ và ra từ sidecar từ xa), thêm một chút độ trễ. Ở một nhúm dịch vụ chi phí chung này vô hình; qua hàng nghìn pod nó trở thành một dòng thực trong hóa đơn tính toán và ngân sách độ trễ của bạn. Chi phí đó đã thúc đẩy một làn sóng các cách tiếp cận không sidecar, hay không proxy.
Hai hướng quan trọng. Một hướng chuyển chức năng lưới ra khỏi sidecar theo từng pod và vào một proxy theo từng nút, để nhiều dịch vụ trên cùng máy chia sẻ một proxy thay vì mỗi cái chạy proxy riêng; điều này đánh đổi một ít cô lập lấy mức giảm chi phí chung lớn. Hướng kia, cách tiếp cận không proxy, nhúng logic của lưới trực tiếp vào dịch vụ qua một thư viện mỏng hoặc môi trường chạy, loại bỏ hoàn toàn các bước nhảy thêm với cái giá là một phụ thuộc theo từng ngôn ngữ. Một diễn biến mới hơn đẩy một số chức năng lưới vào nhân hệ điều hành bằng eBPF (một công nghệ chạy các chương trình sandbox bên trong nhân Linux), có thể thực thi chính sách và thu thập đo đạc từ xa với ít chi phí chung hơn một proxy không gian người dùng. Bạn không cần đặt cược vào một người thắng hôm nay. Bạn cần biết rằng thuế sidecar là thật, rằng các lựa chọn thay thế tồn tại, và rằng các lựa chọn nền tảng của bạn không nên khóa bạn khỏi việc áp dụng chúng sau này. Những mẫu này nằm trên nền móng điều phối container của chương 8.3.
Quyết định khi nào một lưới xứng đáng với độ phức tạp của nó
Một lưới dịch vụ mạnh mẽ và thực sự phức tạp để vận hành. Nó thêm một mặt phẳng điều khiển để vận hành, các proxy để nâng cấp, chứng chỉ để xoay vòng, và một tầng mới để gỡ lỗi khi một yêu cầu biến mất. Độ phức tạp đó đáng để mua khi bạn có đủ dịch vụ để việc đi dây các mối quan tâm này bằng tay, theo từng dịch vụ và từng ngôn ngữ, tốn hơn việc vận hành lưới. Tín hiệu ước chừng là quy mô và sự đa dạng đa ngôn ngữ: hàng chục hay hàng trăm dịch vụ, viết bằng nhiều ngôn ngữ, nơi một thư viện dùng chung cho mTLS và thử lại sẽ là cơn ác mộng để giữ nhất quán. Ở quy mô đó, một lưới tự hoàn vốn bằng tính đồng nhất và bảo mật chứng minh được.
Lưới không xứng đáng với độ phức tạp của nó khi bạn có một nhúm dịch vụ, một ngôn ngữ duy nhất, hoặc một đội nhỏ. Với một hệ thống khiêm tốn, một thư viện hay khung tốt có thể cho bạn mTLS, thử lại và chỉ số với gánh nặng vận hành nhẹ hơn nhiều so với một lưới đầy đủ, và một cổng đơn giản cộng thư viện máy khách hợp lý thường bao quát mọi thứ bạn cần. Áp dụng lưới vì nó hợp mốt, trước khi quy mô của bạn đòi hỏi, là cách phổ biến để dành một năm vận hành hạ tầng giải quyết một vấn đề bạn không có. Hãy bắt đầu với cổng, thêm các mẫu khả năng phục hồi trong mã hoặc thư viện, và với tới lưới khi số lượng dịch vụ và ngôn ngữ khiến cách tiếp cận theo từng dịch vụ tốn hơn. Đây là cùng kỷ luật “nó có xứng đáng với độ phức tạp” mà các chương đám mây và hệ thống phân tán (3.11 và 3.3) quay lại hết lần này đến lần khác.
Tránh xử lý kép nơi cổng và lưới chồng lấn
Cổng và lưới chồng lấn, và sự chồng lấn là nơi các đội tự làm hại mình. Cả hai có thể thử lại, cả hai có thể thực thi thời gian chờ, cả hai có thể kiểm tra danh tính, cả hai có thể thu thập đo đạc. Nếu cổng thử lại một yêu cầu ba lần và lưới cũng thử lại ba lần ở mỗi bước nhảy nội bộ, một lần thử lại của máy khách có thể bùng nổ thành hàng chục lệnh gọi backend và biến một trục trặc nhỏ thành bão thử lại. Nếu cả hai tầng thực thi thời gian chờ và cái bên trong dài hơn cái bên ngoài, cái bên ngoài bỏ cuộc trong khi cái bên trong vẫn làm việc, lãng phí công sức vào một phản hồi không ai đọc.
Cách sửa là một sự phân công lao động rõ ràng được viết ra và thống nhất. Giao mỗi mối quan tâm cho đúng một tầng. Cổng sở hữu các mối quan tâm bắc-nam: xác thực người dùng cuối, giới hạn tốc độ và hạn ngạch bên ngoài, biến đổi yêu cầu, và tổng hợp API cho máy khách. Lưới sở hữu các mối quan tâm đông-tây: mTLS dịch vụ-với-dịch vụ, thử lại và ngắt mạch nội bộ, và chuyển lưu lượng giữa các phiên bản dịch vụ. Ở nơi một mối quan tâm có thể sống ở cả hai, hãy chọn một chủ sở hữu và để tầng kia chuyển qua. Hãy cấu hình ngân sách thử lại và phân cấp thời gian chờ để thời gian chờ ngoài luôn dài hơn công việc bên trong mà nó chờ. Mục tiêu là mỗi yêu cầu có đúng một nơi xử lý mỗi mối quan tâm, và không yêu cầu nào bị thử lại, xác thực hay ghi nhật ký hai lần một cách tình cờ.
Coi cổng và lưới là điểm thực thi chính sách cho không tin cậy
Lý do sâu nhất để chạy các tầng này là kiến trúc bảo mật. Không tin cậy là nguyên tắc rằng không yêu cầu nào được tin vì nó đến từ đâu; mọi yêu cầu phải chứng minh danh tính và quyền của nó, ngay cả bên trong mạng của chính bạn. Mô hình cũ tin bất cứ thứ gì đã ở bên trong chu vi, nghĩa là một dịch vụ bị xâm phạm có thể đi lại tự do. Không tin cậy thay sự tin cậy theo vị trí mạng bằng sự tin cậy dựa trên danh tính ở mọi bước nhảy, và cổng cùng lưới là các điểm thực thi tự nhiên nơi danh tính đó được kiểm tra.
Cổng là điểm thực thi chính sách cho danh tính bên ngoài: nó xác minh người dùng cuối hay đối tác trước khi bất cứ thứ gì đến dịch vụ của bạn. Lưới là điểm thực thi chính sách cho danh tính khối lượng công việc: mỗi dịch vụ nhận một danh tính mật mã, mTLS chứng minh nó trên mỗi lệnh gọi, và chính sách quyết định dịch vụ nào được nói chuyện với dịch vụ nào. Cùng nhau chúng cho bạn phòng thủ theo chiều sâu, nơi một yêu cầu được kiểm tra ở rìa và lại giữa các dịch vụ, để việc xâm phạm một dịch vụ không trao quyền di chuyển tự do cho phần còn lại. Trong các triển khai đa cụm và đa vùng, một lưới có thể mở rộng vải danh tính này qua các ranh giới cụm, để một dịch vụ ở một cụm xác thực với dịch vụ ở cụm khác với cùng bảo đảm mTLS nó dùng cục bộ, cho bạn mạng không tin cậy nhất quán ngay cả khi dấu chân lan rộng. Nền tảng danh tính ở đây liên kết trực tiếp với chương 4.7.
Đánh đổi: ưu và nhược điểm
| Cách tiếp cận | Ưu điểm | Nhược điểm |
|---|---|---|
| Cổng API | Một nơi cho xác thực, giới hạn tốc độ, tổng hợp, phiên bản | Một điểm nghẽn đơn lẻ để mở rộng và giữ sẵn sàng cao |
| Backend cho frontend | Mỗi máy khách có một API được điều chỉnh, tiến hóa độc lập | Nhiều cổng hơn để chạy; logic trùng lặp giữa các BFF |
| Lưới dịch vụ (sidecar) | mTLS, thử lại, khả năng quan sát đồng nhất không đổi mã | Chi phí chung của proxy, độ trễ, và một mặt phẳng điều khiển để vận hành |
| Lưới không sidecar / không proxy | Chi phí chung và độ trễ thấp hơn sidecar theo từng pod | Kém trưởng thành; cô lập yếu hơn hoặc phụ thuộc theo từng ngôn ngữ |
| Khả năng phục hồi dựa trên thư viện | Dễ vận hành; không cần hạ tầng thêm | Trùng lặp theo từng ngôn ngữ; khó giữ nhất quán ở quy mô lớn |
| Lưới xuyên cụm | Danh tính không tin cậy nhất quán ở mọi nơi | Độ phức tạp vận hành và mạng đáng kể |
Căng thẳng trung tâm là tính đồng nhất so với chi phí vận hành. Một tầng dùng chung mua cho bạn sự nhất quán, bảo mật chứng minh được, và chính sách bạn viết một lần, nhưng nó là một hệ thống thật bạn phải chạy, mở rộng, bảo mật và gỡ lỗi, và nó tự chèn vào đường đi của mọi yêu cầu. Hãy giải quyết căng thẳng theo quy mô và nhu cầu. Một cổng gần như luôn hoàn vốn ngay khi bạn có máy khách bên ngoài, vì các mối quan tâm nó tập trung hóa là những thứ bạn không thể tránh. Một lưới hoàn vốn muộn hơn, khi số lượng dịch vụ và ngôn ngữ khiến đi dây theo từng dịch vụ là con đường tốn hơn. Dưới ngưỡng đó, thư viện và một cổng đơn giản cho bạn phần lớn lợi ích với một phần nhỏ chi phí. Trên nó, tính đồng nhất của lưới đáng giá bằng trọng lượng của nó. Sai lầm theo cả hai hướng là áp dụng theo mốt thay vì theo nhu cầu: một lưới quá sớm là một năm cạo lông bò, và một lưới bỏ qua quá muộn là một trăm bản cài đặt mTLS không nhất quán, làm bằng tay.
Câu hỏi để thảo luận với đội của bạn
Với mỗi mối quan tâm xuyên suốt (xác thực, thử lại, thời gian chờ, giới hạn tốc độ, mã hóa, đo đạc từ xa), tầng đơn lẻ nào sở hữu nó, và mọi người có gọi tên được chủ sở hữu mà không đoán không? Đây là câu hỏi ngăn xử lý kép, và hầu hết các đội chưa bao giờ trả lời nó tường minh, nghĩa là câu trả lời khác nhau theo dịch vụ và theo tác giả. Hãy mang một danh sách cụ thể các mối quan tâm dọc bên trái và các tầng của bạn (thư viện máy khách, cổng, lưới, dịch vụ riêng lẻ) ngang phía trên, và cùng nhau điền vào lưới. Những chỗ hai ô được đánh dấu cho một mối quan tâm là các cơn bão thử lại và đảo ngược thời gian chờ đang chờ xảy ra. Những hàng trống là các mối quan tâm không ai xử lý. Sản phẩm bàn giao là một bảng thống nhất duy nhất, được công bố nơi mọi đội thấy, nói rằng đúng một tầng sở hữu mỗi mối quan tâm và các tầng khác chuyển qua. Bảng đó đáng giá hơn bất kỳ lượng cấu hình cổng hay lưới nào, vì nó là thứ giữ cho hai tầng không đánh nhau.
Chúng ta thực sự có đủ dịch vụ và đa dạng ngôn ngữ để biện minh cho một lưới dịch vụ, hay chúng ta sắp mua một mặt phẳng điều khiển để giải quyết một vấn đề chúng ta không có? Một lưới là một cam kết vận hành nghiêm túc, và câu trả lời trung thực với nhiều đội là một thư viện tốt cộng một cổng sẽ phục vụ họ tốt hơn hôm nay. Hãy mang số lượng dịch vụ thực của bạn, số ngôn ngữ chúng được viết, và một đánh giá trung thực về việc logic mạng trùng lặp thực sự làm hại bạn bao nhiêu bây giờ. Rồi mang phía bên kia: ai sẽ vận hành lưới, nâng cấp proxy của nó, xoay vòng chứng chỉ, và bị gọi khi nó định tuyến sai một yêu cầu. Nếu nỗi đau của đi dây theo từng dịch vụ nhỏ hơn chi phí chạy lưới, bạn có câu trả lời, và đó là chờ. Nếu bạn đang chìm trong mã mTLS và thử lại không nhất quán qua hàng chục dịch vụ đa ngôn ngữ, lưới xứng đáng chỗ đứng. Điểm là quyết định dựa trên bằng chứng, không phải theo cách một bài nói chuyện hội nghị làm lưới trông như thế nào.
Ranh giới không tin cậy của chúng ta hôm nay ở đâu, và điều gì xảy ra nếu một dịch vụ nội bộ bị xâm phạm? Nhiều hệ thống vẫn tin bất cứ thứ gì đã ở bên trong mạng, nghĩa là một dịch vụ bị xâm phạm đơn lẻ có thể di chuyển ngang và với tới mọi thứ khác, và các đội thường chỉ phát hiện điều này trong một sự cố. Hãy đi qua bán kính ảnh hưởng một cách trung thực: nếu kẻ tấn công sở hữu một trong các dịch vụ của bạn, nó có thể gọi gì, đọc gì, và cái gì ngăn nó? Hãy mang câu trả lời hiện tại của bạn về cách các lệnh gọi dịch vụ-với-dịch vụ được xác thực và mã hóa, và cụ thể về lệnh gọi nào được bảo vệ bằng mTLS và lệnh gọi nào là sự tin cậy văn bản thuần dựa trên việc ở cùng mạng. Hành động tiếp theo là một kế hoạch có chủ đích cho truy cập dựa trên danh tính ở mọi bước nhảy, với cổng kiểm tra danh tính bên ngoài và lưới hay thứ tương đương kiểm tra danh tính khối lượng công việc, để một vụ xâm phạm được khoanh vùng thay vì thảm khốc. Ngay cả khi bạn chưa sẵn sàng chạy một lưới đầy đủ, gọi tên nơi ranh giới tin cậy thực sự nằm là bước trung thực đầu tiên.
Nếu tầng cổng API của chúng ta hỏng ngay bây giờ, bao nhiêu phần hệ thống tối đen, và chúng ta đã kiểm thử thất bại đó thay vì giả định bỏ qua nó chưa? Cổng tập trung nhiều đến mức sự cố của nó đưa mọi thứ phía sau ngoại tuyến, và các đội lớn có xu hướng đầu tư thiếu vào dự phòng của nó chính vì nó hoạt động lặng lẽ cho đến khi không còn. Hãy cân nhắc các lực kéo đối lập: một cổng đơn giản duy nhất dễ suy luận và rẻ để chạy, trong khi một tầng mở rộng ngang, đa vùng sẵn sàng tốn hơn và thêm cấu hình chuyển đổi dự phòng cùng độ phức tạp riêng. Hãy mang số liệu thực vào cuộc thảo luận, gồm hôm nay chạy bao nhiêu thể hiện, qua bao nhiêu vùng sẵn sàng, thời gian chuyển đổi dự phòng là bao nhiêu, và lần cuối bạn chạy một ngày diễn tập cố ý giết cổng là khi nào. Với các nền tảng doanh nghiệp và chính phủ mang cam kết thời gian hoạt động hoặc mức dịch vụ luật định, hãy thêm hình phạt hợp đồng hay quy định cho một sự cố, vì một cửa trước không có dự phòng là rủi ro sẵn sàng mà bạn đã lặng lẽ chấp nhận thay mặt mọi dịch vụ và mọi công dân phía sau.
Chúng ta đã đo thuế sidecar mà lưới của mình thực sự tính chưa, và chúng ta có kế hoạch cho các lựa chọn không sidecar và eBPF, hay đang trả tiền mù quáng? Ở quy mô lớn chi phí chung proxy theo từng pod về tính toán và độ trễ thôi vô hình và trở thành một dòng thực trong ngân sách, vậy mà nhiều đội chạy hàng nghìn sidecar mà không bao giờ đo chi phí. Căng thẳng là giữa sự trưởng thành và cô lập của mô hình sidecar ở một bên và chi phí chung thấp hơn của proxy theo từng nút, thư viện không proxy, hay cách tiếp cận eBPF trong nhân ở bên kia, vốn mới hơn và đánh đổi một ít cô lập hoặc thêm một phụ thuộc theo từng ngôn ngữ. Hãy mang các con số đã đo: bộ nhớ và CPU mà proxy tiêu thụ qua cả đội hình, độ trễ đuôi thêm mỗi bước nhảy, và tỷ lệ hóa đơn tính toán của bạn mà lưới đại diện. Với một doanh nghiệp lớn chạy lưới qua hàng nghìn pod, hay một nền tảng chính phủ dưới sự soi xét ngân sách, đây là quyết định chi tiêu mà cơ quan giám sát cuối cùng sẽ hỏi, nên biết thuế và liệu các lựa chọn nền tảng của bạn có giữ các phương án rẻ hơn mở là sự thẩm định cơ bản.
Mỗi lớp máy khách có thực sự cần một backend cho frontend riêng, hay chúng ta sắp nhân đôi logic qua các cổng cho những máy khách thực ra muốn cùng một thứ? Mẫu BFF tách các đội máy khách và cho mỗi đội tiến hóa một hợp đồng được điều chỉnh, nhưng mỗi BFF mới là một cổng nữa để chạy, bảo mật và giữ đồng bộ, và logic trùng lặp giữa chúng lặng lẽ trở thành một khoản thuế bảo trì. Các cân nhắc cạnh tranh là quyền tự chủ của đội và hiệu quả đặc thù máy khách so với chi phí vận hành và sự trôi dạt của nhiều cổng gần giống nhau. Hãy mang bằng chứng về nhu cầu của các máy khách thực sự phân kỳ đến đâu: kích thước tải trọng, số vòng đi về, nhịp phiên bản, và bao nhiêu lần thay đổi của một máy khách lẽ ra đã chặn máy khác dưới một cổng dùng chung duy nhất. Trong một tổ chức lớn có nhiều đội máy khách, hay một nền tảng chính phủ phục vụ cùng lúc ứng dụng web công khai, ứng dụng di động và tích hợp đối tác, câu hỏi trung thực là liệu sự phân kỳ có biện minh cho sự sinh sôi không, vì một BFF cho mỗi máy khách mà tất cả muốn cùng hình dạng là sự lan tràn bạn sẽ trả tiền duy trì trong nhiều năm.
Góc nhìn theo lĩnh vực
Công ty khởi nghiệp. Hãy phát hành một cổng API và bỏ qua lưới. Với một nhúm dịch vụ và đội nhỏ xíu, một cổng đơn lẻ xử lý xác thực, giới hạn tốc độ và tổng hợp, trong khi một thư viện máy khách dùng chung cho bạn mTLS và thử lại với một phần nhỏ chi phí của một mặt phẳng điều khiển. Nguồn lực khan hiếm nhất của bạn là sự chú ý kỹ thuật, nên một lưới bạn không vận hành được là một gánh nặng, không phải hào lũy. Giữ cổng đủ dự phòng để sống sót khi một nút chết, và chỉ xem lại lưới khi số lượng dịch vụ và sự đa dạng ngôn ngữ thực sự buộc đặt câu hỏi.
Doanh nghiệp nhỏ. Bạn không có đội nền tảng để chạy lưới, vì vậy hãy dựa vào những gì nền tảng lưu trữ hay sản phẩm cổng của bạn cho sẵn: TLS được quản lý, giới hạn tốc độ tích hợp, và một cổng được lưu trữ thay vì cái bạn tự vá. Hãy đóng khung lựa chọn là mua-so-với-xây, và hãy mua, vì một cổng API được quản lý tốn ít hơn số giờ kỹ sư để vận hành cái riêng của bạn. Hãy coi mã hóa dịch vụ-với-dịch vụ nội bộ là tính năng nền tảng của bạn cung cấp, không phải dự án bạn bố trí nhân sự.
Doanh nghiệp lớn. Với hàng trăm dịch vụ qua nhiều đội và ngôn ngữ, một lưới xứng đáng với độ phức tạp của nó, và công việc thực sự là quản trị: một sự phân công lao động bằng văn bản để cổng và lưới không bao giờ xử lý kép một mối quan tâm, mTLS và đo đạc từ xa đồng nhất, và một đội nền tảng sở hữu nâng cấp proxy và xoay vòng chứng chỉ. Kiểm toán viên muốn một điểm thực thi duy nhất, chứng minh được cho truy cập và mã hóa, nên hãy chuẩn hóa giao diện và biến chính sách thành thứ các đội thừa hưởng thay vì cài đặt lại. Quản lý thuế sidecar như một dòng ngân sách thực, và giữ các lựa chọn không sidecar mở để bạn không bị khóa khỏi các cách tiếp cận rẻ hơn sau này.
Chính phủ. Quy tắc mua sắm, minh bạch và trách nhiệm giải trình công định hình kiến trúc. Hãy coi cổng và lưới là xương sống không tin cậy mà cơ quan quản lý mong đợi: mọi công dân và đối tác được xác thực ở cửa trước, mọi lệnh gọi nội bộ được xác thực và mã hóa bằng danh tính khối lượng công việc, và một dấu vết kiểm toán ở mỗi điểm thực thi chứng minh quyền truy cập được kiểm tra ở đâu và lưu lượng được mã hóa ở đâu. Hãy ưu tiên tiêu chuẩn mở và cấu hình di động hơn khóa chặt độc quyền mà quy tắc mua sắm có thể cấm, và công bố, ở nơi phù hợp, nền tảng bảo vệ dữ liệu công dân thế nào khi nó băng qua từng ranh giới.
Ví dụ
Công ty khởi nghiệp. Một công ty khởi nghiệp mười hai người chạy tám dịch vụ sau một cổng API duy nhất. Cổng xử lý mọi công việc bắc-nam: nó xác thực người dùng bằng kiểm tra token, thực thi giới hạn tốc độ theo gói để người dùng bậc miễn phí không làm ngập hệ thống, và tổng hợp vài điểm cuối lắm lời thành các lệnh gọi đơn thân thiện với di động. Với lưu lượng đông-tây họ cố ý bỏ qua lưới dịch vụ, vì tám dịch vụ trong hai ngôn ngữ không biện minh cho một mặt phẳng điều khiển. Thay vào đó họ nhận mTLS và thử lại từ một thư viện máy khách dùng chung và quản lý chứng chỉ tích hợp của nền tảng, và thu thập truy vết bằng một tác nhân nhẹ. Khi sau này họ thêm một máy khách di động riêng với nhu cầu tải trọng chặt hơn, họ đưa vào một backend cho frontend di động bên cạnh cổng web hiện có. Họ xem lại câu hỏi về lưới mỗi năm và liên tục quyết định, đúng đắn, rằng họ chưa vượt ngưỡng nơi nó sẽ hoàn vốn.
Doanh nghiệp lớn. Một ngân hàng đa quốc gia chạy vài trăm dịch vụ qua nhiều đội và ngôn ngữ, và ở đây một lưới dịch vụ xứng đáng với độ phức tạp của nó. Mỗi dịch vụ nhận một danh tính khối lượng công việc và mTLS theo mặc định, nên mọi lưu lượng nội bộ được xác thực và mã hóa mà không đội nào viết mã mật mã, thỏa mãn cả tổ chức bảo mật lẫn kiểm toán viên muốn một điểm thực thi chứng minh được. Lưới áp dụng thử lại, thời gian chờ và ngắt mạch đồng nhất bằng chính sách, và chuyển lưu lượng dần dần cho các bản phát hành canary để một lần triển khai xấu chạm một phần trăm người dùng trước khi chạm tất cả. Một tầng cổng API đứng trước lưu lượng bên ngoài và đối tác, sở hữu xác thực, hạn ngạch và phiên bản, với một quy tắc cứng bằng văn bản rằng thử lại nội bộ chỉ sống trong lưới và giới hạn tốc độ bên ngoài chỉ sống trong cổng, để hai tầng không bao giờ xử lý kép một yêu cầu. Đo đạc từ xa nhất quán từ mọi proxy nuôi một nền tảng quan sát trung tâm cho phép một kỹ sư trực ca truy một yêu cầu qua hàng chục bước nhảy dịch vụ.
Chính phủ. Một cơ quan thuế quốc gia hiện đại hóa nền tảng nộp hồ sơ hướng đến công dân và coi cổng cùng lưới là xương sống của kiến trúc không tin cậy mà cơ quan quản lý yêu cầu. Một cổng API là cửa trước được kiểm soát: mọi công dân và mọi đối tác được xác thực và cấp quyền ở đó, giới hạn tốc độ bên ngoài bảo vệ hệ thống trong đợt tăng đột biến hạn nộp hồ sơ, và các định dạng máy khách cũ được biến đổi ở rìa để các tích hợp cũ tiếp tục hoạt động. Phía sau nó, một lưới dịch vụ cho mỗi dịch vụ nội bộ một danh tính mật mã và thực thi mTLS trên mọi lệnh gọi, nên không dịch vụ nào được tin chỉ vì ở bên trong mạng, và chính sách truy cập liệt kê tường minh dịch vụ nào được gọi dịch vụ nào. Vì nền tảng trải qua nhiều trung tâm dữ liệu cho khả năng phục hồi, lưới mở rộng cùng bảo đảm danh tính và mã hóa qua các cụm, cho mạng không tin cậy nhất quán trên toàn quốc. Mỗi điểm thực thi phát ra một dấu vết kiểm toán, để cơ quan có thể chứng minh với các cơ quan giám sát chính xác quyền truy cập được kiểm tra ở đâu và lưu lượng được mã hóa ở đâu.
Luận chứng kinh doanh: động lực, ROI và TCO
Lợi tức của một cổng dễ thấy và thường lớn. Thay vì mọi dịch vụ cài đặt lại xác thực, giới hạn tốc độ và ghi nhật ký yêu cầu, bạn xây những thứ đó một lần ở rìa và mọi dịch vụ thừa hưởng chúng. Một bản sửa bảo mật hay chính sách giới hạn tốc độ mới được phát hành trong một lần triển khai thay vì một trăm, rút ngắn thời gian đóng một lỗ hổng và hạ chi phí của mọi cuộc kiểm toán, vì có một nơi duy nhất để kiểm tra. Các tính năng tổng hợp và phiên bản cắt giảm vòng đi về của máy khách và cho phép bạn tiến hóa API mà không làm hỏng bên gọi, giảm cả chi phí độ trễ lẫn thuế phối hợp giữa các đội. Với hầu như bất kỳ hệ thống nào có máy khách bên ngoài, một cổng nhanh chóng tự hoàn vốn.
Lưới dịch vụ có luận chứng kinh doanh tinh tế hơn, vì tổng chi phí sở hữu của nó là thật và liên tục. Bạn trả cho tính toán và độ trễ của proxy, cho các kỹ sư vận hành mặt phẳng điều khiển, và cho đường cong học của việc gỡ lỗi một tầng mới. Chi phí đó được biện minh khi phương án thay thế (cài đặt mTLS, thử lại và đo đạc từ xa theo từng dịch vụ, từng ngôn ngữ) sẽ lớn hơn và, tệ hơn, không nhất quán theo cách tạo ra lỗ hổng bảo mật và sự cố. Ở quy mô cao lưới biến một trăm giải pháp làm tay mong manh thành một giải pháp đồng nhất, chứng minh được, và ROI hiện ra ở ít sự cố bảo mật hơn, triển khai an toàn nhanh hơn qua chuyển lưu lượng, và khả năng quan sát tốt hơn đáng kể. Dưới quy mô đó, phép tính trung thực thường ủng hộ thư viện và một cổng, và bước đi có kỷ luật là chờ. Để trình bày với ban lãnh đạo, hãy nối cổng với các chỉ số họ đã theo dõi (thời gian khắc phục lỗ hổng, chi phí kiểm toán, chi phí chung phối hợp API) và nối lưới với việc khoanh vùng sự cố bảo mật, an toàn triển khai, và chi phí của sự trùng lặp đa ngôn ngữ mà nó thay thế.
Phản mẫu và cạm bẫy
- Lưới trước khi cần: áp dụng một lưới dịch vụ đầy đủ ở một nhúm dịch vụ, mua một mặt phẳng điều khiển để giải quyết vấn đề bạn chưa có.
- Thử lại kép: cổng và lưới đều thử lại, nên một lệnh gọi máy khách nhân thành một bão thử lại backend khuếch đại sự cố.
- Đảo ngược thời gian chờ: một thời gian chờ bên trong dài hơn thời gian bên ngoài, nên bên gọi bỏ cuộc trong khi bên được gọi vẫn làm việc cho một phản hồi không ai đọc.
- Cổng như một khối đơn: nhồi logic nghiệp vụ vào cổng cho đến khi nó thành nút thắt dùng chung mà mọi đội phải phối hợp để thay đổi.
- Điểm lỗi đơn: chạy một thể hiện cổng không dự phòng, nên cửa trước hỏng kéo sập mọi dịch vụ phía sau.
- Tin mạng: coi bất cứ thứ gì bên trong chu vi là an toàn, nên một dịch vụ bị xâm phạm có thể di chuyển ngang và với tới mọi thứ.
- Quyền sở hữu chồng lấn: không có sự phân công lao động bằng văn bản, nên cùng một mối quan tâm được xử lý ở cả hai tầng một cách tình cờ và không ai biết cái nào có thẩm quyền.
- Lan tràn BFF: dựng một backend cho frontend cho mỗi máy khách khi các máy khách muốn cùng một thứ, nhân lên các cổng và trùng lặp logic mà không có lợi ích.
- Bỏ qua thuế sidecar: triển khai hàng nghìn sidecar mà không đo chi phí chung về tính toán và độ trễ, rồi tự hỏi ngân sách đi đâu.
Mô hình trưởng thành
- Mức 1, Khởi đầu: Các dịch vụ nói chuyện trực tiếp với nhau không có tầng dùng chung. Xác thực, thử lại và thời gian chờ được mã hóa bằng tay theo từng dịch vụ và không nhất quán. Lưu lượng nội bộ thường là văn bản thuần và được tin vì ở trên mạng, và không có nơi nào để thực thi chính sách hay quan sát lưu lượng. Các quyết định là phản ứng, được đưa ra từng dịch vụ một khi vấn đề xuất hiện.
- Mức 2, Phát triển: Một cổng API đứng trước lưu lượng bên ngoài và tập trung xác thực, giới hạn tốc độ và định tuyến, nhưng các mối quan tâm đông-tây được xử lý bằng thư viện dùng chung với mức áp dụng không đều. Một số dịch vụ có mTLS; nhiều cái không. Các đội nhận ra sự phân biệt bắc-nam so với đông-tây, nhưng quyền sở hữu không chính thức và thực hành khác nhau từ đội này sang đội khác.
- Mức 3, Chuẩn hóa: Các mối quan tâm bắc-nam và đông-tây được tách bạch với một sự phân công lao động bằng văn bản áp dụng trong toàn tổ chức. Cổng sở hữu danh tính bên ngoài, hạn ngạch và tổng hợp; một lưới hoặc một tầng thư viện nhất quán sở hữu mTLS nội bộ, thử lại và đo đạc từ xa. Các chồng lấn được giải quyết để không mối quan tâm nào bị xử lý kép, lưu lượng nội bộ được mã hóa và kiểm tra danh tính theo mặc định, và tiêu chuẩn được lập tài liệu và thực thi thay vì để theo ý từng đội.
- Mức 4, Quản lý: Tầng lưu lượng được đo và kiểm soát theo các đường cơ sở. Bạn theo dõi thuế sidecar về tính toán và độ trễ đuôi mỗi bước nhảy, tính sẵn sàng của cổng và lưới so với ngân sách lỗi, các sự cố khuếch đại thử lại và đảo ngược thời gian chờ, độ bao phủ mTLS tính theo phần trăm các lệnh gọi nội bộ, và thời gian đẩy một thay đổi chính sách qua cả đội hình. Các chỉ số kiểm soát quyết định: một lần nâng cấp proxy, một ngân sách thử lại mới, hay một quy tắc canary được đánh giá bằng dữ liệu so với đường cơ sở thay vì bằng trực giác, và mọi sự trôi khỏi tiêu chuẩn kích hoạt một bản sửa.
- Mức 5, Điều phối: Cổng và lưới là các điểm thực thi chính sách cho một kiến trúc không tin cậy trưởng thành, với danh tính được kiểm tra ở mọi bước nhảy qua các cụm và vùng. Chuyển lưu lượng điều khiển phân phối tiến bộ an toàn, khả năng quan sát đồng nhất và phong phú, và tổ chức liên tục đánh giá cùng áp dụng các cách tiếp cận không sidecar, không proxy và eBPF ở nơi chúng hoàn vốn. Tầng lưu lượng được tích hợp với bảo mật, phân phối và hoạch định năng lực, và nó thích ứng khi quy mô, ngôn ngữ và bức tranh rủi ro dịch chuyển.
Ý tưởng để thảo luận
- Nếu cổng API duy nhất của bạn hỏng ngay bây giờ, bao nhiêu dịch vụ sẽ không với tới được, và kế hoạch của bạn để làm cho cửa trước dự phòng là gì?
- Mối quan tâm nào trong hệ thống của bạn hiện được xử lý ở cả cổng và một dịch vụ (hoặc một thư viện), và bạn sẽ chứng minh nó không bị xử lý kép thế nào?
- Ở số lượng dịch vụ và ngôn ngữ nào thì đội của bạn sẽ đồng ý rằng một lưới cuối cùng đã xứng đáng với độ phức tạp của nó, và bạn còn cách vạch đó bao xa?
- Nếu kẻ tấn công xâm phạm một dịch vụ nội bộ vào ngày mai, những dịch vụ nào khác nó có thể với tới, và kiểm tra danh tính nào sẽ ngăn nó?
- Các cách tiếp cận lưới không sidecar hay dựa trên eBPF đã đủ trưởng thành cho nền tảng của bạn chưa, và bạn sẽ đo gì để quyết định?
- Mỗi máy khách phân kỳ của bạn có thực sự cần backend cho frontend riêng, hay bạn sắp nhân đôi logic có thể giữ dùng chung?
Những điểm cần ghi nhớ
- Tách lưu lượng bắc-nam (do cổng API xử lý) khỏi lưu lượng đông-tây (do lưới dịch vụ xử lý); mỗi bên sở hữu hướng của mình, và nhầm lẫn chúng gây ra xử lý kép.
- Một cổng tập trung định tuyến, xác thực, cấp quyền, giới hạn tốc độ, hạn ngạch, biến đổi yêu cầu, tổng hợp và phiên bản, để các dịch vụ giữ mỏng và chính sách sống ở một nơi.
- Một lưới dịch vụ cho bạn mTLS, chuyển lưu lượng, thử lại và ngắt mạch ở tầng nền tảng, và khả năng quan sát đồng nhất mà không đổi mã dịch vụ, theo cách cổ điển qua các proxy sidecar.
- Chỉ áp dụng một lưới khi số lượng dịch vụ và ngôn ngữ khiến đi dây theo từng dịch vụ là con đường tốn hơn; dưới mức đó, thư viện cộng một cổng thắng, và thuế sidecar đủ thật để theo dõi.
- Coi cổng và lưới là các điểm thực thi chính sách của một kiến trúc không tin cậy, giao mỗi mối quan tâm xuyên suốt cho đúng một tầng, và kiểm tra danh tính ở mọi bước nhảy qua các cụm.
Tài liệu tham khảo và đọc thêm
- Sam Newman, Building Microservices: Designing Fine-Grained Systems
- Chris Richardson, Microservices Patterns: With Examples in Java
- Lee Calcote và Zack Butcher, Istio: Up and Running
- Ken Owens, Alois Reitbauer và những người khác; Cloud Native Landscape của CNCF và tài liệu lưới dịch vụ
- Evan Gilman và Doug Barth, Zero Trust Networks: Building Secure Systems in Untrusted Networks
- Scott Rose, Oliver Borchert, Stu Mitchell và Sean Connelly, Zero Trust Architecture, NIST Special Publication 800-207
- Susan Fowler, Production-Ready Microservices