xDS REST and gRPC protocol

原文地址:xDS REST and gRPC protocol.

envoy可通过文件系统、一个或多个管理服务器来发现各种动态资源.这些服务发现和他们相对应的API统称为xDS.通过定阅方式获取资源,如监控指定的文件路径、gRPC流或轮询REST-JSON URL.后两种使用DiscoveryRequest来发送请求消息.所有的资源包含在DiscoveryResponse响应消息中.下面,我们将讨论每种订阅类型.

文件订阅

动态配置最简单的方法是将配置写入一个文件,文件路径通过ConfigSource配置.Envoy会使用inotify(Mac OS X上用kqueue)去监控文件的变化,文件更新时用DiscoveryResponse进行解析.DiscoveryResponse支持的格式包括: 二进制protobuf,JSON,YAML和协议文本.

文件订阅支持统计数据和日志,不支持ACK/NACK的更新方式.如果配置更新被拒绝,xDS API将使用最近一次的有效配置.

gRPC流订阅

单资源类型发现

gRPC ApiConfigSource对于xDS API都可单独配置,指向对应的上游管理服务器的集群地址.每种xDS资源类型都会各自启动一个双向的gRPC流,来对应可能会向不同的管理服务器发起.API的交付方式是最终一致性的.明确控制的顺序可看下面的ADS.

URL类型

每个xDS API都与特定的资源类型相关.xDS API和资源类型之间是1:1的.对应关系如下:

URL类型的概念如下所示,其采用type.googleapis.com/<resource type>形式,例如: CDS对应于type.googleapis.com/envoy.api.v2.Cluster.在 Envoy 的请求和管理服务器的响应中,都包括了资源类型 URL.

ACK/NACK和版本控制

每个Enovy以流DiscoveryRequest开始,包括指定订阅资源列表,订阅资源对应的URL类型,结点标志和空version_info.EDS的请求例子如下:

version_info:
node: { id: envoy }
resource_names:
- foo
- bar
type_url: type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
response_nonce:

管理服务器会立即或者等待请求可用时以DiscoveryResponse作为应答.应答例子如下:

version_info: X
resources:
- foo ClusterLoadAssignment proto encoding
- bar ClusterLoadAssignment proto encoding
type_url: type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
nonce: A

处理完DiscoveryResponse应答之后,将通过流发送一个新请求,请求包括应用成功的最后一个版本号和管理服务器提供的nonce.如果这次更新成功应用,version_info将被设置为X,时序图如下:

在此序列图及后续中,将统一使用以下缩写格式:

  • DiscoveryRequest: (V=version_info,R=version_info,N=response_nonce,T=type_url)
  • DiscoveryResponse: (v=version_info,R=resources,N=nonce,T=type_url)

版本为Envoy和管理服务器提供了共享当前应用配置的概念以及通过ACK/NACK来进行配置更新.如果Envoy拒绝配置更新X,它将返回error_detail和上一个版本号,在当前情况下为空的初始版本号.error_detail包含了更多的错误详细信息:

后续,API可能会在版本Y上更新成功:

每个流都有自己的版本,跨资源类型没有共享版本.当不使用ADS时,甚至每个资源类型都可能有不同的版本,因为Envoy API允许不同的EDS/RDS资源配置对应不同的ConfigSource.

何时发送更新

管理服务器仅在DiscoveryResponse更改资源时才向Envoy客户端发送更新.Envoy会根据接受和拒绝的情况,会立即回复包含ACK/NACK的请求.如果管理服务器每次发送相同的资源集而不是等到有改变时再发送,这会导致Envoy和管理服务器的效率大打折扣.

对于同个流,新的DiscoveryRequest将取代之前具有相同的资源类型请求.这意味着管理服务器只响应最新DiscoveryRequest的请求,在相同的资源请求下.

资源提示

DiscoveryRequestresource_names作为资源提示出现.一些资源类型,例如:clusterlistener将使用一个空的resource_names列表.因为Envoy需要获取管理服务器对应于节点标识的所有Clusters(CDS)和Listeners(LDS).对于其它的资源类型,例如:RouteConfigurations(RDS)和ClusterLoadAssignments(EDS),遵循早期的CDS/LDS更新,Envoy能够明确地列举这些资源.

