Envoy 部署类型

目录

Envoy 网络拓扑及请求流程

首先描述Envoy如何适合请求的请求路径,然后描述内部请求从下游到达Envoy代理之后发生的内部事件

1. 术语

Envoy在其代码库和文档中使用以下术语:

  • Cluster/(集群):,集群是指 Envoy 连接到的逻辑上相同的一组上游主机。 Envoy 通过服务发现 来发现集群的成员。可以通过 主动健康检查来确定集群成员的健康状态。 Envoy 通过负载均衡策略 决定将请求路由到哪个集群成员
  • Downstream/(下游): 下游主机连接到Envoy, 发送请求并接收响应。可能是本地应用程序(在Sidecar模型中)或网络节点 ,在非Sidecar模型中,这是一个远程客户端, 对于Envoy(服务端),相当于client .
  • Endpoints(端点):实现逻辑服务的网络节点。它们在集群中被分组。集群中的端点位于Envoy代理的上游。
  • Filter(过滤器):连接或请求处理管道中的模块,用于提供某些请求处理时的连接或请求处理的管道模块。 类似与Unix系统中的管道符。
  • Filter chain: 类似 过滤器
  • Listeners/(监听器): Envoy模块,负责绑定到IP /端口, 可以被下游客户端连接。Envoy 暴露一个或者多个监听器给下游主机连接。
  • Upstream/(上游):上游主机接收来自 Envoy 的连接和请求,并返回响应。这可能是本地应用程序(在Sidecar模型中)或网络节点。在非Sidecar模型中,这对应于Envoy来说,相当于服务端(server)。

2. 网络拓扑

请求如何流经网络(包括Envoy)中的组件取决于网络的拓扑。Envoy可用于多种网络拓扑中。

  1. Envoy最初是作为Service Mesh Sidecar代理,从应用程序中排除了负载平衡,路由,可观察性,安全性和发现服务。在Service Mesh模型中,请求数据流经Envoy作为网络的网关。请求通过入口或出口侦听器到达Envoy:

    • Ingress listeners 从Service Mesh中的其他节点获取请求,并将其转发到本地应用程序。本地应用程序的响应通过Envoy流回到下游。

    • Egress listeners 从本地应用程序获取请求,并将其转发到网络中的其他节点。这些接收节点通常还将运行Envoy,并通过其入口侦听器接受请求。

  2. Service mesh外,Envoy还用于各种配置中。例如,它还可以充当内部负载平衡器:

  3. 作为网络边缘上的入口/出口(ingress/egress proxy)代理:

  4. 在实际应用中,会混合使用上面的方法, 其中Envoy在service mesh(服务网格)中, 在边缘网络上作为 内部负载均衡 使用。 请求路径可能会遍历多个Envoy

  5. Envoy可以在多层拓扑中进行配置以实现可伸缩性可靠性,其中请求首先通过边缘Envoy,然后再通过第二个Envoy层:

在上述所有的网络拓扑模型中,请求将从下游通过TCPUDPUnix域套接字到达特定的Envoy。 Envoy将通过TCPUDPUnix域套接字向上游转发请求。

下面重点介绍一个Envoy代理模式

3. 配置

Envoy是扩展性很强的平台。 这导致可能的请求路径组合很多,具体取决于:

  • L3 / 4层协议例如TCP,UDP,Unix域套接字
  • L7层协议,例如HTTP / 1,HTTP / 2,HTTP / 3,gRPC,Thrift,Dubbo,Kafka,Redis和各种数据库。
  • 传输socket套接字,例如纯文本,TLS,ALTS。
  • 连接路由,例如PROXY协议,原始目的地,动态转发。
  • 身份验证和授权
  • 断路器和异常值检测配置以及激活状态。
  • 许多其他配置,如用于网络,HTTP,侦听器,访问日志记录,运行状况检查,跟踪和统计信息扩展等配置

以下示例主要使用到如下配置相关

  1. 一次具有TLS协议的连接上游和下游的HTTP/2的请求
  2. HTTP连接管理器 作为唯一的网络过滤器
  3. 假定一个客户自定义过滤器和一个路由作为 HTTP过滤器
  4. 文件系统访问日志记录
  5. 具有静态端点的单个群集
  6. 统计接收器

为了简单起见,假定使用静态引导程序配置文件:example.yml

