Envoy 快速入門

微服務的服務間通訊與服務治理 一文中,咱們提到扇貝目前的 Service Mesh 架構是基於 Envoy 來作的。nginx

本文的主角就是這個新秀 Envoygit

拋棄了 Nginx, 選擇了 Envoy

其實以前扇貝是大量使用 Nginx 的,不管是對於其部署,配置仍是調優都更爲有經驗。若是能夠,咱們仍是傾向於選用 Nginx做爲 Service Mesh 的核心方案的。github

可是碰到幾個繞不開的問題:json

  1. Nginx的反向代理不支持 http2/grpc (好像今年3月份剛支持)
  2. 不像 Envoy 幾乎全部的網絡配置均可以利用 xDS API 來實現動態變動,Nginx缺少有效的配置熱變動機制(除非深刻開發或者不斷地reload)。
  3. Nginx的不少微服務功能都是要買 Nginx Plus 纔有的

Envoy 做爲一個主打 Service Mesh 方案的 proxy,其設計到處考慮 Service Mesh,在通過必定地瞭解後,咱們果斷入了 Envoy 的坑。api

Envoy 是什麼

咱們援引一段官網的描述:網絡

Envoy is an L7 proxy and communication bus designed for large modern service oriented architectures. The project was born out of the belief that: "The network should be transparent to applications. When network and application problems do occur it should be easy to determine the source of the problem."架構

Envoy 的核心功能/賣點

  • 非侵入的架構:Envoy 是和應用服務並行運行的,透明地代理應用服務發出/接收的流量。應用服務只須要和 Envoy 通訊,無需知道其餘微服務應用在哪裏。
  • 基於 Modern C++11實現,性能優異。
  • L3/L4 過濾器架構:Envoy 的核心是一個 L3/L4 代理,而後經過插件式的過濾器(network filters)鏈條來執行 TCP/UDP 的相關任務,例如 TCP 轉發,TLS 認證等工做。
  • HTTP L7 過濾器架構:HTTP在現代應用體系裏是地位很是特殊的應用層協議,因此 Envoy 內置了一個很是核心的過濾器: http_connection_managerhttp_connection_manager 自己是如此特殊和複雜,支持豐富的配置,以及自己也是過濾器架構,能夠經過一系列 http 過濾器(http filters)來實現 http協議層面的任務,例如:http路由,重定向,CORS支持等等。
  • HTTP/2 做爲第一公民:Envoy 支持 HTTP/1.1 和 HTTP/2,推薦使用 HTTP/2。
  • gRPC 支持:由於對 HTTP/2 的良好支持,Envoy 能夠方便的支持 gRPC,特別是在負載和代理上。
  • 服務發現: 支持包括 DNS, EDS 在內的多種服務發現方案。
  • 健康檢查:內置健康檢查子系統。
  • 高級的負載均衡方案:除了通常的負載均衡,Envoy 還支持基於 rate limit 服務的多種高級負載均衡方案,包括: automatic retries, circuit breaking, global rate limiting
  • Tracing:方便集成 Open Tracing 系統,追蹤請求
  • 統計與監控:內置 stats 模塊,方便集成諸如 prometheus/statsd 等監控方案
  • 動態配置:經過「動態配置API」實現配置的動態調整,而無需重啓 Envoy 服務的。

核心術語解釋

Hostapp

這裏的 Host,能夠理解爲由 IP, Port 惟一肯定的服務實例負載均衡

Downstreamdom

發送請求給 Envoy 的 Host 是 Downstream(下游),例如gRPC的 client

Upstream

接收 Enovy 發出的請求的 Host 是Upstream(上游),例如 gRPC的 server

Listener

Envoy 監聽的一個地址,例如 ip:port, unix socket 等等

Cluster

一組功能一致的上游 Host,稱爲一個cluster。相似 k8sService, nginxupstream

Http Route Table

HTTP 的路由規則,例如請求的域名,Path符合什麼規則,轉發給哪一個 Cluster。

配置(v2)

Envoy 的配置接口以 proto3(Protocol Buffers v3)的格式定義,完整的定義見 data plane API repository

具體的配置文件編寫支持:yaml, json, pb, pb_text 四種格式。出於可讀性的考慮,咱們下面都以 yaml 格式爲例。

先看一個簡單的例子:

徹底靜態的配置

admin:
 access_log_path: /tmp/admin_access.log
 address:
 socket_address: { address: 127.0.0.1, port_value: 9901 }

static_resources:
 listeners:
 - name: listener_0
 address:
 socket_address: { address: 127.0.0.1, port_value: 10000 }
 filter_chains:
 - filters:
 - name: envoy.http_connection_manager
 config:
 stat_prefix: ingress_http
 route_config:
 name: local_route
 virtual_hosts:
 - name: local_service
 domains: ["example.com"]
 routes:
 - match: { prefix: "/" }
 route: { cluster: some_service }
 http_filters:
 - name: envoy.router
 clusters:
 - name: some_service
 connect_timeout: 0.25s
 type: STATIC
 lb_policy: ROUND_ROBIN
 hosts: [{ socket_address: { address: 127.0.0.2, port_value: 1234 }}]
複製代碼

在上面的例子中,咱們配置了一個 envoy實例,監聽 127.0.0.1:10000,支持 http 協議訪問,http 訪問域名爲:example.com。接收到的全部http流量,轉發給 127.0.0.2:1234 的服務。

