- Authors: Zhongming Hua, Jun Liu, Guoqing Cong
除了应用启动和服务注册流程以外,其他两大流程都是在直连模式下:服务发现以及服务调用流程。其中应用下线不单独列出来主要是优雅下线时候的处理
以下是应用启动的大致流程(省略了 spring 容器启动等与 mesh 无关的流程):
- ApplicationDeployer #initialize():注册 ShutdownHook ->开启配置中心 -> 加载应用配置 -> 初始化 ModuleDeployer -> 开启元数据中心
- ApplicationDeployer #doStart():ModuleDeployer #start()
- ModuleDeployer #start():ModuleDeployer #initialize() -> 暴露服务 -> 引用服务
- ApplicationDeployer #onModuleStarted():暴露 MetadataService 服务-> 上报元数据信息-> 注册应用实例地址
以下是服务暴露的流程:
- 暴露 injvm 协议的服务
- 暴露 Triple 协议的服务
- 发起服务注册:registry 协议
- 暴露 MetadataService 服务
- 发起服务注册:service-discovery-registry 协议
在应用启动中的服务引用过程包含了服务发现,以下是直连模式下的引用服务流程:
- TripleProtocol #refer
- 创建 TripleInvoker 实例
- 与对端建连(ConnectionManager #connect)
- 将 TripleInvoker 实例包装成 ClusterInvoker,附加集群相关处理能力(Cluster #join)
- 新增 Cluster Interceptor(主要是附加一些容错策略、结果处理策略)
- 推送 consumer 端元数据信息
- 创建代理
- InvokerInvocationHandler #invoke()
- filter chain 处理:ConsumerContextFilter 、FutureFilter 、MonitorFilter 、RouterSnapshotFilter
- 执行 router chain(直连模式不需要路由)
- 执行负载均衡策略(由于是直连一个 sidecar,所以负载均衡策略没有效果):(AbstractClusterInvoker #select)
- TripleInvoker #doInvoke()
- DefaultFuture2 #received
- Dubbo 应用进程与 Sidecar 生命周期对齐,正常启动后,让 Sidecar 感知到该 Endpoint 是健康的。
- 初步方案:Dubbo 应用与 Sidecar 建连,并且发送 POST /healthcheck/ok。这里具体是往哪个端口和地址发送请求?
- 运行态:通过健康检查来保活
- Dubbo 应用优雅下线时,需要能够让 Sidecar 感知到该 Endpoint 下线了。(应用所在的 Container 原地热升级、应用优雅下线等场景)
- 初步方案:发送 POST /healthcheck/fail
- 在启动过程中,除了生命周期对齐以外,其他主要需要做缩减的动作,对 mesh 主流程影响不大。
运行态,通过 envoy 的健康检查来保证 Dubbo 应用是否正常。目前 Triple 协议基于 gRPC 的 Health 接口实现健康检查。需要在 Consumer 端侧的 Envoy 配置 EnvoyFilter 支持 HTTP 健康检查 Filter,对其上游集群 provider 做主动健康检查(GRPC):
- 参考 EnvoyFilter 配置
- https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/health_check/v3/health_check.proto#envoy-v3-api-msg-extensions-filters-http-health-check-v3-healthcheck
- https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/health_check.proto
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
本次从 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)实例,后续则以增量的方式推送。
Isito 官网给出的 BookInfo demo 中,微服务之间的调用方式,可以看到使用 K8S 的服务名作为主机名即可。
- 解决 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
- 第二阶段工作(路由等流量治理接入)
负载均衡策略的对接:交由 Sidecar 来做:
- envoy 支持的负载均衡策略:https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/load_balancers
- 服务路由:路由规则的存储,将 Kubernetes API Server 作为 Config Store,注册 Kubernetes CRD 资源来作为路由规则的存储。通过 RDS 下发路由规则到 Sidecar,由 Sidecar 来做服务路由。
- 涉及到现有的路由规则如何迁移到 istio 中路由规则管控的问题。
目前 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
]
在进行服务调用时:
- :authority 会被识别成一个 virtual host,需要适配成如 demo.default.svc.cluster.local:50051 标准格式。
- 需要支持 envoy header:https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#config-http-conn-man-headers-custom-request-headers
- 需要支持 envoy router 的 header:调用时支持 Envoy router header:https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/router_filter#id7 *对比 google grpc 和 envoy grpc 的差异,适配 header 内容:https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/grpc_service.proto.html#envoy-api-field-core-grpcservice-envoy-grpc
- 探索envoy和istio支持的服务治理的内容,比如开发者需要实现重试,API处要传什么值。
- 解决目前readinessProbe不适用mesh模式的问题
- 精简SDK。
- 优雅下线的时候已经有相关的逻辑。
- 接口级别的服务注册对接 sidecar
- 多实例应用。
- 老系统迁移到 mesh 的方案
- 目前 mesh 模式的 providerPort 没有考虑多端口情况
- 目前 Dubbo 的 ReadinessProbe 不适用 mesh 场景,需修正 ReadinessProbe 的计算逻辑