自发布版本 1.15.0 起,Envoy 代理就开始支持 Postgres 信息解码用于统计目的了。该功能为网络中发生的 Postgres 事务提供聚合视图。有了聚合视图,Postgres 作业的种类、故障的数量和严重性瞬间一目了然。通过时间序列格式,请求组合出错率的变化也能清楚呈现出来。

值得留意的是,统计数据并不是存储在 Postgres 的服务器中,也不是在客户端,而是通过在网络层面嗅探应用与 Postgres 服务器的信息来往而获得的。这篇文章会带你摸清这个新功能的运作原理,文末为你附上一个小练习,向你演示如何运作。如果你是一名系统工程师,又想知道 Envoy 在解构网络中的 Postgres 流量发挥了什么作用,那么本文就对你很有帮助了。

利用 Envoy 观察 Postgres 网络流量

将 Envoy 部署为 Postgres 服务器中的负载均衡器时,所有数据库事务都会自然通过 Envoy,所以收集数据并不困难。

Postgres Network Traffic

此场景下,Envoy 作为负载均衡器对 Postgres 客户端没有什么架构方面的要求,不管该客户应用使用宏大的单体架构,还是分布式的 Postgres 数据库系统,都可轻松部署 Envoy。就架构而言,很重要的一点是, Envoy 是通往 Postgres 服务器集群的通道,故此每项事务都必须穿过 Envoy。如此一来,所需的 Envoy 数量相对有限,而且处于静态。通常情况下,都会有多于一个 Envoy 实例作为备用,以免单点故障的出现。引导 Prometheus 爬取 Envoy 的指标数据其实是很简单的,可以通过静态配置实现。

利用服务网格观察 Postgres 网络流量

一旦你的架构模式开始应用服务网格,每个应用都会连上可以拦截的应用网络流量 Envoy Sidecar。与前端代理架构相比,服务网格所需的 Envoy 数量更多,数据收集器必须向每个 Envoy 实例逐一收集信息。此外,应用(和相关的 Envoy Sidecar)只会短暂存在——它们只会应要求出现,而且可以随时关闭或移到另一个主机上运作。追踪 Envoy 实例和引导数据收集器到所有现行的 Envoy 实例变得愈来愈困难,不能像以前一样通过静态配置实现。服务网格架构采用控制平面,能够追踪应用、Sidecar 和它们的端点,并把这些信息供给数据收集器。但效果也是一样的。每条发生在网络中的 Postgres 信息都会经过分析,继而产生统计数据。

Network traffic system flow

Sidecar 架构是分布式系统中约定俗成的标准。虽然我们现阶段专注在它轻易收集数据这项优点上——因为这些 Envoy Sidecar「大队」可将应用和 Postgres 服务器间的流量来往通通拦截下来——但实际上,它还有多不胜数的好处。比如说,Envoy 可以检测每个 Postgres 实例故障,然后将请求路由到运作正常的服务器,并避开有问题的服务器。

运作原理

下文将描述如何启用简易的前端代理方案、生成半随机的 Postgres 流量,和用图表表示多种网络中可见的 Postgres 信息。配置代码段突显配置中最核心的部分。想获得整组档案,可以点此下载 https://github.com/tetratelabs/envoy-postgres-stats-example。 设置中的个别组件,例如 Envoy、Postgres 服务器、Postgres 客户端、Prometheus 和 Grafana,都是以容器形式创建,再以 Docker Compose 部署的

Envoy 配置

第一步是启动 Envoy 数据平面。Envoy 会在端口 1999 侦听,然后将所有请求转发到 Postgres 服务器。Postgres 的预设端口是 5432,当然可以配置 Envoy 用来侦听端口 5432,但为了强调 Envoy 一直积极转发数据包,所以把它调配到了不同的端口,而非预设的 Postgres 端口 5432。

通过下列代码,在端口 1999 创建侦听器,然后绑定到全部接口:

- name: postgres_listener
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 1999

接下来,Filter Chain 必须附加在监听器上。Filter Chain 描述监听端口上接收到数据包后所发生的事件。这个场景的 Filter Chain 就包含了 PostgresProxy 和 TcpProxy。PostgresProxy 过滤器负责检查 Postgres 服务器和客户端之间来往的信息。而链上的最后一个过滤器 TcpProxy,亦即所谓的终端过滤器,则负责提供流量给上游主机,也就是这个场景使用的 Postgres 服务器。

filter_chains:
- filters:
  - name: envoy.filters.network.postgres_proxy
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.network.postgres_proxy.v3alpha.PostgresProxy
      stat_prefix: egress_postgres
  - name: envoy.filters.network.tcp_proxy
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
      stat_prefix: postgres_tcp
      cluster: postgres_cluster