很快你們發現一個問題,就是 some_service 這個cluster中 hosts 是固定的(127.0.0.2:1234),可是頗有可能對應的 host是會變的。例如:增長了新的 host(水平擴展), k8s環境中,發了新代碼(pod變了),等等。這時候,總不至於咱們須要不停的該 cluster 中的 hosts吧?放心,若是是這樣,咱們就不會用 Envoy 了。

經過EDS動態配置cluster hosts

接下來咱們會碰到第一個動態配置的例子,就是動態配置 cluster 的 hosts。

咱們先假設有這麼一個服務A,地址是:127.0.0.3:5678,會返回 proto3 編碼的下屬響應

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
 cluster_name: some_service
 endpoints:
 - lb_endpoints:
 - endpoint:
 address:
 socket_address:
 address: 127.0.0.2
 port_value: 1234
複製代碼

那麼咱們把 envoy 的配置調整爲:

admin:
 access_log_path: /tmp/admin_access.log
 address:
 socket_address: { address: 127.0.0.1, port_value: 9901 }

static_resources:
 listeners:
 - name: listener_0
 address:
 socket_address: { address: 127.0.0.1, port_value: 10000 }
 filter_chains:
 - filters:
 - name: envoy.http_connection_manager
 config:
 stat_prefix: ingress_http
 route_config:
 name: local_route
 virtual_hosts:
 - name: local_service
 domains: ["example.com"]
 routes:
 - match: { prefix: "/" }
 route: { cluster: some_service }
 http_filters:
 - name: envoy.router
 clusters:
 - name: some_service
 connect_timeout: 0.25s
 lb_policy: ROUND_ROBIN
 type: EDS
 eds_cluster_config:
 eds_config:
 api_config_source:
 api_type: GRPC
 cluster_names: [xds_cluster]
 - name: xds_cluster
 connect_timeout: 0.25s
 type: STATIC
 lb_policy: ROUND_ROBIN
 http2_protocol_options: {}
 hosts: [{ socket_address: { address: 127.0.0.3, port_value: 5678 }}]
複製代碼

就能夠實現 some_service 這個 cluster 的 hosts 的動態配置了。新的配置中,some_service 這個 cluster 的 hosts 是 EDS(Endpoint Discovery Service) 的返回值決定的,就是說 EDS 會返回 some_service 這個 cluster 的 hosts 的列表。新配置中,EDS 服務的地址定義在 xds_cluster 這個 cluster中,地址正是咱們開頭假設的服務A的地址。

其實 Envoy 的 listener, cluster, http route 等都是能夠動態配置的,方法和 EDS同樣,經過 LDS, CDS, RDS 來實現配置,而它們統稱爲 xDS。一個完整的動態配置的例子以下:

基於xDS的動態配置

admin:
 access_log_path: /tmp/admin_access.log
 address:
 socket_address: { address: 127.0.0.1, port_value: 9901 }

dynamic_resources:
 lds_config:
 api_config_source:
 api_type: GRPC
 cluster_names: [xds_cluster]
 cds_config:
 api_config_source:
 api_type: GRPC
 cluster_names: [xds_cluster]

static_resources:
 clusters:
 - name: xds_cluster
 connect_timeout: 0.25s
 type: STATIC
 lb_policy: ROUND_ROBIN
 http2_protocol_options: {}
 hosts: [{ socket_address: { address: 127.0.0.3, port_value: 5678 }}]
複製代碼

這裏咱們假設 127.0.0.3:5678 提供完整的 xDS

LDS:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.Listener
 name: listener_0
 address:
 socket_address:
 address: 127.0.0.1
 port_value: 10000
 filter_chains:
 - filters:
 - name: envoy.http_connection_manager
 config:
 stat_prefix: ingress_http
 codec_type: AUTO
 rds:
 route_config_name: local_route
 config_source:
 api_config_source:
 api_type: GRPC
 cluster_names: [xds_cluster]
 http_filters:
 - name: envoy.router
複製代碼

RDS:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.RouteConfiguration
 name: local_route
 virtual_hosts:
 - name: local_service
 domains: ["*"]
 routes:
 - match: { prefix: "/" }
 route: { cluster: some_service }
複製代碼

CDS:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.Cluster
 name: some_service
 connect_timeout: 0.25s
 lb_policy: ROUND_ROBIN
 type: EDS
 eds_cluster_config:
 eds_config:
 api_config_source:
 api_type: GRPC
 cluster_names: [xds_cluster]
複製代碼

EDS:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
 cluster_name: some_service
 endpoints:
 - lb_endpoints:
 - endpoint:
 address:
 socket_address:
 address: 127.0.0.2
 port_value: 1234
複製代碼

結束語

做爲一篇 Envoy 的快速入門文,咱們大概地瞭解了 Envoy的核心功能,術語,以及配置。關於更加深刻的定製配置,能夠進一步翻閱 Envoy 的官方文檔。

在扇貝,Envoy 做爲 Service Mesh 的核心組件,承載了微服務間的全部直接調用流量。

咱們的不一樣的微服務對應一個個 Cluster,經過 authority 來設置 Route Table。

利用 Envoy 的 stats 數據作服務調用的性能監控,Envoy 的 access log 作流量日誌收集,rate limit 作服務保護。

相關文章
相關標籤/搜索