3.1 Dubbo Thin SDK (draft)

  • Authors: Zhongming Hua, Jun Liu, Guoqing Cong

Objective

Background

Dubbo 基本工作原理介绍

除了应用启动和服务注册流程以外,其他两大流程都是在直连模式下:服务发现以及服务调用流程。其中应用下线不单独列出来主要是优雅下线时候的处理

应用启动

以下是应用启动的大致流程(省略了 spring 容器启动等与 mesh 无关的流程):

  1. ApplicationDeployer #initialize():注册 ShutdownHook ->开启配置中心 -> 加载应用配置 -> 初始化 ModuleDeployer -> 开启元数据中心
  2. ApplicationDeployer #doStart():ModuleDeployer #start()
  3. ModuleDeployer #start():ModuleDeployer #initialize() -> 暴露服务 -> 引用服务
  4. ApplicationDeployer #onModuleStarted():暴露 MetadataService 服务-> 上报元数据信息-> 注册应用实例地址

服务暴露

以下是服务暴露的流程:

  1. 暴露 injvm 协议的服务
  2. 暴露 Triple 协议的服务
  3. 发起服务注册:registry 协议
  4. 暴露 MetadataService 服务
  5. 发起服务注册:service-discovery-registry 协议

服务发现

在应用启动中的服务引用过程包含了服务发现,以下是直连模式下的引用服务流程:

  1. TripleProtocol #refer
  2. 创建 TripleInvoker 实例
  3. 与对端建连(ConnectionManager #connect)
  4. 将 TripleInvoker 实例包装成 ClusterInvoker,附加集群相关处理能力(Cluster #join)
  5. 新增 Cluster Interceptor(主要是附加一些容错策略、结果处理策略)
  6. 推送 consumer 端元数据信息
  7. 创建代理

服务调用

  1. InvokerInvocationHandler #invoke()
  2. filter chain 处理:ConsumerContextFilter 、FutureFilter 、MonitorFilter 、RouterSnapshotFilter
  3. 执行 router chain(直连模式不需要路由)
  4. 执行负载均衡策略(由于是直连一个 sidecar,所以负载均衡策略没有效果):(AbstractClusterInvoker #select)
  5. TripleInvoker #doInvoke()
  6. DefaultFuture2 #received

Related Proposals

Proxyless Mesh

Proposal

ThinSDK 改造方案

应用启动

  1. Dubbo 应用进程与 Sidecar 生命周期对齐,正常启动后,让 Sidecar 感知到该 Endpoint 是健康的。
  • 初步方案:Dubbo 应用与 Sidecar 建连,并且发送 POST /healthcheck/ok。这里具体是往哪个端口和地址发送请求?
  • 运行态:通过健康检查来保活
  1. Dubbo 应用优雅下线时,需要能够让 Sidecar 感知到该 Endpoint 下线了。(应用所在的 Container 原地热升级、应用优雅下线等场景)
  • 初步方案:发送 POST /healthcheck/fail
  1. 在启动过程中,除了生命周期对齐以外,其他主要需要做缩减的动作,对 mesh 主流程影响不大。

健康检查

运行态,通过 envoy 的健康检查来保证 Dubbo 应用是否正常。目前 Triple 协议基于 gRPC 的 Health 接口实现健康检查。需要在 Consumer 端侧的 Envoy 配置 EnvoyFilter 支持 HTTP 健康检查 Filter,对其上游集群 provider 做主动健康检查(GRPC):

Kubernetes 相关实例状态检查

Pod 的生命周期与服务调度息息相关,通过对 Kubernetes 官方探针的实现,能够使 Dubbo 乃至整个应用的生命周期与 Pod 的生命周期对齐。

存活检测

对于 livenessProbe 存活检测,由于 Dubbo 框架本身无法获取到应用的存活状态,因此本接口无默认实现,且默认返回成功。开发者可以根据 SPI 定义对此 SPI 接口进行拓展,从应用层次对是否存活进行判断。

就绪检测

对于 readinessProbe 就绪检测,目前 Dubbo 默认提供了两个检测维度,一是对 Dubbo 服务自身是否启停做判断,另外是对所有服务是否存在已注册接口,如果所有服务均已从注册中心下线(可以通过 QOS 运维进行操作)将返回未就绪的状态。(readinessProbe 目前 dubbo 实现方式不适用于 mesh,mesh 模式不配置注册中心,dubbo 的 readinessProbe 会返回 false)

启动检测

对于 startupProbe 启动检测,目前Dubbo 默认提供了一个检测维度,即是在所有启动流程(接口暴露、注册中心写入等)均结束后返回已就绪状态。

使用方法:

参考配置(具体可以参考 dubbo-samples-mesh-provider 的配置文件)

livenessProbe:
  httpGet:
    path: /live
    port: 22222
  initialDelaySeconds: 5
  periodSeconds: 5
readinessProbe:
  httpGet:
    path: /ready
    port: 22222
  initialDelaySeconds: 5
  periodSeconds: 5
startupProbe:
  httpGet:
    path: /startup
    port: 22222
  failureThreshold: 30
  periodSeconds: 10
Envoy 主动主动健康检车

本次从 consumer 侧的 Envoy ,对其上游集群 provider 做主动健康检查(GRPC)。

配置EnvoyFilter如下:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: cluster
  namespace: dubbo-demo
spec:
  workloadSelector:
    labels:
      app: dubbo-samples-mesh-consumer
  configPatches:
    - applyTo: CLUSTER
      match:
        cluster:
          name: outbound|50052||dubbo-samples-mesh-provider.dubbo-demo.svc.cluster.local
      patch:
        operation: MERGE
        value:
          health_checks:
            - timeout: 5s
              interval: 5s
              initial_jitter: 1s
              interval_jitter: 1s
              interval_jitter_percent: 50
              unhealthy_threshold: 1
              healthy_threshold: 1
              reuse_connection: true
              no_traffic_interval: 2s
              no_traffic_healthy_interval: 4s
              unhealthy_interval: 5s
              unhealthy_edge_interval: 10s
              healthy_edge_interval: 10s
              tls_options:
                alpn_protocols:
                  - http1.1
                  - h2
              transport_socket_match_criteria:
                useMTLS: true
              grpc_health_check:
                authority: dubbo-samples-mesh-provider.dubbo-demo.svc.cluster.local

Envoy健康检查的配置说明( 详见Envoy 健康检查文档):

{
  "timeout": "{...}",超时时间
  "interval": "{...}",检测间隔
  "initial_jitter": "{...}",初始抖动
  "interval_jitter": "{...}",间隔抖动
  "interval_jitter_percent": "...",间隔抖动比例
  "unhealthy_threshold": "{...}",不健康阈值
  "healthy_threshold": "{...}",健康阈值
  "reuse_connection": "{...}",重用连接
  "http_health_check": "{...}",http类型健康检测
  "tcp_health_check": "{...}",tcp类型健康检测
  "grpc_health_check": "{...}",grpc类型健康检测
  "custom_health_check": "{...}",自定义健康检测
  "no_traffic_interval": "{...}",没有流量时的间隔
  "no_traffic_healthy_interval": "{...}",没有流量健康后的间隔
  "unhealthy_interval": "{...}",不健康的间隔
  "unhealthy_edge_interval": "{...}",不健康边缘间隔
  "healthy_edge_interval": "{...}",健康边缘间隔
  "event_log_path": "...",日志路径
  "always_log_health_check_failures": "...",失败总是记录日志
  "tls_options": "{...}",选项
  "transport_socket_match_criteria": "{...}"trasport_socket匹配条件
}

服务注册

istio 中所支持的注册中心中成熟度最高的是 Kubernetes,第一阶段推荐使用 Kubernetes Registry,Kubernetes 调度的服务将自动被 Istio 识别所以第一阶段暂不需要做额外操作。

将注册中心配置为 N/A,不需要额外的注册中心。

dubbo.registry.address=N/A

服务发现

服务发现需要解决的问题是如何触发数据面的服务发现。目前 Pilot 的操作是在集群第一次启动时从 Kubernetes 中发现全量的 Service、Workload 数据,并将这些服务发现数据通过 xDS 下发给 Envoy(Pilot-Agent)实例,后续则以增量的方式推送。

Think Dubbo

服务调用

Isito 官网给出的 BookInfo demo 中,微服务之间的调用方式,可以看到使用 K8S 的服务名作为主机名即可。 image

  1. 解决 Dubbo SDK 的请求如何代理给 sidecar?
  • sdk 的 RPC 请求转换为类似如下格式的请求动作:http://demo.default.svc.cluster.local:50051. 其中,demo 为当前接口对应的 app-name,default 为当前的 namespace。

  • 避免 dubbo 之前的 Cluster 选址等问题

    目前对 consumer 端增加 meshEnable 和 providerPort 配置,跑通基础的 mesh 模式,代码dubbo mesh demo

  1. 第二阶段工作(路由等流量治理接入)

负载均衡策略的对接:交由 Sidecar 来做:

目前 triple 协议默认的 header:

[
:scheme: http,
:method: POST,
:path: /org.apache.dubbo.demo.GreeterService/sayHello,
:authority: 127.0.0.1:50051,
grpc-accept-encoding: gzip,
te: trailers,
content-type: application/grpc+proto,
tri-consumer-appname: dubbo-demo-triple-api-consumer
]

在进行服务调用时:

下一步工作计划

  • 探索envoy和istio支持的服务治理的内容,比如开发者需要实现重试,API处要传什么值。
  • 解决目前readinessProbe不适用mesh模式的问题
  • 精简SDK。

其他事项:

  • 优雅下线的时候已经有相关的逻辑。
  • 接口级别的服务注册对接 sidecar
  • 多实例应用。
  • 老系统迁移到 mesh 的方案
  • 目前 mesh 模式的 providerPort 没有考虑多端口情况
  • 目前 Dubbo 的 ReadinessProbe 不适用 mesh 场景,需修正 ReadinessProbe 的计算逻辑