LDS和CDS资源信息始终为空,并且期望管理服务器将在每个响应中提供LDS / CDS资源的完整状态.缺席的ListenerCluster将被删除.resource_names只是一个提示.

对于EDS/RDS,管理服务器不需要提供每个资源的请求,也可能提供额外的未请求资源.Envoy会忽略多余的资源信息.当一个RDS或EDS的更新缺少请求资源时,Envoy将会保留对应资源最后的有效值.管理服务器可能能够从node标识中推断出所有所需的EDS/ RDS资源DiscoveryRequest,在这种情况下,提示信息可能会被丢弃.从特定角度看,一个空的EDS/RDS DiscoveryResponse响应说明Envoy是一个空的资源.

ListenerCluster被删除,Envoy上相应EDS和RDS资源也会被删除.为了让Envoy知道或跟踪EDS资源,必须存在应用过的Cluster定义(例如:通过CDS获得).RDS和Listeners之间也存在相似的关系(通过LDS获得).

对于EDS/RDS,Envoy可以为每个给定类型的资源生成不同的流(如每个ConfigSource都有自己的上游管理服务集群)或当指定资源类型的请求发送到同一个管理服务器的时候,允许将多个资源请求组合在一起发送.虽然可以单个实现,但管理服务器应该能够为resource_names每个请求中的给定资源类型处理一个或多个.下面的两个时序图都可用于获取两个EDS资源{foo, bar}:

资源更新

如上所述,Envoy可能会更新resource_names列表在每个DiscoveryRequest,其中DiscoveryResponse是用来ACK/NACK管理服务器的特定的.此外,Envoy 后续可能会发送额外的DiscoveryRequest,用于在特定version_info上使用新的资源提示来更新管理服务器.举个例子: 如果Envoy在EDS版本X时仅知道集群foo,但随后收到一个CDS更新时额外获取了集群bar,它可能会为版本X发出额外的DiscoveryRequest请求,并将{foo,bar}作为请求的resource_names.

这里可能会出现竞争情况;如果Envoy在版本X上发布了资源提示更新请求,但在管理服务器处理该请求之前发送了新的版本号为Y的响应,对于version_info为X的版本,资源提示更新可能会被解释为拒绝Y.为了避免这种情况,管理服务器提供nonce,Envoy可以用来保证DiscoveryResponse对应每个DiscoveryRequest.

管理服务器不应发送DiscoveryResponse响应给任何过期DiscoveryRequest请求.Envoy在DiscoveryResponse响应中包含了新的nonce,而旧的nonce将过期做废.在新的版本就绪前,管理服务器不需要发送更新.同版本的早期请求也会过期.在新版本就绪时,管理服务器可能会处理同版本的多个DiscoveryRequests请求.

上述资源更新时序图表明Envoy 并不能期待其发出的每个DiscoveryRequest请求都能得到DiscoveryResponse响应.

最终一致性考虑

由于Envoy xDS API采用最终一致性,在更新期会导致流量丢失.举个例子: 如果通过CDS/EDS仅获取到了集群X,而且RouteConfiguration引用了集群X,在CDS/EDS更新集群Y配置之前,如果将集群调整为Y,那么流量将被丢弃,直到集群Y被Envoy实例获取.

对某些应用程序,暂时的流量丢失是可接受的,客户端重试或其它的Envoy sidecar会掩盖这这些丢失.对于对流量丢失不能容忍的场景,可以通过以下方式避免流量丢失.CDS/EDS更新同时携带X和Y,然后发送RDS更新从X切换到Y,最后发送丢弃X的CDS/EDS更新.

通常情况下,为了避免流量丢失,更新的顺序应该遵循make before break模型,其中

  • 必须始终先推送CDS更新(如果有).
  • EDS更新(如果有)必须在相应群集的CDS更新后到达.
  • LDS更新必须在相应的CDS/EDS更新后到达.
  • 与新添加的监听器相关的RDS更新必须最终到达.
  • 删除过期的CDS群集和相关的EDS端点(不再被引用的端点).

如果没有新的集群/路由/监听器或者允许更新时临时流量丢失的情况下,可以单独推送xDS更新.请注意,在LDS更新的情况下,监听器须在接收流量之前被预热,例如: 如果配置了依赖的路由,则需先从RDS获取规则.添加/删除/更新集群信息时,集群也要进行预热.另一方面,路由可以不用预热,例如: 管理平面确保在更新路由时,集群中的路由已经就绪.

