Sử dụng Envoy Proxy để cải thiện độ tin cậy, bảo mật và khả năng giám sát của Microservices


Envoy là một proxy nguồn mở được tạo bởi Lyft. Khi thế giới đang hướng tới một kiến ​​trúc microservices, các lập trình viên đang gặp phải những khó khăn trong việc vận hành các hoạt động trong hai lĩnh vực chính:

  • Kết nối mạng.
  • Khả năng giám sát.

Envoy cố gắng giải quyết những vấn đề này bằng cách làm cho các mạng trở nên minh bạch hơn với các ứng dụng. Nó cũng cung cấp một cách để thu thập số liệu thống kê tốt hơn để việc gỡ lỗi và theo dõi các vấn đề trở nên dễ dàng hơn.

Cách phổ biến nhất mà proxy Envoy được triển khai ngày nay là kết hợp với các ứng dụng dưới dạng một sidecar. Nếu bạn chưa biết về mẫu sidecar thì bạn có thể đọc về nó trong bài viết dưới đây.

Các mẫu design pattern hiện đại
Một số mẫu design pattern có thể giúp bạn đạt được khả năng mở rộng, tính khả dụng, bảo mật, độ tin cậy và khả năng phục hồi cho ứng dụng.

Trong bài viết này, tôi sẽ nói về cách bắt đầu với Envoy Proxy với hướng dẫn DIY và cách sử dụng các tính năng khác nhau của Envoy để cải thiện độ tin cậy, bảo mật và khả năng giám sát các ứng dụng của bạn.

Giới thiệu về Envoy

Envoy là một quy trình khép kín. Khi một client gọi một proxy Envoy, yêu cầu sẽ đi qua các mô-đun Envoy khác nhau. Hãy cố gắng hiểu những điều này.

Giới thiệu về Envoy
  • Downstream - Một ứng dụng khách từ xa kết nối với Envoy.
  • Listener - Một mô-đun Envoy chịu trách nhiệm chấp nhận các kết nối mới và nạp IP / Port.
  • Filter - Một mô-đun Envoy chịu trách nhiệm xử lý các yêu cầu. Một yêu cầu có thể phải trải qua một chuỗi các bộ lọc.
  • Upstream - Một endpoint của Envoy chuyển tiếp một yêu cầu đến. Trong một mô hình sidecar, đây là ứng dụng hoặc một cụm ứng dụng / dịch vụ.

Triển khai Envoy

Trang web của Envoy liệt kê các Docker image khác nhau để bạn sử dụng. Trong hướng dẫn này, tôi sẽ đặt Envoy đằng trước một RESTful API. Nếu bạn không muốn sử dụng Envoy trong Docker container thì bạn có thể chỉ cần tải file cài đặt Envoy từ https://www.getenvoy.io/.

Tôi sẽ sử dụng một dịch vụ được tạo sẵn từ Spring Boot, dịch vụ này sẽ hoạt động như một application / microservice chính của tôi.

Khi bạn chạy lệnh dưới đây, bạn sẽ có thể thấy API đang hoạt động.

java -jar -d complete/target/rest-service-0.0.1-SNAPSHOT.jar
$curl http://localhost:8080/greeting
{"id":2,"content":"Hello, World!"}

Tiếp theo, bạn cần viết một cấu hình proxy Envoy YAML như hình dưới đây:

Cấu hình này ra lệnh cho những điều sau:

  • Nó tạo một HTTP Listener trên cổng 8585.
  • Nó tạo ra một chuỗi bộ lọc kiểm tra bất kỳ yêu cầu nào khớp với yêu cầu /greeting và chuyển tiếp yêu cầu đó tới cụm greetingservice.
  • Trong cụm greetingservice, có một endpoint chuyển hướng các yêu cầu đến địa chỉ 0.0.0.0:8080.
  • Các cụm greetingservice sẽ thực hiện cân bằng tải (load balancing) các yêu cầu sử dụng kỹ thuật ROUND_ROBIN trong trường hợp cụm chứa nhiều endpoint.
  • Nó chạy dịch vụ quản trị Envoy trên cổng 9901.

Ở đây tôi đang sử dụng Get Envoy phiên bản 1.15.0 cho thử nghiệm này. Lệnh sau sẽ khởi động proxy Envoy với cấu hình đã cho ở trên.

$getenvoy run standard:1.15.0 -- --config-path simple.yaml

Bây giờ, khi bạn nhập địa chỉ http://localhost:8585/greeting vào trình duyệt, bạn sẽ thấy Envoy bắt đầu hoạt động như một proxy cho dịch vụ greeting của bạn.

curl http://localhost:8585/greeting
{"id":6,"content":"Hello, World!"}

Bạn cũng có thể truy cập vào trang quản trị Envoy tại địa chỉ http://localhost:9901/.

Trang quản trị của Envoy

Tất cả các dịch vụ quản trị cũng có sẵn dưới dạng API.

Nếu bạn truy cập http://localhost:9901/stats, bạn sẽ có thể thấy một lượng lớn thông tin về các yêu cầu được cung cấp bởi proxy này.