# 静态资源
static_resources:
  listeners:
  # 简单的监听器,绑定端口443
  - name: listener_https
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 443
    # A single listener filter exists for TLS inspector.
    listener_filters:
    - name: "envoy.filters.listener.tls_inspector"
      typed_config: {}
    # On the listener, there is a single filter chain that matches SNI for acme.com.
    filter_chains:
    - filter_chain_match:
        # This will match the SNI extracted by the TLS Inspector filter.
        server_names: ["acme.com"]
      # 下游 TLS 配置.
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            tls_certificates:
            - certificate_chain: { filename: "certs/servercert.pem" }
              private_key: { filename: "certs/serverkey.pem" }
      filters:
      # HTTP连接管理器
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          use_remote_address: true
          http2_protocol_options:
            max_concurrent_streams: 100
          # 基于系统文件的 日志
          access_log:
            - name: envoy.access_loggers.file
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
                path: "/var/log/envoy/access.log"
          # 路由表,匹配本地服务的 /foo请求
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["acme.com"]
              routes:
              - match:
                  path: "/foo"
                route:
                  cluster: some_service
          # CustomFilter and the HTTP router filter are the HTTP filter chain.
          http_filters:
            # - name: some.customer.filter
            - name: envoy.filters.http.router
  clusters:
  - name: some_service
    connect_timeout: 5s
    # 上游 TLS 认证.
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
    load_assignment:
      cluster_name: some_service
      # 静态端点分配(逻辑主机节点)
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 10.1.2.10
                port_value: 10002
        - endpoint:
            address:
              socket_address:
                address: 10.1.2.11
                port_value: 10002
    typed_extension_protocol_options:
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
        explicit_http_config:
          http2_protocol_options:
            max_concurrent_streams: 100
  - name: some_statsd_sink
    connect_timeout: 5s
    # The rest of the configuration for statsd sink cluster.
# statsd sink.
stats_sinks:
  - name: envoy.stat_sinks.statsd
    typed_config:
      "@type": type.googleapis.com/envoy.config.metrics.v3.StatsdSink
      tcp_cluster_name: some_statsd_sink

4. 更高层的架构

Envoy中的请求处理路径包括两个主要部分:

  1. Listener子系统,用于处理下游请求。它还负责管理下游请求生命周期以及到客户端的响应路径。下游的HTTP/2请求位于此模块中
  2. Cluster子系统,负责选择和配置与端点的上游连接。可以从此处了解群集和端点健康状况负载均衡连接池的地方。上游HTTP / 2请求处理位于此模块

这两个子系统与HTTP路由器过滤器桥接,该过滤器将HTTP请求从下游转发到上游。

Envoy还具有基于事件的线程模型。主线程负责服务器的生命周期,配置处理,状态等,并且一些工作线程负责处理请求。所有线程都围绕事件循环运行,当监听器接收到一个连接请求时,该连接将其生命周期绑定到一个单独的 worker 线程。worker 线程则负责执行监听、过滤和转发。每个工作线程都维护自己的与上游端点的TCP连接池。UDP过滤器状态为给定的工作线程共享,过滤器负责根据需要提供会话语义。

worker线程很少共享状态,并且很少并行运行。该线程模型可以扩展到核心数量非常多的CPU。

5. 请求流程

使用上面的示例配置简要概述了请求和响应的生命周期:

  1. workder线程上运行的Envoy Listener接受来自下游的一个TCP连接。
  2. 监听过滤器创建并运行,将会提供 SNI 和其他 TLS欲配置项。一旦完成后,侦听器将匹配网络过滤器链。每个侦听器可能具有多个过滤器链,这些过滤器链在目标IP CIDR范围,SNI,ALPN,源端口等的某种组合上匹配。传输套接字(在我们的示例中为TLS传输套接字)与此过滤器链相关联。
  3. 在网络读取时,TLS传输套接字将从TCP连接读取的数据流并进行解密,以进行进一步处理。
  4. 网络过滤器链已创建并运行。 HTTP最重要的过滤器是HTTP连接管理器,它是链中的最后一个网络过滤器。
  5. **HTTP connection manager **中的HTTP / 2编解码器 从TLS连接获取到多个独立的数据流进行解密。每个流只处理一个请求和响应。
  6. 对于每个HTTP流,会有一个HTTP过滤器创建和运行。该请求首先通过CustomFilter(可以读取和修改该请求),最重要的HTTP过滤器是位于HTTP过滤器尾部的路由器过滤器。在路由器过滤器上调用解码时,将选择路由并选择集群。数据中请求头将转发到该群集中的上游端点。路由器过滤器从群集管理器中为匹配的群集获取HTTP连接池,以执行此操作。
  7. 集群中具体的负载均衡 被执行用以查找一个端点。群集的断路器被检查,以确定是否允许新的数据流。如果端点的连接池为空或容量不足,一个新的连接(端点)被创建。
  8. 上游端点连接器HTTP/2的解码器将请求的流与通过单个TCP连接流向上游的任何其他流进行多路复用和帧化。
  9. 上游端点连接的TLS传输套接字加密这些字节并将它们写入上游连接的TCP套接字。
  10. 包含请求头,请求正文和尾部组成的 Request 在上游被代理,Response在下游被代理。响应以与请求相反的顺序通过HTTP过滤器,从路由器过滤器开始并通过CustomFilter,然后再发送到下游。
