<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>提案 on Apache Dubbo</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/</link><description>Recent content in 提案 on Apache Dubbo</description><generator>Hugo</generator><language>zh-cn</language><atom:link href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/index.xml" rel="self" type="application/rss+xml"/><item><title>Rest 协议</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/protocol-http/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/protocol-http/</guid><description>&lt;p>本文将介绍 Dubbo 的 REST/HTTP 协议设计。&lt;/p>
&lt;h2 id="restprotocol设计">RestProtocol 设计&lt;/h2>
&lt;h3 id="原版本dubborest">原版本dubbo rest&lt;/h3>
&lt;p>&lt;strong>consumer&lt;/strong>&lt;/p>
&lt;p>restClient支持 依赖resteasy 不支持spring mvc &lt;/p>
&lt;p>&lt;strong>provider(较重)&lt;/strong>&lt;/p>
&lt;p>依赖web container   (tomcat,jetty，)servlet 模式，jaxrs netty server&lt;/p>
&lt;h3 id="新版本dubborest">新版本dubbo rest &lt;/h3>
&lt;p>更加轻量，具有dubbo风格的rest，微服务体系互通（Springcloud Alibaba）&lt;/p>
&lt;p>&lt;strong>1.注解解析&lt;/strong>&lt;/p>
&lt;p>&lt;strong>2.报文编解码&lt;/strong>&lt;/p>
&lt;p>&lt;strong>3.restClient&lt;/strong>&lt;/p>
&lt;p>&lt;strong>4.restServer(netty)&lt;/strong>&lt;/p>
&lt;p>支持程度：&lt;/p>
&lt;p>content-type   text json xml form(后续会扩展)&lt;/p>
&lt;p>注解&lt;/p>
&lt;p>param,header,body,pathvaribale （spring mvc &amp;amp; resteasy）&lt;/p>
&lt;h2 id="http协议报文">Http 协议报文&lt;/h2>
&lt;pre>&lt;code>POST /test/path? HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-type: application/json


{&amp;quot;name&amp;quot;:&amp;quot;dubbo&amp;quot;,&amp;quot;age&amp;quot;:10,&amp;quot;address&amp;quot;:&amp;quot;hangzhou&amp;quot;}
&lt;/code>&lt;/pre>
&lt;h3 id="dubbohttpheader">dubbo http(header)&lt;/h3>
&lt;pre>&lt;code>// service key header
path: com.demo.TestInterface
group: demo
port: 80
version: 1.0.0

// 保证长连接
Keep-Alive,Connection: keep-alive
Keep-alive: 60

// RPCContext Attachment
userId: 123456
&lt;/code>&lt;/pre>
&lt;h2 id="支持粒度">支持粒度&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">数据位置&lt;/th>
 &lt;th style="text-align: left">content-type&lt;/th>
 &lt;th style="text-align: left">spring注解&lt;/th>
 &lt;th style="text-align: left">resteasy注解&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">body&lt;/td>
 &lt;td style="text-align: left">无要求&lt;/td>
 &lt;td style="text-align: left">ReuqestBody&lt;/td>
 &lt;td style="text-align: left"> 无注解即为body&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">querystring(?test=demo)&lt;/td>
 &lt;td style="text-align: left">无要求&lt;/td>
 &lt;td style="text-align: left">RequestParam&lt;/td>
 &lt;td style="text-align: left">QueryParam&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">header&lt;/td>
 &lt;td style="text-align: left">无要求&lt;/td>
 &lt;td style="text-align: left">RequestHeader&lt;/td>
 &lt;td style="text-align: left">PathParam&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">form&lt;/td>
 &lt;td style="text-align: left">application/x-www-form-urlencoded&lt;/td>
 &lt;td style="text-align: left">RequestParam ReuqestBody&lt;/td>
 &lt;td style="text-align: left">FormParam&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">path&lt;/td>
 &lt;td style="text-align: left">无要求&lt;/td>
 &lt;td style="text-align: left">PathVariable&lt;/td>
 &lt;td style="text-align: left">PathParam&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">method&lt;/td>
 &lt;td style="text-align: left">无要求&lt;/td>
 &lt;td style="text-align: left">PostMapping GetMapping&lt;/td>
 &lt;td style="text-align: left">GET POST&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">url&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">PostMapping GetMapping path属性&lt;/td>
 &lt;td style="text-align: left">Path&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">content-type&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">PostMapping GetMapping consumers属性&lt;/td>
 &lt;td style="text-align: left">Consumers&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">Accept&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">PostMapping GetMapping produces属性&lt;/td>
 &lt;td style="text-align: left">Produces&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="rest注解解析">rest注解解析&lt;/h2>