聚合服务发现(ADS)

当管理服务器进行分发时,通过上述保证交互顺序的方式来避免流量丢失是一项很有挑战的工作.ADS允许单一管理服务器,通过gRPC流的方式来分发所有的API更新.配合仔细规划的更新顺序,ADS可规避更新过程中流量丢失.使用ADS,在单个流上可通过URL类型来进行复用多个独立的DiscoveryRequest/DiscoveryResponse序列.对于任何给定类型的URL,以上的DiscoveryRequestDiscoveryResponse消息序列都适合.一个更新的时序图如下:

对于每个Envoy实例,ADS流都是可用的.

最小化ADS配置的bootstrap.yaml片段示例如下:

node:
id: <node identifier>
dynamic_resources:
cds_config: {ads: {}}
lds_config: {ads: {}}
ads_config:
api_type: GRPC
grpc_services:
envoy_grpc:
cluster_name: ads_cluster
static_resources:
clusters:
- name: ads_cluster
connect_timeout: { seconds: 5 }
type: STATIC
hosts:
- socket_address:
address: <ADS management server IP address>
port_value: <ADS management server port>
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
admin:
...

增量xDS

增量xDS是可用于允许的ADS、CDS和RDS的单独xDS端点:

  • xDS客户端对跟踪资源列表进行增量更新.这支持Envoy按需/惰性地请求额外资源.举个例子: 当与未知集群相对应的请求到达时,这是有可能发生的.
  • xDS服务端可以增量更新客户端上的资源.这支持xDS资源可伸缩性的目标.管理服务器只需发送给更改的单个集群,而不是在修改单个集群时发送给所有100k集群.

xDS增量会话始终位于gRPC双向流的上下文中.这允许xDS服务器能够跟踪到连接的xDS客户端的状态.xDS REST版本不支持增量.

在增量xDS中,nonce字段是必须的,用于匹配IncrementalDiscoveryResponseIncrementalDiscoveryRequest关联的ACK或NACK.可选地,响应级别的消息system_version_info仅用来调试.

IncrementalDiscoveryRequest在以下3种情况发送:

  1. 在一个双向gRPC流初始化消息.
  2. 作为对先前的IncrementalDiscoveryResponse的ACK或NACK响应.这种情况下,response_nonce将在响应中被设为nonce值.ACK或NACK存不存在由error_detail确定.
  3. 由客户自发.可以动态地添加或删除被跟踪resource_names集.在这种情况下,response_nonce必须被忽略.

在第一个示例中,客户端连接并接收它的第一个更新并ACK,第二次更新失败,客户发送NACK拒绝更新,然后xDS客户端会自发的请求"wc"资源.

在重新连接时,增量的xDS客户端可能会告诉服务器其已有资源从而避免通过网络重新发送它们.

轮询REST-JSOM URL订阅

通过REST端点进行同步(长)轮询,也可用于xDS单例API.和上面的消息序列类似,除了在管理服务器没有保持一个永久的流.在任何时间点只有一个未完成的请求,因此响应现时在REST-JSON中是可选的.proto3的Json编码规范用于编码DiscoveryRequestDiscoveryResponse消息.ADS不适用REST-JSON轮询.

当轮询周期设置为较小的值时,为了进行长轮询,则还需要避免发送DiscoveryResponse,除非对底层资源进行了更改.