Ví dụ, nếu bạn muốn biết:

  • Tổng số kết nối
  • Tổng số kết nối bị hủy
  • Tổng số kết nối đang hoạt động
  • Các phản hồi HTTP cho các yêu cầu khác nhau được xử lý
  • ...
listener.0.0.0.0_8585.downstream_cx_active: 2
listener.0.0.0.0_8585.downstream_cx_destroy: 4
listener.0.0.0.0_8585.downstream_cx_total: 6
listener.0.0.0.0_8585.downstream_pre_cx_active: 0
listener.0.0.0.0_8585.downstream_pre_cx_timeout: 0
listener.0.0.0.0_8585.http.ingress.downstream_rq_1xx: 0
listener.0.0.0.0_8585.http.ingress.downstream_rq_2xx: 3
listener.0.0.0.0_8585.http.ingress.downstream_rq_3xx: 0
listener.0.0.0.0_8585.http.ingress.downstream_rq_4xx: 2
listener.0.0.0.0_8585.http.ingress.downstream_rq_5xx: 0
listener.0.0.0.0_8585.http.ingress.downstream_rq_completed: 5
listener.0.0.0.0_8585.no_filter_chain_match: 0

Bạn cũng có thể đạt được kết quả tương tự bằng cách chạy Docker dưới dạng container trên cùng một máy chủ.

Các tính năng của Envoy

Bây giờ bạn đã biết cách chạy proxy cơ bản bằng Envoy, hãy xem một số tính năng chính:

  • Caching
  • Fault injection
  • External authorization
  • Circuit breaking
  • Stats, access logging & tracing
  • Security

Caching

Giống như các reverse proxy điển hình, Envoy cho phép cache các phản hồi. Nếu bạn biết một số đối tượng không thay đổi thường xuyên, thì bạn có thể sử dụng tính năng này.

Nó cho phép bạn triển khai các kỹ thuật cache khác nhau như:

  • no-cache - Trong trường hợp này, cache sẽ gửi yêu cầu xác thực đến máy chủ gốc trước khi phục vụ yêu cầu.
  • private - Trong trường hợp này, phản hồi được đánh dấu là riêng tư và nó sẽ không được lưu trữ trên cache công khai / dùng chung.
  • valid-for-time - Trong trường hợp này, phản hồi vẫn còn trong bộ nhớ cache một thời gian nhất định trước khi nó được xác thực lại từ máy chủ ban đầu.

Bằng cách triển khai bộ nhớ đệm, bạn có thể cải thiện độ trễ của phản hồi từ microservices của mình. Điều này cần được code trong ứng dụng / logic nghiệp vụ.

Fault injection

Nếu bạn đã nghe về kỹ thuật hỗn loạn, bạn sẽ biết rằng fault injection là một trong những kỹ thuật để kiểm tra khả năng phục hồi của các microservices của bạn.

Envoy cho phép tạo ra sự chậm trễ, hủy bỏ yêu cầu dịch vụ với phản hồi của người dùng được chỉ định. Điều này giúp kiểm tra khả năng của dịch vụ trong trường hợp có sự cố hoặc hỏng hóc hoặc quá tải. Nó có thể được giới hạn trong một tập hợp các dịch vụ cụ thể mà bạn không cần phải thay đổi code của ứng dụng.

Bạn có thể tạo một hệ thống file ảo (/etc/config/v1) có thể được sử dụng bởi Envoy để chọn các cấu hình fault injection một cách nhanh chóng. Sau đây là một ví dụ về cấu hình như vậy:

Số liệu thống kê của Envoy cũng cho phép bạn cung cấp thông tin chi tiết về các lỗi được đưa vào để bạn biết ứng dụng đang hoạt động như thế nào.

http.ingress_http.fault.aborts_injected: 6
http.ingress_http.fault.active_faults: 0
http.ingress_http.fault.delays_injected: 0
http.ingress_http.fault.faults_overflow: 0
http.ingress_http.fault.response_rl_injected: 0

External authorization

Bạn có thể sử dụng Envoy để ủy quyền các yêu cầu cho một máy chủ ủy quyền bên ngoài. Nếu bạn đang sử dụng Envoy như một sidecar, điều này dễ dàng giúp tách logic nghiệp vụ của ứng dụng khỏi máy chủ ủy quyền mà bạn sử dụng.

Nếu bạn đã quen thuộc với Open Policy Agent, đây là một ví dụ khá hay cho thấy cách sử dụng tính năng này.

Circuit Breaking

Trong bài viết trước của tôi, tôi đã nói về mẫu Circuit Breaker, có thể được sử dụng để tự động xác định sự suy giảm dịch vụ hoặc ngừng dịch vụ và bắt đầu trả lại phản hồi từ chính proxy, thay vì làm cạn kiệt tài nguyên dịch vụ ban đầu.

Hiện tại, Envoy hỗ trợ ngắt mạch dựa trên các thông số sau:

  • Tối đa các kết nối cụm.
  • Yêu cầu đang chờ xử lý tối đa.
  • Yêu cầu tối đa.
  • Số lần thử lại tối đa.
  • Số lượng kết nối tối đa trên mỗi cụm.
  • ...