从 TcpProxy 过滤器的配置可以看出来,请求会被路由至 postgres_cluster,它的定义如下:

- name: postgres_cluster
  connect_timeout: 1s
  type: strict_dns
  load_assignment:
    cluster_name: postgres_cluster
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address:
              address: postgres
              port_value: 5432

集群包含了一系列标识为 postgres 的端点,而 Envoy 会用 DNS 来查找出该端点的 IP 地址。至于 DNS 的运作,可以有多种方法。例如是单独的 DNS 服务器,或是作为 Kubernetes 架构的一部分。在这个场景中,Docker Compose 网络提供了它的 DNS 解析。

收集数据

这个场景中, Prometheus 会负责收集统计数据。而 Envoy 能将统计数据直接以 Prometheus 格式导出。 所以你只需将 Prometheus 与 Envoy 对接。Prometheus 的 config 配置文件如下:

global:
  scrape_interval:  15s
scrape_configs:
  - job_name: 'envoy_stats'
    scrape_interval: 5s
    metrics_path: /stats/prometheus
    static_configs:
      - targets: ['proxy:8001']
        labels:
          group: 'services'

proxy 是 Envoy 的 DNS 名称,并由 Docker Compose 网络解析。Envoy 的管理接口是可见于 /stats/prometheus 路径下的端口 8001。

可观察性

Grafana 通过图表表示 Postgres 的种类。全部所需数据都会收集并存储在 Prometheus 上,而 Grafana 会定期读取该些数据。Grafana 需要两组配置。第一组是数据源:

datasources:
  - name: prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090

读者可以特别注意 type 和 url 两行。type 定义了数据的格式。 url 指出数据所在的端点。prometheus 是 DNS 名称,必须被解析为 IP 地址。在这个场景中,Docker Compose 网络会提供地址的解析。

Grafana 的第二组配置是仪表板规格(dashboard spec),基本上定义了哪些数据会显示出来,以及如何显示。经过手工搭建了这个仪表板后,你会注意到这个由 Grafana 创建的文件将是一个特别长的 json 档案。在这个场景中,我们会追踪 3 组 Postgres 信息:所有前端信息(由客户端产生并输出到服务器的信息)、服务器回馈的故障,及客户端发出的 SELECT 语句的数量。

"targets": [
  {
    "expr": "rate(envoy_postgres_egress_postgres_messages_frontend[1m])",
    "interval": "",
    "legendFormat": "frontend msgs",
    "refId": "A"
  },
  {
    "expr": "rate(envoy_postgres_egress_postgres_errors[1m])",
    "interval": "",
    "legendFormat": "errors",
    "refId": "B"
  },
  {
    "expr": "rate(envoy_postgres_egress_postgres_statements_select[1m])",
    "interval": "",
    "legendFormat": "select statements",
    "refId": "C"
  }
],

生成流量

此次演示的最后一步就是生成 Postgres 流量。我们可以通过重复运行几组代码,生成不同的 Postgres 事务。这些代码位于代码目录(script directory)中。它们会循环地运行,每一回它都会随机生成一个数字,数值代表事务序列重复的次数。如此一来,便带点半随机性。

启用系统

此次演示中的所有个别组件都是以容器形式启用,再以 Docker Compose 将它们组合。点击下列链接可以下载 docker-compose 文件 https://github.com/tetratelabs/envoy-postgres-stats-example。 这个文件已基本列出了所有服务,还有基本的网络配置跟原始数据。
启用整个系统,只需在 envoy-postgres-stats-example 目录中输入

docker-compose up

。 这个场景中所涉及的组件也会以容器形式启用。它们通过环回接口通信,也如上所述,组件是按 docker-compose 文件所命名的。下列是以 docker-compose 建立的系统的概念图表。

Docker compose logical framework

练习

开始练习之前,先点击以下链接下载全部文件: https://github.com/tetratelabs/envoy-postgres-stats-example。 假设 Docker 已经在系统中安装成功,启用整个系统只需输入:

docker-compose up

Grafana 的用户接口可见于端口 3000。将你的网页浏览器对接到 docker-compose 调用的端口上。如果系统在本地运行,请输入 ‘http://localhost:3000’。如果在云端上运行,请注明 IP 地址(确保防火墙规则允许流量通往 TCP 端口 3000)。Grafana 的预设账号密码是 ‘admin/admin’.

登录 Grafana 后,选择 PostgreSQL 仪表板(dashboard)。下列的仪表板例子包含 3 个查询:

  • 前端信息的数量(由产生代码的流量所产生的信息)
  • Postgres 服务器故障回复的次数
  • SELECT 语句的数量

Grafana select PostgreSQL dashboard