(译)xDS REST and gRPC protocol的更多相关文章

  1. Go微服务实战 - 用户服务开发(gRPC+Protocol Buffer)

    概要 用户服务基本是每个互联网产品里必备的一个服务了,因为没有用户基本是什么也干不了.所以他的重要性不言而喻.本文主要介绍下如何开发一个用户微服务,以及他的详细开发流程. 目录 Go微服务实战 - 从 ...

  2. Istio流量管理实现机制深度解析

    https://zhaohuabing.com/post/2018-09-25-istio-traffic-management-impl-intro/TOC 前言 Pilot高层架构 统一的服务模型 ...

  3. 深入理解Istio核心组件之Pilot

    Istio作为当前服务网格(Service Mesh)领域的事实标准,流量治理(Traffic Management)是其最为基础也最为重要的功能.本文将结合源码对Istio流量治理的实现主体——组件 ...

  4. 新手学分布式 - Envoy Proxy XDS Server动态配置的一点使用心得

    Envoy Proxy 动态API的使用总结 Envoy Proxy和其它L4/L7反向搭理工具最大的区别就是原生支持动态配置. 首先来看一下Envoy的大致架构 从上图可以简单理解:Listener ...

  5. springboot2 + grpc + k8s + istio

    项目情况说明: ubuntu - 16.04 springboot - 2.2.2.RELEASE mysql - 5.7 mongodb - 4.0.14 redis - 3.0.6 grpc -  ...

  6. Istio中的流量配置

    Istio中的流量配置 目录 Istio中的流量配置 Istio注入的容器 Istio-init istio-proxy Envoy架构 Pilot-agent生成的初始配置文件 Envoy管理接口获 ...

  7. NetCore开源项目集合

    具体见:https://github.com/thangchung/awesome-dotnet-core 半年前看到的,今天又看到了,记录下. 框架类: ZKWeb ABP General ASP. ...

  8. 11 Go 1.11 Release Notes

    Go 1.11 Release Notes Introduction to Go 1.11 Changes to the language Ports WebAssembly RISC-V GOARC ...

  9. 09 Go 1.9 Release Notes

    Go 1.9 Release Notes Introduction to Go 1.9 Changes to the language Ports ppc64x requires POWER8 Fre ...

随机推荐

  1. luogu3978 [TJOI2015]概率论

    题目链接:洛谷 题目大意:求所有$n$个点的有根二叉树的叶子节点数总和/$n$个点的有根二叉树的个数. 数据范围:$n\leq 10^9$ 生成函数神题!!!!(我只是来水博客的) 首先$n$个点的有 ...

  2. caffe报错:cudnn.hpp:86] Check failed: status == CUDNN_STATUS_SUCCESS (3 vs. 0) CUDNN_STATUS_BAD_PARAM 原因

    在实际项目中出现的该问题,起初以为是cudnn版本的问题,后来才定位到在网络进行reshape操作的时候 input_layer->Reshape({(), input_layer->sh ...

  3. autoMapper的介绍

    .NET的DTO映射工具AutoMapper 分类: 多层架构 DTO .NET2012-08-11 10:27 2466人阅读 评论(0) 收藏 举报 原文:https://github.com/A ...

  4. 文件上传下下载(不包含断点续传) Excel,Word导入导出基础

    1.文件上传下载(MVC应用) 视图:form表单,编码方式为multipart/form-data <body> <div> <form action="/D ...

  5. Python基础(十三) 为什么说python多线程没有真正实现多现程

    Python中的多线程没有真正实现多现程! 为什么这么说,我们了解一个概念,全局解释器锁(GIL). Python代码的执行由Python虚拟机(解释器)来控制. Python在设计之初就考虑要在主循 ...

  6. Go 初体验 - 死锁的几种情况

    go 语言里,channel 是一个重要的对象和概念,它是通信的基础实现 如何实例化: ch := make(chan int) 由 channel 通信引起的死锁共有3种: 第一种是因为给 ch 推 ...

  7. Sitecore Aliases

    Sitecore别名 出于各种原因,有时您希望页面URL简短且易于记忆.例如,如果您在网站上运行任何广告系列或某些广告,则需要轻松记住该网址.在Sitecore中,有一种方法可以为名为Sitecore ...

  8. hdu4916 Count on the path

    调了好久.... •把树视为以1为根的有向树,然后将1删除 •原树变为一个森林,并且任一棵树的根节点均为原树中1的子节点 •只需要考虑最小编号前3小的三棵树 •记f[x][y]为去掉x和y两棵树后的最 ...

  9. Mysql error 1317导致从库复制断开

    环境 :Percona Server for MySQL 5.5.18 1. 报错日志: 171212 19:59:58 [ERROR] Slave SQL: Query partially comp ...

  10. 什么是DNS攻击?它是如何工作的?

    什么是DNS攻击?它是如何工作的? DNS攻击是一种利用域名系统中的弱点或漏洞的网络攻击.今天,互联网已成为我们生活中不可或缺的一部分.从社交到金融.购物再到旅游,我们生活的方方面面都是互联网.由于互 ...