Nếu đạt đến bất kỳ ngưỡng nào, thì Envoy sẽ mở mạch. Việc mở mạch có thể được theo dõi bằng cách sử dụng các số liệu thống kê như hình dưới đây:

cluster.local_service.circuit_breakers.default.cx_open: 0
cluster.local_service.circuit_breakers.default.cx_pool_open: 0
cluster.local_service.circuit_breakers.default.rq_open: 0
cluster.local_service.circuit_breakers.default.rq_pending_open: 0
cluster.local_service.circuit_breakers.default.rq_retry_open: 0
cluster.local_service.circuit_breakers.high.cx_open: 0
cluster.local_service.circuit_breakers.high.cx_pool_open: 0
cluster.local_service.circuit_breakers.high.rq_open: 0
cluster.local_service.circuit_breakers.high.rq_pending_open: 0
cluster.local_service.circuit_breakers.high.rq_retry_open: 0

Stats, access logging & tracing

Như tôi đã đề cập trước đó, Envoy có một số thống kê để giúp bạn dễ hiểu. Nó tạo ra ba loại thống kê:

  • Upstream stats
  • Downstream stats
  • Server stats

Một số bộ lọc như Trình quản lý kết nối HTTP, hỗ trợ ghi nhật ký truy cập có thể mở rộng. Bạn có thể sử dụng sinks như file hoặc file nhật ký truy cập gRPC, để ghi lại nhật ký truy cập.

Envoy hỗ trợ theo dõi với các nhà cung cấp theo dõi gốc cũng như bên ngoài như Jaeger, LightStep, Zipkin, v.v. Theo dõi phân tán là rất quan trọng đối với kiến ​​trúc microservices để hiểu các luồng dịch vụ, độ trễ, tuần tự hóa, v.v.

Nhìn chung, các tính năng này cải thiện khả năng giám sát của ứng dụng / dịch vụ của bạn.

Security

Giống như nhiều proxy khác, Envoy có thể được sử dụng để cải thiện tính bảo mật tổng thể của ứng dụng. Nó hỗ trợ các bộ lọc khác nhau như sau:

Phần kết luận

Envoy proxy là một công cụ tuyệt vời và đang được áp dụng khá rộng rãi. Có rất nhiều dự án thương mại và mã nguồn mở được xây dựng trên Envoy. Có rất nhiều bộ lọc thú vị mà Envoy hỗ trợ mà bạn có thể muốn khám phá và sử dụng.

Một số người có thể tranh luận rằng chúng tôi có thể đạt được điều này bằng cách sử dụng một số công cụ hiện có hoặc thậm chí sử dụng các framework tích hợp sẵn, vậy tại sao lại sử dụng Envoy? Và đây là một lập luận công bằng. Tôi thấy công dụng lớn nhất của Envoy là trong các doanh nghiệp đang chạy các ứng dụng cũ. Bằng cách sử dụng Envoy như một sidecar hoặc proxy phía trước, bạn có thể dễ dàng cải thiện tính bảo mật, độ tin cậy và khả năng giám sát của hầu hết mọi ứng dụng (cũ / mới) mà không cần chạm vào mã ứng dụng.

MicroservicesEnvoy
Bài Viết Liên Quan:
Xây dựng Microservices bằng ASP.NET Core - Transaction Outbox với RabbitMQ
Trung Nguyen 16/05/2021
Xây dựng Microservices bằng ASP.NET Core - Transaction Outbox với RabbitMQ

Trong bài viết này, chúng ta sẽ tìm hiểu cách sử dụng outbox pattern để triển khai distributed transaction trong kiến trúc microservices.

Xây dựng Microservices bằng ASP.NET Core - Giao tiếp máy chủ thời gian thực với SignalR và RabbitMQ
Trung Nguyen 16/05/2021
Xây dựng Microservices bằng ASP.NET Core - Giao tiếp máy chủ thời gian thực với SignalR và RabbitMQ

Trong bài viết này, chúng tôi sẽ chỉ cho bạn cách bạn có thể kết hợp SignalR và RabbitMQ để xây dựng giao tiếp máy chủ-máy khách thời gian thực.

Xây dựng Microservices bằng ASP.NET Core - Thao tác với database bằng Marten
Trung Nguyen 16/05/2021
Xây dựng Microservices bằng ASP.NET Core - Thao tác với database bằng Marten

Trong bài viết này, chúng ta sẽ tìm hiểu về truy cập dữ liệu và cách lưu trữ dữ liệu một cách hiệu quả trong microservices sử dụng Marten và PostgreSQL.

Xây dựng Microservices bằng ASP.NET Core - Xây dựng API Gateway với Ocelot
Trung Nguyen 09/05/2021
Xây dựng Microservices bằng ASP.NET Core - Xây dựng API Gateway với Ocelot

Trong bài viết này, chúng ta sẽ tìm hiểu về API Gateway trong kiến ​​trúc microservices và cách xây dựng API Gateway bằng Ocelot.