营销型网站建设策划书,广州市最新消息,wordpress输出某一分类的文章,重庆唐卡装饰公司作者 | 刘军(陆龟) Apache Dubbo PMC概述社区版本 Dubbo 从 2.7.5 版本开始#xff0c;新引入了一种基于实例(应用)粒度的服务发现机制#xff0c;这是我们为 Dubbo 适配云原生基础设施的一步重要探索。版本发布到现在已有近半年时间#xff0c;经过这段时间的探索与总结新引入了一种基于实例(应用)粒度的服务发现机制这是我们为 Dubbo 适配云原生基础设施的一步重要探索。版本发布到现在已有近半年时间经过这段时间的探索与总结我们对这套机制的可行性与稳定性有了更全面、深入的认识同时在 Dubbo 3.0 的规划也在全面进行中如何让应用级服务发现成为未来下一代服务框架 Dubbo 3.0 的基础服务模型解决云原生、规模化微服务集群扩容与可伸缩性问题也已经成为我们当前工作的重点。既然这套新机制如此重要那它到底是怎么工作的呢今天我们就来详细解读一下。在最开始的社区版本我们给这个机制取了一个神秘的名字 - 服务自省下文将进一步解释这个名字的由来并引用服务自省代指这套应用级服务发现机制。熟悉 Dubbo 开发者应该都知道一直以来都是面向 RPC 方法去定义服务的并且这也是 Dubbo 开发友好性、治理功能强的基础。既然如此那我们为什么还要定义个应用粒度的服务发现机制呢这个机制到底是怎么工作的它与当前机制的区别是什么它能给我们带来哪些好处那对适配云原生、性能提升又有哪些帮助带着所有的这些问题我们开始本文的讲解。服务自省是什么首先我们先来解释文章开篇提到的问题应用粒度服务发现是到底是一种怎样的模型它与当前的 Dubbo 服务发现模型的区别是什么我们为什么叫它服务自省所谓“应用/实例粒度” 或者“RPC 服务粒度”强调的是一种地址发现的数据组织格式。以 Dubbo 当前的地址发现数据格式为例它是“RPC 服务粒度”的它是以 RPC 服务作为 key以实例列表作为 value 来组织数据的RPC Service1: [ {name:instance1, ip:127.0.0.1, metadata:{timeout:1000}}, {name:instance2, ip:127.0.0.1, metadata:{timeout:2000}}, {name:instance3, ip:127.0.0.1, metadata:{timeout:3000}},]RPC Service2: [Instance list of RPC Service2],RPC ServiceN: [Instance list of RPC ServiceN]而我们新引入的“应用粒度的服务发现”它以应用名(Application)作为 key以这个应用部署的一组实例(Instance)列表作为 value。这带来两点不同数据映射关系变了从 RPC Service - Instance 变为 Application - Instance数据变少了注册中心没有了 RPC Service 及其相关配置信息。application1: [ {name:instance1, ip:127.0.0.1, metadata:{}}, {name:instance2, ip:127.0.0.1, metadata:{}}, {name:instanceN, ip:127.0.0.1, metadata:{}}]要进一步理解新模型带来的变化我们看一下应用与 RPC 服务间的关系显而易见的1 个应用内可能会定义 n 个 RPC Service。因此 Dubbo 之前的服务发现粒度更细在注册中心产生的数据条目也会更多(与 RPC 服务成正比)同时也存在一定的数据冗余。简单理解了应用级服务发现的基本机制接着解释它为什么会被叫做“服务自省”其实这还是得从它的工作原理说起上面我们提到应用粒度服务发现的数据模型有几个以下明显变化数据中心的数据量少了RPC 服务相关的数据在注册中心没有了现在只有 application - instance 这两个层级的数据。为了保证这部分缺少的 RPC 服务数据仍然能被 Consumer 端正确的感知我们在 Consumer 和 Provider 间建立了一条单独的通信通道Consumer 和 Provider 两两之间通过特定端口交换信息我们把这种 Provider 自己主动暴露自身信息的行为认为是一种内省机制因此从这个角度出发我们把整个机制命名为服务自省。为什么需要服务自省上面讲服务自省的大概原理的时候也提到了它给注册中心带来的几点不同这几点不同体现在 Dubbo 框架侧(甚至整个微服务体系中)有以下优势与业界主流微服务模型对齐比如 SpringCloud、Kubernetes Native Service 等提升性能与可伸缩性。注册中心数据的重新组织(减少)能最大幅度的减轻注册中心的存储、推送压力进而减少 Dubbo Consumer 侧的地址计算压力集群规模也开始变得可预测、可评估(与 RPC 接口数量无关只与实例部署规模相关)。1. 对齐主流微服务模型自动、透明的实例地址发现(负载均衡)是所有微服务框架需要解决的事情这能让后端的部署结构对上游微服务透明上游服务只需要从收到的地址列表中选取一个发起调用就可以了。要实现以上目标涉及两个关键点的自动同步实例地址服务消费方需要知道地址以建立链接RPC 方法定义服务消费方需要知道 RPC 服务的具体定义不论服务类型是 rest 或 rmi 等。按照文章中的 4 级成熟度定义Dubbo 当前基于接口粒度的模型可以对应到 L4 级别。接下来我们看看 Dubbo、SpringCloud 以及 Kubernetes 分别是怎么围绕自动化的实例地址发现这个目标设计的。2. Spring CloudSpring Cloud 通过注册中心只同步了应用与实例地址消费方可以基于实例地址与服务提供方建立链接但是消费方对于如何发起 HTTP 调用(SpringCloud 基于 rest 通信)一无所知比如对方有哪些 HTTP endpoint需要传入哪些参数等。RPC 服务这部分信息目前都是通过线下约定或离线的管理系统来协商的。这种架构的优缺点总结如下优势部署结构清晰、地址推送量小缺点地址订阅需要指定应用名 provider 应用变更(拆分)需消费端感知RPC 调用无法全自动同步。3. DubboDubbo 通过注册中心同时同步了实例地址和 RPC 方法因此其能实现 RPC 过程的自动同步面向 RPC 编程、面向 RPC 治理对后端应用的拆分消费端无感知其缺点则是地址推送数量变大和 RPC 方法成正比。4. Dubbo KubernetesDubbo 要支持 Kubernetes native service相比之前自建注册中心的服务发现体系来说在工作机制上主要有两点变化服务注册由平台接管provider 不再需要关心服务注册consumer 端服务发现将是 Dubbo 关注的重点通过对接平台层的 API-Server、DNS 等Dubbo client 可以通过一个 Service Name(通常对应到 Application Name)查询到一组 Endpoints(一组运行 provider 的 pod)通过将 Endpoints 映射到 Dubbo 内部地址列表以驱动 Dubbo 内置的负载均衡机制工作。Kubernetes Service 作为一个抽象概念怎么映射到 Dubbo 是一个值得讨论的点Service Name - Application NameDubbo 应用和 Kubernetes 服务一一对应对于微服务运维和建设环节透明与开发阶段解耦。apiVersion: v1kind: Servicemetadata: name: provider-app-namespec: selector: app: provider-app-name ports: - protocol: TCP port: targetPort: 9376Service Name - Dubbo RPC ServiceKubernetes 要维护调度的服务与应用内建 RPC 服务绑定维护的服务数量变多。---apiVersion: v1kind: Servicemetadata: name: rpc-service-1spec: selector: app: provider-app-name ports: ##...---apiVersion: v1kind: Servicemetadata: name: rpc-service-2spec: selector: app: provider-app-name ports: ##...---apiVersion: v1kind: Servicemetadata: name: rpc-service-Nspec: selector: app: provider-app-name ports: ##...结合以上几种不同微服务框架模型的分析我们可以发现Dubbo 与 SpringCloud、Kubernetes 等不同产品在微服务的抽象定义上还是存在很大不同的。SpringCloud 和 Kubernetes 在微服务的模型抽象上还是比较接近的两者基本都只关心实例地址的同步如果我们去关心其他的一些服务框架产品会发现它们绝大多数也是这么设计的即 REST 成熟度模型中的 L3 级别。对比起来 Dubbo 则相对是比较特殊的存在更多的是从 RPC 服务的粒度去设计的。对应 REST 成熟度模型中的 L4 级别。如我们上面针对每种模型做了详细的分析每种模型都有其优势和不足。而我们最初决定 Dubbo 要做出改变往其他的微服务发现模型上的对齐是我们最早在确定 Dubbo 的云原生方案时我们发现要让 Dubbo 去支持 Kubernetes Native Service模型对齐是一个基础条件另一点是来自用户侧对 Dubbo 场景化的一些工程实践的需求得益于 Dubbo 对多注册、多协议能力的支持使得 Dubbo 联通不同的微服务体系成为可能而服务发现模型的不一致成为其中的一个障碍。5. 更大规模的微服务集群 - 解决性能瓶颈这部分涉及到和注册中心、配置中心的交互关于不同模型下注册中心数据的变化之前原理部分我们简单分析过。为更直观的对比服务模型变更带来的推送效率提升我们来通过一个示例看一下不同模型注册中心的对比图中左边是微服务框架的一个典型工作流程Provider 和 Consumer 通过注册中心实现自动化的地址通知。其中Provider 实例的信息如图中表格所示应用 DEMO 包含三个接口 DemoService 1 2 3当前实例的 ip 地址为 10.210.134.30。对于 Spring Cloud 和 Kubernetes 模型注册中心只会存储一条 DEMO - 10.210.134.30metadata 的数据对于老的 Dubbo 模型注册中心存储了三条接口粒度的数据分别对应三个接口 DemoService 1 2 3并且很多的址数据都是重复的。可以总结出基于应用粒度的模型所存储和推送的数据量是和应用、实例数成正比的只有当我们的应用数增多或应用的实例数增长时地址推送压力才会上涨。而对于基于接口粒度的模型数据量是和接口数量正相关的鉴于一个应用通常发布多个接口的现状这个数量级本身比应用粒度是要乘以倍数的另外一个关键点在于接口粒度导致的集群规模评估的不透明相对于实i例、应用增长都通常是在运维侧的规划之中接口的定义更多的是业务侧的内部行为往往可以绕过评估给集群带来压力。以 Consumer 端服务订阅举例根据我对社区部分 Dubbo 中大规模头部用户的粗略统计根据受统计公司的实际场景一个 Consumer 应用要消费(订阅)的 Provier 应用数量往往要超过 10 个而具体到其要消费(订阅)的的接口数量则通常要达到 30 个平均情况下 Consumer 订阅的 3 个接口来自同一个 Provider 应用如此计算下来如果以应用粒度为地址通知和选址基本单位则平均地址推送和计算量将下降 60% 还要多。而在极端情况下也就是当 Consumer 端消费的接口更多的来自同一个应用时这个地址推送与内存消耗的占用将会进一步得到降低甚至可以超过 80% 以上。一个典型的几段场景即是 Dubbo 体系中的网关型应用有些网关应用消费(订阅)达 100 应用而消费(订阅)的服务有 1000 平均有 10 个接口来自同一个应用如果我们把地址推送和计算的粒度改为应用则地址推送量从原来的 n 1000 变为 n 100地址数量降低可达近 90%。工作原理1. 设计原则上面一节我们从服务模型及支撑大规模集群的角度分别给出了 Dubbo 往应用级服务发现靠拢的好处或原因但这么做的同时接口粒度的服务治理能力还是要继续保留这是 Dubbo 框架编程模型易用性、服务治理能力优势的基础。以下是我认为我们做服务模型迁移仍要坚持的设计原则新的服务发现模型要实现对原有 Dubbo 消费端开发者的无感知迁移即 Dubbo 继续面向 RPC 服务编程、面向 RPC 服务治理做到对用户侧完全无感知建立 Consumer 与 Provider 间的自动化 RPC 服务元数据协调机制解决传统微服务模型无法同步 RPC 级接口配置的缺点。2. 基本原理详解应用级服务发现作为一种新的服务发现机制和以前 Dubbo 基于 RPC 服务粒度的服务发现在核心流程上基本上是一致的即服务提供者往注册中心注册地址信息服务消费者从注册中心拉取订阅地址信息。这里主要的不同有以下两点注册中心数据以“应用 - 实例列表”格式组织不再包含 RPC 服务信息以下是每个 Instance metadata 的示例数据总的原则是 metadata 只包含当前 instance 节点相关的信息不涉及 RPC 服务粒度的信息。总体信息概括如下实例地址、实例各种环境标、metadata service 元数据、其他少量必要属性。{ name: provider-app-name, id: 192.168.0.102:20880, address: 192.168.0.102, port: 20880, sslPort: null, payload: { id: null, name: provider-app-name, metadata: { metadataService: {\dubbo\:{\version\:\1.0.0\,\dubbo\:\2.0.2\,\release\:\2.7.5\,\port\:\20881\}}, endpoints: [{\port\:20880,\protocol\:\dubbo\}], storage-type: local, revision: 6785535733750099598, } }, registrationTimeUTC: 1583461240877, serviceType: DYNAMIC, uriSpec: null}Client – Server 自行协商 RPC 方法信息。在注册中心不再同步 RPC 服务信息后服务自省在服务消费端和提供端之间建立了一条内置的 RPC 服务信息协商机制这也是“服务自省”这个名字的由来。服务端实例会暴露一个预定义的 MetadataService RPC 服务消费端通过调用 MetadataService 获取每个实例 RPC 方法相关的配置信息。当前 MetadataService 返回的数据格式如下[ dubbo://192.168.0.102:20880/org.apache.dubbo.demo.DemoService?anyhosttrueapplicationdemo-providerdeprecatedfalsedubbo2.0.2dynamictruegenericfalseinterfaceorg.apache.dubbo.demo.DemoServicemethodssayHellopid9585release2.7.5sideprovidertimestamp1583469714314, dubbo://192.168.0.102:20880/org.apache.dubbo.demo.HelloService?anyhosttrueapplicationdemo-providerdeprecatedfalsedubbo2.0.2dynamictruegenericfalseinterfaceorg.apache.dubbo.demo.DemoServicemethodssayHellopid9585release2.7.5sideprovidertimestamp1583469714314, dubbo://192.168.0.102:20880/org.apache.dubbo.demo.WorldService?anyhosttrueapplicationdemo-providerdeprecatedfalsedubbo2.0.2dynamictruegenericfalseinterfaceorg.apache.dubbo.demo.DemoServicemethodssayHellopid9585release2.7.5sideprovidertimestamp1583469714314]熟悉 Dubbo 基于 RPC 服务粒度的服务发现模型的开发者应该能看出来服务自省机制机制将以前注册中心传递的 URL 一拆为二一部分和实例相关的数据继续保留在注册中心如 ip、port、机器标识等另一部分和 RPC 方法相关的数据从注册中心移除转而通过 MetadataService 暴露给消费端。理想情况下是能达到数据按照实例、RPC 服务严格区分开来但明显可以看到以上实现版本还存在一些数据冗余有些也数据还未合理划分。尤其是 MetadataService 部分其返回的数据还只是简单的 URL 列表组装这些 URL其实是包含了全量的数据。以下是服务自省的一个完整工作流程图详细描述了服务注册、服务发现、MetadataService、RPC 调用间的协作流程。服务提供者启动首先解析应用定义的“普通服务”并依次注册为 RPC 服务紧接着注册内建的 MetadataService 服务最后打开 TCP 监听端口启动完成后将实例信息注册到注册中心(仅限 ip、port 等实例相关数据)提供者启动完成服务消费者启动首先依据其要“消费的 provider 应用名”到注册中心查询地址列表并完成订阅(以实现后续地址变更自动通知)消费端拿到地址列表后紧接着对 MetadataService 发起调用返回结果中包含了所有应用定义的“普通服务”及其相关配置信息至此消费者可以接收外部流量并对提供者发起 Dubbo RPC 调用。在以上流程中我们只考虑了一切顺利的情况但在更详细的设计或编码实现中我们还需要严格约定一些异常场景下的框架行为。比如如果消费者 MetadataService 调用失败则在重试知道成功之前消费者将不可以接收外部流量。服务自省中的关键机制1. 元数据同步机制Client 与 Server 间在收到地址推送后的配置同步是服务自省的关键环节目前针对元数据同步有两种具体的可选方案分别是内建 MetadataService独立的元数据中心通过中细化的元数据集群协调数据。内建 MetadataServiceMetadataService 通过标准的 Dubbo 协议暴露根据查询条件会将内存中符合条件的“普通服务”配置返回给消费者。这一步发生在消费端选址和调用前元数据中心复用 2.7 版本中引入的元数据中心provider 实例启动后会尝试将内部的 RPC 服务组织成元数据的格式到元数据中心而 consumer 则在每次收到注册中心推送更新后主动查询元数据中心。注意 consumer 端查询元数据中心的时机是等到注册中心的地址更新通知之后。也就是通过注册中心下发的数据我们能明确的知道何时某个实例的元数据被更新了此时才需要去查元数据中心。2. RPC 服务 - 应用映射关系回顾上文讲到的注册中心关于“应用 - 实例列表”结构的数据组织形式这个变动目前对开发者并不是完全透明的业务开发侧会感知到查询/订阅地址列表的机制的变化。具体来说相比以往我们基于 RPC 服务来检索地址现在 consumer 需要通过指定 provider 应用名才能实现地址查询或订阅。老的 Consumer 开发与配置示例新的 Consumer 开发与配置示例以上指定 provider 应用名的方式是 Spring Cloud 当前的做法需要 consumer 端的开发者显示指定其要消费的 provider 应用。以上问题的根源在于注册中心不知道任何 RPC 服务相关的信息因此只能通过应用名来查询。为了使整个开发流程对老的 Dubbo 用户更透明同时避免指定 provider 对可扩展性带来的影响(参见下方说明)我们设计了一套 RPC 服务到应用名的映射关系以尝试在 consumer 自动完成 RPC 服务到 provider 应用名的转换。Dubbo 之所以选择建立一套“接口-应用”的映射关系主要是考虑到 service - app 映射关系的不确定性。一个典型的场景即是应用/服务拆分如上面提到的配置 PC Service 2 是定义于 provider-app-x 中的一个服务未来它随时可能会被开发者分拆到另外一个新的应用如 provider-app-x-1 中这个拆分要被所有的 PC Service 2 消费方感知到并对应用进行修改升级如改为 这样的升级成本不可否认还是挺高的。到底是 Dubbo 框架帮助开发者透明的解决这个问题还是交由开发者自己去解决当然这只是个策略选择问题并且 Dubbo 2.7.5 版本目前是都提供了的。其实我个人更倾向于交由业务开发者通过组织上的约束来做这样也可进一步降低 Dubbo 框架的复杂度提升运行态的稳定性。总结与展望应用级服务发现机制是 Dubbo 面向云原生走出的重要一步它帮 Dubbo 打通了与其他微服务体系之间在地址发现层面的鸿沟也成为 Dubbo 适配 Kubernetes Native Service 等基础设施的基础。我们期望 Dubbo 在新模型基础上能继续保留在编程易用性、服务治理能力等方面强大的优势。但是我们也应该看到应用粒度的模型一方面带来了新的复杂性需要我们继续去优化与增强另一方面除了地址存储与推送之外应用粒度在帮助 Dubbo 选址层面也有进一步挖掘的潜力。作者简介刘军Github 账号 ChickenljApache Dubbo PMC项目核心开发见证了Dubbo从重启开源到Apache毕业的整个流程。现任职阿里云云原生应用平台团队参与服务框架、微服务相关工作目前主要在推动 Dubbo 3.0 - Dubbo 云原生。 动动小手指 了解更多详情