1. Listener TCP 接收

如图

ListenerManager负责获取侦听器的配置,并实例化绑定到其各自IP /端口的多个侦听器实例上。侦听器可能处于以下三种状态之一:

  • Warming: 侦听器正在等待配置依赖项(如外部配置,动态机密)。侦听器尚未准备好接受TCP连接。
  • Active: 侦听器已绑定到其IP /端口并接受TCP连接。
  • Draining: 监听已存在的 TCP链接持续一段时间, 不再接受新的TCP链接

每个工作线程为每个配置的侦听器维护自己的侦听器实例。每个侦听器都可以通过SO_REUSEPORT绑定到同一端口,或者共享一个绑定到该端口的套接字。当新的TCP连接到达时,内核将决定哪个工作线程将接受该连接,并且该工作线程的侦听器将调用其Server :: ConnectionHandlerImpl :: ActiveTcpListener :: onAccept()回调。

2. 侦听器过滤器链和网络过滤器链匹配

然后,工作线程的侦听器将创建并运行侦听器过滤器链。过滤器链是通过应用每个过滤器的过滤器工厂而创建的。工厂知道过滤器的配置,并为每个连接或流创建一个新的过滤器实例。

3.TLS传输套接字解密

Envoy通过TransportSocket扩展接口提供可插拔的运输插座。传输套接字遵循TCP连接的生命周期事件,并读写网络缓冲区。运输套接字必须实现的一些关键方法是:

virtual void onConnected() PURE;
virtual IoResult doRead(Buffer::Instance& buffer) PURE;
virtual IoResult doWrite(Buffer::Instance& buffer, bool end_stream) PURE;
virtual void closeSocket(Network::ConnectionEvent event) PURE;

当TCP连接上有可用数据时,Network :: ConnectionImpl :: onReadReady()会通过SslSocket :: doRead()调用TLS传输套接字。然后,传输套接字在TCP连接上执行TLS握手。握手完成后,SslSocket :: doRead()将解密的字节流提供给Network :: FilterManagerImpl的实例,该实例负责管理网络过滤器链。

需要特别注意的是,无论是TLS握手还是过滤器管道暂停,都无法阻止任何操作。由于Envoy是基于事件的,因此任何需要额外数据处理的情况都将导致事件的尽早完成,并使CPU产生另一个事件。当网络使更多数据可供读取时,读取事件将触发TLS握手的恢复。

4.网络过滤器链处理

与侦听器过滤器链一样,Envoy将通过Network :: FilterManagerImpl实例化其过滤器工厂中的一系列网络过滤器。该实例对于每个新连接都是新鲜的。网络过滤器(如传输套接字)跟随TCP生命周期事件,并随着数据从传输套接字可用而被调用。

网络过滤器是作为管道组成的,与每个连接一个的传输套接字不同。网络过滤器分为三种:

  • ReadFilter 实现onData(),当连接中有数据可用时(由于某些请求)而调用。
  • **WriteFilter **实现onWrite(),在即将将数据写入连接时(由于某些响应)而调用。
  • Filter 同时实现ReadFilter和WriteFilter。
5. HTTP/2 codec 解码

Envoy中的HTTP / 2编解码器基于nghttp2。

6. HTTP filter 链处理

对于每个HTTP流,HCM都按照上面为侦听器和网络过滤器链建立的模式实例化HTTP过滤器链。

HTTP过滤器接口共有三种:

  1. StreamDecoderFilter 带有用于请求处理的回调。
  2. StreamEncoderFilter 带有用于响应处理的回调。
  3. StreamFilter 同时实现 StreamDecoderFilter 和StreamEncoderFilter.

请求路径将如下所示:

响应路径如下所示:

调用路由器过滤器时,路由将最终确定。所选路由的配置将指向上游群集名称。然后,路由器过滤器向ClusterManager询问群集的HTTP连接池。

7. 负载均衡