&lt;p>ServiceRestMetadataResolver&lt;/p></description></item><item><title>注册中心、配置中心和元数据中心</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/registry-config-meta/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/registry-config-meta/</guid><description>&lt;h2 id="三中心逻辑架构">三中心逻辑架构&lt;/h2>
&lt;blockquote>
&lt;p>本节侧重描述传统模式下的 Dubbo 部署架构，在云原生背景下的部署架构会有些变化，主要体现在基础设施（Kubernetes、Service Mesh等）会承担更多的职责，
中心化组件如注册中心、元数据中心、配置中心等的职责被集成、运维变得更加简单，但通过强调这些中心化的组件能让我们更容易理解 Dubbo 的工作原理。&lt;/p>
&lt;/blockquote>
&lt;p>作为一个微服务框架，Dubbo sdk 跟随着微服务组件被部署在分布式集群各个位置，为了在分布式环境下实现各个微服务组件间的协作，
Dubbo 定义了一些中心化组件，这包括：&lt;/p>
&lt;ul>
&lt;li>注册中心。协调 Consumer 与 Provider 之间的地址注册与发现&lt;/li>
&lt;li>配置中心。
&lt;ul>
&lt;li>存储 Dubbo 启动阶段的全局配置，保证配置的跨环境共享与全局一致性&lt;/li>
&lt;li>负责服务治理规则（路由规则、动态配置等）的存储与推送。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>元数据中心。
&lt;ul>
&lt;li>接收 Provider 上报的服务接口元数据，为 Admin 等控制台提供运维能力（如服务测试、接口文档等）&lt;/li>
&lt;li>作为服务发现机制的补充，提供额外的接口/方法级别配置信息的同步能力，相当于注册中心的额外扩展&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>&lt;img alt="threecenters" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/concepts/threecenters.png">&lt;/p>
&lt;p>上图完整的描述了 Dubbo 微服务组件与各个中心的交互过程。&lt;/p>
&lt;p>以上三个中心并不是运行 Dubbo 的必要条件，用户完全可以根据自身业务情况决定只启用其中一个或多个，以达到简化部署的目的。通常情况下，所有用户都会以独立的注册中心
以开始 Dubbo 服务开发，而配置中心、元数据中心则会在微服务演进的过程中逐步的按需被引入进来。&lt;/p>
&lt;h3 id="注册中心">注册中心&lt;/h3>
&lt;p>注册中心扮演着非常重要的角色，它承载着服务注册和服务发现的职责。目前Dubbo支持以下两种粒度的服务发现和服务注册，分别是接口级别和应用级别，注册中心可以按需进行部署：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>在传统的Dubbo SDK使用姿势中，如果仅仅提供直连模式的RPC服务，不需要部署注册中心。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>无论是接口级别还是应用级别，如果需要Dubbo SDK自身来做服务注册和服务发现，则可以选择部署注册中心，在Dubbo中集成对应的注册中心。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>在Dubbo + Mesh 的场景下，随着 Dubbo 服务注册能力的弱化，Dubbo内的注册中心也不再是必选项，其职责开始被控制面取代，如果采用了Dubbo + Mesh的部署方式，无论是ThinSDK的mesh方式还是Proxyless的mesh方式，都不再需要独立部署注册中心。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>而注册中心并不依赖于配置中心和元数据中心，如下图所示：&lt;/p>
&lt;p>&lt;img alt="centers-registry" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/concepts/centers-registry.png">&lt;/p>
&lt;p>该图中没有部署配置中心和元数据中心，在Dubbo中会默认将注册中心的实例同时作为配置中心和元数据中心，这是Dubbo的默认行为，如果确实不需要配置中心或者元数据中心的能力，可在配置中关闭，在注册中心的配置中有两个配置分别为use-as-config-center和use-as-metadata-center，将配置置为false即可。&lt;/p>
&lt;h3 id="元数据中心">元数据中心&lt;/h3>
&lt;p>元数据中心在2.7.x版本开始支持，随着应用级别的服务注册和服务发现在Dubbo中落地，元数据中心也变的越来越重要。在以下几种情况下会需要部署元数据中心：&lt;/p>
&lt;ol>
&lt;li>对于一个原先采用老版本Dubbo搭建的应用服务，在迁移到Dubbo 3时，Dubbo 3 会需要一个元数据中心来维护RPC服务与应用的映射关系（即接口与应用的映射关系），因为如果采用了应用级别的服务发现和服务注册，在注册中心中将采用“应用 —— 实例列表”结构的数据组织形式，不再是以往的“接口 —— 实例列表”结构的数据组织形式，而以往用接口级别的服务注册和服务发现的应用服务在迁移到应用级别时，得不到接口与应用之间的对应关系，从而无法从注册中心得到实例列表信息，所以Dubbo为了兼容这种场景，在Provider端启动时，会往元数据中心存储接口与应用的映射关系。&lt;/li>
&lt;li>为了让注册中心更加聚焦于地址的发现和推送能力，减轻注册中心的负担，元数据中心承载了所有的服务元数据、大量接口/方法级别配置信息等，无论是接口粒度还是应用粒度的服务发现和注册，元数据中心都起到了重要的作用。&lt;/li>
&lt;/ol>
&lt;p>如果有以上两种需求，都可以选择部署元数据中心，并通过Dubbo的配置来集成该元数据中心。&lt;/p>
&lt;p>元数据中心并不依赖于注册中心和配置中心，用户可以自由选择是否集成和部署元数据中心，如下图所示：&lt;/p></description></item><item><title>Dubbo Admin 控制面总体架构设计</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/admin/</link><pubDate>Tue, 28 Feb 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/admin/</guid><description>&lt;h2 id="1-dubbo-整体架构">1 Dubbo 整体架构&lt;/h2>
&lt;p>&lt;img alt="DubboAdmin架构图.png" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/reference/admin/architecture.png">&lt;/p>
&lt;p>架构上分为：&lt;strong>服务治理抽象控制面&lt;/strong> 和 &lt;strong>Dubbo 数据面&lt;/strong> 。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>服务治理控制面&lt;/strong>。控制面包含注册中心、流量管控策略、Admin 控制台、Istio、OpenSergo 等组件。&lt;/li>
&lt;li>&lt;strong>Dubbo 数据面&lt;/strong>。数据面代表集群部署的所有 Dubbo 进程，进程之间通过 RPC 协议实现数据交换，并与控制面进行治理策略交互。&lt;/li>
&lt;/ul>
&lt;p>**进一步解释：**&lt;a href="https://cn.dubbo.apache.org/zh-cn/overview/what/overview/">https://cn.dubbo.apache.org/zh-cn/overview/what/overview/&lt;/a>&lt;/p>
&lt;h2 id="dubbo-admin-的整体定位与解释">Dubbo Admin 的整体定位与解释&lt;/h2>
&lt;p>&lt;strong>Dubbo Admin 是对微服务治理体系的统一定义与抽象，通过自定义核心组件与一系列配套工具，为不同部署架构和基础设施环境下部署的微服务集群带来统一的开发与运维差异。&lt;/strong>&lt;/p>
&lt;h2 id="2-面向用户的开发步骤">2 面向用户的开发步骤&lt;/h2>
&lt;h3 id="第一步安装-dubbo-stackadmin">第一步：安装 Dubbo Stack/Admin&lt;/h3>
&lt;blockquote>
&lt;p>核心思路是，屏蔽架构差异，通过统一入口将治理组件的安装和配置纳入成为 Dubbo 体系中的前置步骤&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>dubboctl install dubbo-stack
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>安装请参见: &lt;a href="../../setup/install/">Dubbo Admin 安装指南&lt;/a>&lt;/p>
&lt;h3 id="第二步服务框架开发">第二步：服务框架开发&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://cn.dubbo.apache.org/zh-cn/overview/quickstart/java/">Java&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://cn.dubbo.apache.org/zh-cn/overview/quickstart/go/">Go&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/apache/dubbo-js">Node.js&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://cn.dubbo.apache.org/zh-cn/overview/quickstart/rust/">Rust&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="3-控制面方案">3 控制面方案&lt;/h2>
&lt;p>&lt;img alt="Dubbo架构草图.jpeg" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/reference/admin/architecture-draft.png">&lt;/p>
&lt;h3 id="31-确定-dubbo-微服务治理体系的核心能力">3.1 确定 Dubbo 微服务治理体系的核心能力&lt;/h3>
&lt;ul>
&lt;li>服务发现&lt;/li>
&lt;li>配置管理&lt;/li>
&lt;li>流量治理规则&lt;/li>
&lt;li>安全基础设施&lt;/li>
&lt;li>可视化控制台&lt;/li>
&lt;/ul>
&lt;h3 id="32-统一服务治理层接入方式">3.2 统一服务治理层接入方式&lt;/h3>
&lt;p>&lt;img alt="address-discovery.png" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/reference/admin/address-discovery.png">&lt;/p>
&lt;p>**对于任何微服务部署模式，Dubbo 数据面统一面向 **&lt;code>**dubbo://hopst:ip**&lt;/code>&lt;strong>抽象服务治理控制面编程。&lt;/strong>&lt;/p>
&lt;p>具体工作流程：&lt;/p>
&lt;ol>
&lt;li>数据面通过配置先与 admin 组件进行交互，admin 返回当前部署架构下的实际注册中心、配置中心等组件地址，如图中的 &lt;code>nacos://host:port&lt;/code>。&lt;/li>
&lt;li>数据面组件接收到新的组件地址后，直接与 Nacos 建立通信，此后依赖 Nacos 完成服务发现等功能。&lt;/li>
&lt;/ol>
&lt;h3 id="33-在不同场景下如何兑现这些核心能力">3.3 在不同场景下如何兑现这些核心能力？&lt;/h3>
&lt;h4 id="场景一传统微服务体系-vm--kubernetes">场景一：传统微服务体系 (VM &amp;amp; Kubernetes)&lt;/h4>
&lt;ul>
&lt;li>控制面治理体系一键安装 (Admin &amp;amp; Nacos)&lt;/li>
&lt;li>传统 Nacos 服务发现与治理模式&lt;/li>
&lt;li>控制面可按需拉起更多的的组件，如 prometheus 等&lt;/li>
&lt;/ul>
&lt;p>&lt;img alt="traditional.png" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/reference/admin/traditional.png">&lt;/p></description></item><item><title>指标埋点</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/metrics/</link><pubDate>Mon, 20 Feb 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/metrics/</guid><description>&lt;h1 id="概述">概述&lt;/h1>
&lt;h2 id="1-指标接入说明">1. 指标接入说明&lt;/h2>
&lt;h2 id="2-指标体系设计">2. 指标体系设计&lt;/h2>
&lt;p>Dubbo的指标体系，总共涉及三块，指标收集、本地聚合、指标推送&lt;/p>
&lt;ul>
&lt;li>指标收集：将Dubbo内部需要监控的指标推送至统一的Collector中进行存储&lt;/li>
&lt;li>本地聚合：指标收集获取的均为基础指标，而一些分位数指标则需通过本地聚合计算得出&lt;/li>
&lt;li>指标推送：收集和聚合后的指标通过一定的方式推送至第三方服务器，目前只涉及Prometheus&lt;/li>
&lt;/ul>
&lt;h2 id="3-结构设计">3. 结构设计&lt;/h2>
&lt;ul>
&lt;li>移除原来与 Metrics 相关的类&lt;/li>
&lt;li>创建新模块 dubbo-metrics/dubbo-metrics-api、dubbo-metrics/dubbo-metrics-prometheus，MetricsConfig 作为该模块的配置类&lt;/li>
&lt;li>使用micrometer，在Collector中使用基本类型代表指标，如Long、Double等，并在dubbo-metrics-api中引入micrometer，由micrometer对内部指标进行转换&lt;/li>
&lt;/ul>
&lt;h2 id="4-数据流转">4. 数据流转&lt;/h2>
&lt;p>&lt;img alt="img.png" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/docs3-v2/java-sdk/observability/dataflow.png">&lt;/p>
&lt;h2 id="5-目标">5. 目标&lt;/h2>
&lt;p>指标接口将提供一个 MetricsService，该 Service 不仅提供柔性服务所的接口级数据，也提供所有指标的查询方式，其中方法级指标的查询的接口可按如下方式声明&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">MetricsService&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * Default {@link MetricsService} extension name.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String DEFAULT_EXTENSION_NAME &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#2aa198">&amp;#34;default&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * The contract version of {@link MetricsService}, the future update must make sure compatible.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String VERSION &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#2aa198">&amp;#34;1.0.0&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * Get metrics by prefixes
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param categories categories
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return metrics - key=MetricCategory value=MetricsEntityList
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsCategory, List&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsEntity&lt;span style="color:#719e07">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#268bd2">getMetricsByCategories&lt;/span>(List&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsCategory&lt;span style="color:#719e07">&amp;gt;&lt;/span> categories);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * Get metrics by interface and prefixes
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param categories categories
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return metrics - key=MetricCategory value=MetricsEntityList
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsCategory, List&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsEntity&lt;span style="color:#719e07">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#268bd2">getMetricsByCategories&lt;/span>(String serviceUniqueName, List&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsCategory&lt;span style="color:#719e07">&amp;gt;&lt;/span> categories);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * Get metrics by interface、method and prefixes
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param methodName methodName
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param parameterTypes method parameter types
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param categories categories
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return metrics - key=MetricCategory value=MetricsEntityList
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsCategory, List&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsEntity&lt;span style="color:#719e07">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#268bd2">getMetricsByCategories&lt;/span>(String serviceUniqueName, String methodName, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;[]&lt;/span> parameterTypes, List&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsCategory&lt;span style="color:#719e07">&amp;gt;&lt;/span> categories);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>其中 MetricsCategory 设计如下:&lt;/p></description></item><item><title>自适应负载均衡与限流</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/heuristic-flow-control/</link><pubDate>Mon, 30 Jan 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/heuristic-flow-control/</guid><description>&lt;h1 id="整体介绍">整体介绍&lt;/h1>
&lt;p>本文所说的柔性服务主要是指&lt;strong>consumer端的负载均衡&lt;/strong>和&lt;strong>provider端的限流&lt;/strong>两个功能。在之前的dubbo版本中，&lt;/p>
&lt;ul>
&lt;li>负载均衡部分更多的考虑的是公平性原则，即consumer端尽可能平等的从provider中作出选择，在某些情况下表现并不够理想。&lt;/li>
&lt;li>限流部分只提供了静态的限流方案，需要用户对provider端设置静态的最大并发值，然而该值的合理选取对用户来讲并不容易。&lt;/li>
&lt;/ul>
&lt;p>我们针对这些存在的问题进行了改进。&lt;/p>
&lt;h2 id="负载均衡">负载均衡&lt;/h2>
&lt;h3 id="使用介绍">使用介绍&lt;/h3>
&lt;p>在原本的dubbo版本中，有五种负载均衡的方案供选择，他们分别是 &lt;code>Random&lt;/code>、&lt;code>ShortestResponse&lt;/code>、&lt;code>RoundRobin&lt;/code>、&lt;code>LeastActive&lt;/code> 和 &lt;code>ConsistentHash&lt;/code>。其中除 &lt;code>ShortestResponse&lt;/code> 和 &lt;code>LeastActive&lt;/code> 外，其他的几种方案主要是考虑选择时的公平性和稳定性。&lt;/p>
&lt;p>对于 &lt;code>ShortestResponse&lt;/code> 来说，其设计目的是从所有备选的 provider 中选择 response 时间最短的以提高系统整体的吞吐量。然而存在两个问题：&lt;/p>
&lt;ol>
&lt;li>在大多数的场景下，不同provider的response时长没有非常明显的区别，此时该算法会退化为随机选择。&lt;/li>
&lt;li>response的时间长短有时也并不能代表机器的吞吐能力。对于 &lt;code>LeastActive&lt;/code> 来说，其认为应该将流量尽可能分配到当前并发处理任务较少的机器上。但是其同样存在和 &lt;code>ShortestResponse&lt;/code> 类似的问题，即这并不能单独代表机器的吞吐能力。&lt;/li>
&lt;/ol>
&lt;p>基于以上分析，我们提出了两种新的负载均衡算法。一种是同样基于公平性考虑的单纯 &lt;code>P2C&lt;/code> 算法，另一种是基于自适应的方法 &lt;code>adaptive&lt;/code>，其试图自适应的衡量 provider 端机器的吞吐能力，然后将流量尽可能分配到吞吐能力高的机器上，以提高系统整体的性能。&lt;/p>
&lt;h4 id="总体效果">总体效果&lt;/h4>
&lt;p>对于负载均衡部分的有效性实验在两个不同的情况下进行的，分别是提供端机器配置比较均衡和提供端机器配置差距较大的情况。&lt;/p>
&lt;p>&lt;img alt="image.png" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/overview/reference/proposals/heuristic-flow-control/1675265258687-c3df68a8-80e0-4311-816c-63480494850c.png">&lt;/p>
&lt;p>&lt;img alt="image.png" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/overview/reference/proposals/heuristic-flow-control/1675265271198-5b045ced-8524-42a2-8b34-d7edbbd1f232.png">&lt;/p>
&lt;h4 id="使用方法">使用方法&lt;/h4>
&lt;p>&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance">Dubbo Java 实现的使用方法&lt;/a> 与原本的负载均衡方法相同。只需要在consumer端将&amp;quot;loadbalance&amp;quot;设置为&amp;quot;p2c&amp;quot;或者&amp;quot;adaptive&amp;quot;即可。&lt;/p>
&lt;h4 id="代码结构">代码结构&lt;/h4>
&lt;p>负载均衡部分的算法实现只需要在原本负载均衡框架内继承 LoadBalance接口即可。&lt;/p>
&lt;h3 id="原理介绍">原理介绍&lt;/h3>
&lt;h4 id="p2c算法">P2C算法&lt;/h4>
&lt;p>Power of Two Choice 算法简单但是经典，主要思路如下：&lt;/p>
&lt;ol>
&lt;li>对于每次调用，从可用的provider列表中做两次随机选择，选出两个节点providerA和providerB。&lt;/li>
&lt;li>比较providerA和providerB两个节点，选择其“当前正在处理的连接数”较小的那个节点。&lt;/li>
&lt;/ol>
&lt;h4 id="adaptive算法">adaptive算法&lt;/h4>
&lt;p>&lt;a href="https://github.com/apache/dubbo/pull/10745">代码的github地址&lt;/a>&lt;/p>
&lt;h5 id="相关指标">相关指标&lt;/h5>
&lt;ol>
&lt;li>
&lt;p>cpuLoad
&lt;img alt="img" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/overview/reference/proposals/heuristic-flow-control/26808016bc7f1ee83ab425e308074f17.svg">。该指标在provider端机器获得，并通过invocation的attachment传递给consumer端。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>rt
rt为一次rpc调用所用的时间，单位为毫秒。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>timeout
timeout为本次rpc调用超时剩余的时间，单位为毫秒。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>weight
weight是设置的服务权重。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>currentProviderTime
provider端在计算cpuLoad时的时间，单位是毫秒&lt;/p>
&lt;/li>
&lt;li>
&lt;p>currentTime
currentTime为最后一次计算load时的时间，初始化为currentProviderTime，单位是毫秒。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>multiple
&lt;img alt="img" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/overview/reference/proposals/heuristic-flow-control/b60f036bd026b92129df8a6476922cc8.svg">&lt;/p></description></item><item><title>Dubbo3 应用级服务发现设计</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/service-discovery/</link><pubDate>Mon, 30 Jan 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/service-discovery/</guid><description>&lt;h2 id="objective">Objective&lt;/h2>
&lt;ul>
&lt;li>显著降低服务发现过程的资源消耗，包括提升注册中心容量上限、降低消费端地址解析资源占用等，使得 Dubbo3 框架能够支持更大规模集群的服务治理，实现无限水平扩容。&lt;/li>
&lt;li>适配底层基础设施服务发现模型，如 Kubernetes、Service Mesh 等。&lt;/li>
&lt;/ul>
&lt;h2 id="background">Background&lt;/h2>
&lt;p>&lt;img alt="interface-arc" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/proposals/discovery/arc.png">&lt;/p>
&lt;p>我们从 Dubbo 最经典的工作原理图说起，Dubbo 从设计之初就内置了服务地址发现的能力，Provider 注册地址到注册中心，Consumer 通过订阅实时获取注册中心的地址更新，在收到地址列表后，consumer 基于特定的负载均衡策略发起对 provider 的 RPC 调用。&lt;/p>
&lt;p>在这个过程中：&lt;/p>
&lt;ul>
&lt;li>每个 Provider 通过特定的 key 向注册中心注册本机可访问地址；&lt;/li>
&lt;li>注册中心通过这个 key 对 provider 实例地址进行聚合；&lt;/li>
&lt;li>Consumer 通过同样的 key 从注册中心订阅，以便及时收到聚合后的地址列表；&lt;/li>
&lt;/ul>
&lt;p>&lt;img alt="interface-data1" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/proposals/discovery/interface-data1.png">&lt;/p>
&lt;p>这里，我们对接口级地址发现的内部数据结构进行详细分析。&lt;/p>
&lt;p>首先，看右下角 provider 实例内部的数据与行为。Provider 部署的应用中通常会有多个 Service，也就是 Dubbo2 中的服务，每个 service 都可能会有其独有的配置，我们所讲的 service 服务发布的过程，其实就是基于这个服务配置生成地址 URL 的过程，生成的地址数据如图所示；同样的，其他服务也都会生成地址。&lt;/p>
&lt;p>然后，看一下注册中心的地址数据存储结构，注册中心以 service 服务名为数据划分依据，将一个服务下的所有地址数据都作为子节点进行聚合，子节点的内容就是实际可访问的ip地址，也就是我们 Dubbo 中 URL，格式就是刚才 provider 实例生成的。&lt;/p>
&lt;p>&lt;img alt="interface-data2" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/proposals/discovery/interface-data2.png">&lt;/p>
&lt;p>这里把 URL 地址数据划分成了几份：&lt;/p>
&lt;ul>
&lt;li>首先是实例可访问地址，主要信息包含 ip port，是消费端将基于这条数据生成 tcp 网络链接，作为后续 RPC 数据的传输载体&lt;/li>
&lt;li>其次是 RPC 元数据，元数据用于定义和描述一次 RPC 请求，一方面表明这条地址数据是与某条具体的 RPC 服务有关的，它的版本号、分组以及方法相关信息，另一方面表明&lt;/li>
&lt;li>下一部分是 RPC 配置数据，部分配置用于控制 RPC 调用的行为，还有一部分配置用于同步 Provider 进程实例的状态，典型的如超时时间、数据编码的序列化方式等。&lt;/li>
&lt;li>最后一部分是自定义的元数据，这部分内容区别于以上框架预定义的各项配置，给了用户更大的灵活性，用户可任意扩展并添加自定义元数据，以进一步丰富实例状态。&lt;/li>
&lt;/ul>
&lt;p>结合以上两页对于 Dubbo2 接口级地址模型的分析，以及最开始的 Dubbo 基本原理图，我们可以得出这么几条结论：&lt;/p></description></item><item><title>Triple协议Http标准能力增强-多Content-Type支持</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/support-more-content-types/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/reference/proposals/support-more-content-types/</guid><description>&lt;h3 id="triple协议http标准能力增强-多content-type支持">&lt;strong>Triple协议Http标准能力增强-多Content-Type支持&lt;/strong>&lt;/h3>
&lt;blockquote>
&lt;p>本文主要介绍Triple对更多HTTP标准Content-Type的支持方式，以及服务该如何接收这些请求。&lt;/p>
&lt;/blockquote>
&lt;h4 id="概述">&lt;strong>概述&lt;/strong>&lt;/h4>
&lt;p>Triple目前支持两种序列化方式：Json和protobuf，对应的ContentType：&lt;/p>
&lt;ul>
&lt;li>application/json&lt;/li>
&lt;li>application/grpc+proto&lt;/li>
&lt;/ul>
&lt;p>这在消费者和提供者都是后端服务时没有问题。但对于浏览器客户端，其可能发送更多类型的ContentType，需要服务端支持解码，如：&lt;/p>
&lt;ul>
&lt;li>multipart/formdata&lt;/li>
&lt;li>text/plain&lt;/li>
&lt;li>application/x-www-form-urlencoded&lt;/li>
&lt;li>application/xml&lt;/li>
&lt;/ul>
&lt;p>Rest已基本实现上述解码能力，使Triple实现这些能力是让Triple服务端与浏览器客户端完全互通的重要一步。&lt;/p>
&lt;h4 id="用法">&lt;strong>用法&lt;/strong>&lt;/h4>
&lt;h5 id="multipartformdata">&lt;strong>multipart/formdata&lt;/strong>&lt;/h5>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-http" data-lang="http">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">POST&lt;/span> /org.apache.dubbo.samples.tri.noidl.api.PojoGreeter/greetPojo &lt;span style="color:#268bd2">HTTP&lt;/span>&lt;span style="color:#719e07">/&lt;/span>&lt;span style="color:#2aa198">1.1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Host&lt;span style="color:#719e07">:&lt;/span> 192.168.202.1:50052
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Type&lt;span style="color:#719e07">:&lt;/span> multipart/form-data; boundary=example-part-boundary
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Accept&lt;span style="color:#719e07">:&lt;/span> application/json
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--example-part-boundary
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Disposition: form-data; name=&amp;#34;username&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Type: text/plain
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>LuYue
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--example-part-boundary
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Disposition: form-data; name=&amp;#34;userdetail&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Type: application/json
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;location&amp;#34;:&amp;#34;beijing&amp;#34;,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;username&amp;#34;:&amp;#34;LuYue&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--example-part-boundary
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Disposition: form-data; name=&amp;#34;userimg&amp;#34;;filename=&amp;#34;user.jpeg&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Type: image/jpeg
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;binary-image data&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--example-part-boundary--
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>接收：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> ServerResponse &lt;span style="color:#268bd2">greetPojo&lt;/span>(String username, User user, &lt;span style="color:#dc322f">byte&lt;/span>&lt;span style="color:#719e07">[]&lt;/span> attachment) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//LuYue&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> System.out.println(username); 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//user.name=Luyue;user.location=beijing&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> System.out.println(user); 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//&amp;lt;binary-image data&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> System.out.println(&lt;span style="color:#719e07">new&lt;/span> String(attachment, StandardCharsets.UTF_8)); 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServerResponse(&lt;span style="color:#2aa198">&amp;#34;Server Received:&amp;#34;&lt;/span>&lt;span style="color:#719e07">+&lt;/span>username);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>每一个 part 根据其 Content-Type 解码&lt;/li>
&lt;li>若方法参数是 byte[] 或 Byte[]，对应字段不会解码&lt;/li>
&lt;li>响应使用 application/json 编码&lt;/li>
&lt;/ul>
&lt;h5 id="applicationx-www-form-urlencoded">application/x-www-form-urlencoded&lt;/h5>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-http" data-lang="http">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">POST&lt;/span> /org.apache.dubbo.samples.tri.noidl.api.PojoGreeter/greetUrlForm &lt;span style="color:#268bd2">HTTP&lt;/span>&lt;span style="color:#719e07">/&lt;/span>&lt;span style="color:#2aa198">1.1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Host&lt;span style="color:#719e07">:&lt;/span> 192.168.202.1:50052
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Type&lt;span style="color:#719e07">:&lt;/span> application/x-www-form-urlencoded
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Content-Length&lt;span style="color:#719e07">:&lt;/span> 33
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Accept&lt;span style="color:#719e07">:&lt;/span> application/json
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Hello=World&amp;amp;Apache=Dubbo&amp;amp;id=10086
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>两种接收方式：&lt;/p></description></item></channel></rss>