负载平衡是一种在单个上游群集内的多个主机之间分配流量以有效利用可用资源的方法。有许多不同的方法可以完成此任务,因此Envoy提供了几种不同的负载平衡策略。从高层次上讲,我们可以将这些策略分为两类:全局负载平衡和分布式负载平衡。

分布式负载平衡是指 让Envoy自己基于了解上游主机的位置来确定应如何将负载分配到端点。

例子:

  • Active health checking: 通过对上游主机进行状况检查,Envoy可以调整优先级和位置的权重以解决不可用主机的问题。
  • Zone aware routing: 可使Envoy选择使用更近的端点,而不必在控制平面中显式配置优先级。
  • Load balancing algorithms:Envoy可以使用几种不同的算法来使用提供的权重来确定要选择的主机

每个集群都有一个负载均衡器,当新请求到达时,该负载均衡器会选择一个端点。Envoy支持多种负载平衡算法,例如加权轮循,磁悬浮列车,负荷最小,随机。

负载平衡器从静态引导程序配置,DNS,动态xDS(CDS和EDS发现服务)以及主动/被动运行状况检查的组合中获得有效分配。

选择端点后,将使用该端点的连接池来查找用于转发请求的连接。如果不存在与主机的连接,或者所有连接均处于其最大并发流限制,则除非连接集群最大连接的断路器跳闸,否则将建立新连接并将其放置在连接池中。如果配置并达到了连接的最大生存期流限制,则会在池中分配一个新的连接,并且耗尽受影响的HTTP / 2连接。

8. HTTP/2 codec 编码

所选连接的HTTP / 2编解器将请求流与单个TCP连接流向同一上游的任何其他流进行多路复用。这与HTTP / 2编解码器解码相反。

与下游HTTP / 2解码器一样,上游编解码器负责获取Envoy对HTTP的标准抽象,即在单个连接上与请求/响应标头/正文/尾部复用的多个流,并通过生成一系列HTTP / 2帧将其映射到HTTP / 2

9. TLS transport socket 加密

上游端点连接的TLS传输套接字对HTTP / 2编解码器输出中的字节进行加密,并将其写入用于上游连接的TCP套接字。与TLS传输套接字解密一样,示例中,群集配置了提供TLS传输安全性的传输套接字。上游和下游传输套接字扩展存在相同的接口。

10. 响应路径和HTTP生命周期

Reuest 在上游被代理,Response在下游被代理。响应以相反的顺序通过HTTP和网络过滤器。从请求。

解码器/编码器请求生命周期事件的各种回调将在HTTP过滤器中调用,例如当响应预告片被转发或请求主体被流式传输时。同样,当请求期间数据继续在两个方向上流动时,读/写网络过滤器也将调用其各自的回调。

请求有可能提前终止。这可能是由于(但不限于):

  1. 请求超时。
  2. 上游端点重启。
  3. HTTP筛选器流重置。
  4. 熔断
  5. 上游资源不可用,例如缺少路线的群集。
  6. 没有健康的端点
  7. DoS保护。
  8. HTTP协议违规。
  9. 来自HCM或HTTP过滤器的本地回复。例如。速率限制HTTP过滤器返回429响应。

如果发生这些情况中的任何一个,Envoy内部可能会发送生成的响应(如果尚未发送上游响应头),或者将流重置(如果响应头已经转发至下游)。

11.Post-request 处理

请求完成后,数据流将被销毁。还会发生以下情况:

  • 请求后统计信息将进行更新(例如,计时,活动请求,升级,运行状况检查)。但是,在请求处理期间,某些统计信息会更早更新。此时,统计信息尚未写入统计信息接收器,它们由主线程定期进行批处理和写入。在我们的示例中,这是一个statsd接收器。
  • 访问日志将写入访问日志接收器。示例中,这是一个文件访问日志。

给TA买糖
共{{data.count}}人
人已赞赏
经验教程

All I know about A/B Test (1) : 均值型指标与比值(率)型指标的计算区别

2021-3-17 16:52:00

经验教程

JVM之调优及常见场景分析

2021-3-17 17:37:00

⚠️
免责声明:根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。 本站为个人博客非盈利性站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途,网站会员捐赠是您喜欢本站而产生的赞助支持行为,仅为维持服务器的开支与维护,全凭自愿无任何强求。本站部份代码及教程来源于互联网,仅供网友学习交流,若您喜欢本文可附上原文链接随意转载。
无意侵害您的权益,请发送邮件至 momeis6@qq.com 或点击右侧 私信:momeis 反馈,我们将尽快处理。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索