| <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Apache Dubbo – 升级和兼容性</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/</link><description>Recent content in 升级和兼容性 on Apache Dubbo</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><atom:link href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/index.xml" rel="self" type="application/rss+xml"/><item><title>Overview: 2.x 升级至 3.x</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/</guid><description> |
| <h2 id="升级到-dubbo-3x-的收益">升级到 Dubbo 3.X 的收益</h2> |
| <p>Dubbo3 依旧保持了 2.x 的经典架构,以解决微服务进程间通信为主要职责,通过丰富的服务治理(如地址发现、流量管理等)能力来更好的管控微服务集群;Dubbo3 对原有框架的升级是全面的,体现在核心 Dubbo 特性的几乎每个环节,通过升级实现了稳定性、性能、伸缩性、易用性的全面提升。</p> |
| <p><img src="https://dubbo.apache.org/imgs/v3/concepts/architecture-1.png" alt="architecture-1"></p> |
| <ul> |
| <li><strong>通用的通信协议。</strong> 全新的 RPC 协议应摒弃私有协议栈,以更通用的 HTTP/2 协议为传输层载体,借助 HTTP 协议的标准化特性,解决流量通用性、穿透性等问题,让协议能更好的应对前后端对接、网关代理等场景;支持 Stream 通信模式,满足不同业务通信模型诉求的同时给集群带来更大的吞吐量。</li> |
| <li><strong>面向百万集群实例,集群高度可伸缩。</strong> 随着微服务实践的推广,微服务集群实例的规模也在不停的扩展,这得益于微服务轻量化、易于水平扩容的特性,同时也给整个集群容量带来了负担,尤其是一些中心化的服务治理组件;Dubbo3 需要解决实例规模扩展带来的种种资源瓶颈问题,实现真正的无限水平扩容。</li> |
| <li><strong>全面拥抱云原生。</strong></li> |
| </ul> |
| <h2 id="dubbo-30-新特性">Dubbo 3.0 新特性</h2> |
| <p>Dubbo 3.0 提供的新特性包括:</p> |
| <ul> |
| <li><strong>新的地址发现模型(应用级服务发现)。</strong> |
| <ul> |
| <li>查看<a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/">应用级服务发现迁移示例</a>。</li> |
| <li>查看<a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/">应用级服务发现的迁移步骤</a></li> |
| <li>查看<a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/">应用级服务发现地址迁移规则说明</a></li> |
| </ul> |
| </li> |
| <li><strong>下一代基于 HTTP/2 的 Triple 协议。</strong> |
| <ul> |
| <li>查看<a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/">Triple 协议迁移步骤</a></li> |
| <li>查看 <a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/guide/">Triple 协议使用方式</a></li> |
| <li>查看 <a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/overview/">Triple 协议设计与实现</a>。</li> |
| </ul> |
| </li> |
| <li><strong>统一的路由规则。</strong> |
| <ul> |
| <li>查看<a href="https://dubbo.apache.org/zh-cn/overview/tasks/traffic-management/">统一路由规则设计与实现</a></li> |
| </ul> |
| </li> |
| </ul> |
| <h2 id="升级前的兼容性检查">升级前的兼容性检查</h2> |
| <p>在跨版本升级的过程中,存在的风险点从大到小分别有:直接修改 Dubbo 源码 -&gt; 基于 Dubbo SPI 扩展点进行扩展 -&gt; 基于 API 或者 Spring 的使用方式。</p> |
| <h3 id="1-直接修改-dubbo-源码">1. 直接修改 Dubbo 源码</h3> |
| <p>对于直接修改 Dubbo 源码这部分的需要修改方自行判断是否在高版本中正常工作,对于这种非标准行为,Dubbo 无法保证其先前的兼容性。此外,通过 javagent 或者 asm 等通过运行时对 Dubbo 的修改也在此范围内。此类修改大部分可以通过后文提供的扫描工具检测出来。</p> |
| <h3 id="2-spi-扩展">2. SPI 扩展</h3> |
| <h4 id="不兼容项">不兼容项</h4> |
| <p>对于 SPI 扩展的,除了应用级服务方向和 EventDispatcher 两个机制在 3.x 中做了破坏性的修改,在 2.7.x 中提供的绝大多数的扩展在 3.x 中也都提供。此部分需要关注的有两个方面:</p> |
| <ul> |
| <li>事件总线:出于事件管理的复杂度原因,EventDispatcher 和 EventListener 在 Dubbo 3.x 的支持已经删除。如果有对应扩展机制的使用请考虑重构为对应 Dubbo 功能的扩展。</li> |
| <li>应用级服务发现:Dubbo 2.7 中的应用级服务发现的整体机制在 Dubbo 3.x 中已经被完整重构,功能的性能与稳定性有了很大程度上的提高。因此我们建议您不要使用 Dubbo 2.7 中的应用级服务发现机制,如果有对应的扩展可以在升级到 Dubbo 3.x 之后基于新的代码重新验证实现(绝大多数应用级服务发现的 API 是向前兼容的)。</li> |
| </ul> |
| <h4 id="优化项可选">优化项(可选)</h4> |
| <p>此外,Dubbo 3.x 中对部分扩展点的工作机制进行了优化,可以较大程度上提升应用的性能。</p> |
| <ul> |
| <li>1)拦截器机制</li> |
| </ul> |
| <p>Dubbo 中可以基于 Filter 拦截器对请求进行拦截处理。在 Dubbo 2.7 中支持在路由选址后再对请求进行拦截处理。Dubbo 3.x 中抽象了全新的 ClusterFilter 机制,可以在很大程度上降低内存的占用,对与超大规模集群有较大的收益。 |
| 如果您有一些 Consumer 侧的拦截器是基于 Filter 机制实现的,如果没有和远端的 IP 地址强绑定的逻辑,我们建议您将对应的 <code>org.apache.dubbo.rpc.Filter</code> SPI 扩展点迁移到 <code>org.apache.dubbo.rpc.cluster.filter.ClusterFilter</code> 这个新的 SPI 扩展点。两个接口的方法定义是完全一样的。</p> |
| <ul> |
| <li>2)Router -&gt; StateRouter</li> |
| </ul> |
| <p>Dubbo 中提供了 Router 这个可以动态进行选址路由的能力,同时绝大多数的服务治理能力也都是基于这个 Router 扩展点实现的。在 Dubbo 3.x 中,Dubbo 在 Router 的基础上抽象了全新的 StateRouter 机制,可以在选址性能以及内存占用上有大幅优化。关于 StateRouter 的更多介绍我们会在后续的文档中发布。</p> |
| <h3 id="3-api--spring-使用">3. API / Spring 使用</h3> |
| <p>对于基于 API 或者 Spring 的使用,Dubbo 3.x 和 2.7.x 的使用方式是对齐的,在 Dubbo 3.x 中对部分无效的配置进行了强校验,这部分异常会在启动过程中直接报错,请按照提示修改即可。</p> |
| <h2 id="升级流程">升级流程</h2> |
| <h3 id="1-依赖升级">1. 依赖升级</h3> |
| <p>如果使用 Nacos 作为注册中心,由于 Nacos 特性支持的原因,在升级到 Dubbo 3.x 之前需要将 Nacos Server 升级到 2.x(参考文档 <a href="https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-upgrading.html">https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-upgrading.html</a>),然后再将应用的 Nacos Client 也对应升级。如果使用 Zookeeper 注册中心则不需要处理。 |
| 如果您是使用 Spring Cloud Alibaba Dubbo 进行接入的,由于 Dubbo 部分内部 API 进行了变更,请升级到 xxx。</p> |
| <p>Dubbo 依赖请升级到最新的 3.1.3 版本,Dubbo 和对应的 springboot starter GAV 如下所示。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>3.1.3<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-spring-boot-starter<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>3.1.3<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><h3 id="2-灰度升级">2. 灰度升级</h3> |
| <p>Dubbo 3 升级对于发布流程没有做特殊限制,按照正常业务发布即可。 |
| 由于 Dubbo 是进行跨大版本的变更升级,发布中请尽可能多分批次发布,同时拉大第一批和第二批发布的时间间隔,做好充足的观察。 |
| 发布过程中,我们建议您先升级应用的下游(也即是服务提供者),在验证服务处理正常以后再继续后续发布。</p> |
| <h3 id="3-升级观测指标">3. 升级观测指标</h3> |
| <p>在发布的过程中,有以下几个纬度的指标可以判断升级是否出现问题。</p> |
| <ul> |
| <li>机器的 CPU、内存使用情况</li> |
| <li>接口请求成功率</li> |
| <li>接口请求 RT</li> |
| <li>日志的报错信息</li> |
| <li>自定义扩展行为是否符合预期</li> |
| </ul> |
| <h2 id="注意事项">注意事项</h2> |
| <h3 id="1-应用级服务发现">1. 应用级服务发现</h3> |
| <p>由于 Dubbo 2.7 的应用级服务发现模型存在设计上的问题,在 Dubbo 3.x 中做了大量格式上的修改,所以 2.7.x 和 3.x 的应用级服务发现可能存在无法互相订阅调用的可能性。虽然 Dubbo 会剔除识别不了的实例,但是从稳定性的角度出发,如果您在 2.7.x 中开启了应用级服务发现特性(在 2.7.x 中非默认注册),我们建议先在 2.7.x 中关闭,待升级到 3.x 之后再开启。</p></description></item><item><title>Overview: 3.0 升级至 3.1</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide/</guid><description> |
| <h2 id="功能修改点">功能修改点</h2> |
| <h3 id="1-nacos-group-对齐应用级服务发现">1. Nacos Group 对齐(应用级服务发现)</h3> |
| <p>在 Dubbo 2.7.x 中,配置在 Nacos Registry URL 上的 group 值是对齐 Nacos 注册中心中的 group 分组的。(group 可以当成类似 namespace 的软隔离)</p> |
| <p>在 Dubbo 3.0.x 中,配置在 Nacos Registry URL 上的 group 默认不使用,全部使用 DEFAULT_GROUP。(group 不再提供隔离功能)</p> |
| <p>在 Dubbo 3.1.x 中,配置在 Nacos Registry URL 上的 group 值将会重新对齐 Nacos 注册中心中的 group 分组的。</p> |
| <p>注意事项:</p> |
| <ol> |
| <li>请检查注册中心 URL 上是否已经配置了 group 属性,如果是的话需要检查服务端和消费端的 group 是否都一致,如果不一致请修改为一致</li> |
| <li>如果不希望 group 重新对齐到 Nacos 注册中心中的 group 分组,可以配置 <code>dubbo.nacos-service-discovery.use-default-group=false</code> 全局属性值忽略该功能</li> |
| </ol></description></item><item><title>Overview: 3.1 升级至 3.2</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide/</guid><description> |
| <p>对于绝大多数的用户,升级到 Dubbo 3.2.0 是完全平滑的,仅需要修改依赖包版本即可。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>3.2.0<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><p>或者</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-spring-boot-starter<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>3.2.0<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><h1 id="兼容性-checklist">兼容性 CheckList</h1> |
| <h2 id="1-序列化检查模式重要">1. 序列化检查模式(重要!!!)</h2> |
| <p>在 Dubbo 3.2.0 版本中,Dubbo 将默认开启序列化白名单的强校验,以提升 Dubbo 的安全性,避免远程命令执行的问题。 |
| 对于一些使用了泛型等可能存在扫描不全或者是<strong>服务规模较大</strong>的用户,我们建议您添加 <code>-Ddubbo.application.serialize-check-status=WARN</code> 配置。 |
| 观察一段时间后(通过日志、QoS 命令),如果没有触发安全告警,则可以配置强校验模式。</p> |
| <p>关于自定义白名单的配置,可以参考官网的 <a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/">文档 / SDK 手册 / Java SDK / 高级特性和用法 / 提升安全性 / 类检查机制</a> 一文进行配置。</p> |
| <h4 id="q1为什么要开启序列化白名单的强校验">Q1:为什么要开启序列化白名单的强校验?</h4> |
| <p>由于 Java 本身机制的问题,Dubbo 支持的非 IDL 序列化天然允许访问任意类,这将可能导致远程命令执行(RCE)风险。</p> |
| <h4 id="q2升级到-32-的最佳实践是什么">Q2:升级到 3.2 的最佳实践是什么?</h4> |
| <p>我们建议<strong>所有用户</strong>在升级 Dubbo 3.2.0 版本前添加 <code>-Ddubbo.application.serialize-check-status=WARN</code> 配置以保证最佳的兼容性。否则可能导致线上数据异常的情况!</p> |
| <hr> |
| <h2 id="2-默认序列化切换">2. 默认序列化切换</h2> |
| <p>Dubbo 3.2.0 版本开始默认序列化方式从 <code>hessian2</code> 切换为 <code>fastjson2</code>,对于升级到 3.2.0 的应用,Dubbo 会自动尝试采用 <code>fastjson2</code> 进行序列化。</p> |
| <h4 id="q1会不会影响和低版本的-dubbo-互通">Q1:会不会影响和低版本的 Dubbo 互通?</h4> |
| <p>不会。与低版本互通仍使用 <code>hessian-lite</code>。原理可参考<a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/">序列化协议升级指南</a>一文。</p> |
| <h4 id="q2为什么要切换默认序列化方式">Q2:为什么要切换默认序列化方式?</h4> |
| <p><code>fastjson2</code> 是一款高性能的序列化框架,性能优于 <code>hessian2</code>,原生支持 JDK17、Native 等,以及完全向前兼容 <code>hessian2</code> 所有功能。 |
| 由于 <code>hessian-lite</code> 在未来维护难度越来越大,我们决定将默认序列化方式从 <code>hessian2</code> 切换为 <code>fastjson2</code>。</p> |
| <h4 id="q3和原生的-json-是什么关系">Q3:和原生的 JSON 是什么关系?</h4> |
| <p>Dubbo 中使用 <code>fastjson2</code> 的 JSONB 格式,而不是原生的 JSON 格式。JSONB 格式和JSON格式对应,能完全表示JSON,是一种二进制格式。 |
| 具体协议格式可以参考:<a href="https://github.com/alibaba/fastjson2/wiki/jsonb_format_cn">JSONB 格式</a></p> |
| <h4 id="q4如果我不想使用-fastjson2怎么办">Q4:如果我不想使用 <code>fastjson2</code>,怎么办?</h4> |
| <p>如果你不想使用 <code>fastjson2</code>,可以配置 <code>prefer-serialization</code> 为 <code>hessian2</code> 覆盖默认配置。(如 <code>dubbo.provider.prefer-serialization=fastjson2,hessian2</code>) 如果没有特殊的需求,我们不建议仍继续使用 <code>hessian2</code>。</p> |
| <hr> |
| <h2 id="3-默认关闭推空保护">3. 默认关闭推空保护</h2> |
| <p>Dubbo 3.2.0 版本开始默认关闭推空保护,即使注册中心推送空地址,Dubbo 也将不会保留最后一批 provider 信息。 |
| 如果需要开启推空保护,可以配置 <code>dubbo.application.enable-empty-protection</code> 为 <code>true</code>。</p> |
| <h4 id="q1关闭推空保护对我有什么影响">Q1:关闭推空保护对我有什么影响?</h4> |
| <p>在绝大部分场景下没有影响。 |
| 推空保护的目的是在注册中心出现故障并且主动推送空地址的时候,Dubbo 保留最后一批 provider 信息,以保证服务可用。 |
| 但是在大多数注册中心出现故障的时候,注册中心也不会推送空地址,只有一些特殊情况才会出现。 |
| 但如果开启推空保护,将对 Dubbo 的 Fallback 逻辑、心跳逻辑等造成较大的影响,给开发使用 Dubbo 带来困扰。</p> |
| <h4 id="q2我想开启推空保护怎么办">Q2:我想开启推空保护,怎么办?</h4> |
| <p>如果在生产上为了高可用,需要开启推空保护,可以配置 <code>dubbo.application.enable-empty-protection</code> 为 <code>true</code>。 |
| 目前已知开启推空保护会导致服务端应用从 <code>2.6.x</code>、<code>2.7.x</code> 等仅支持接口级服务发现的版本升级到 <code>3.x</code> 之后回滚到原来版本出现异常,极端场景下会导致服务调用失败。 |
| 此外,开启推空保护后在服务端地址真的为空的时候出现较多的心跳异常、日志异常等。</p> |
| <hr> |
| <h2 id="4-传递依赖变更">4. 传递依赖变更</h2> |
| <ul> |
| <li>Dubbo 3.2.0 版本开始默认不再在 <code>dubbo-all</code> 中 shade <code>hessian-lite</code> 的代码,而是使用传递依赖传递。如果你的应用中不需要使用 <code>hessian-lite</code>,可以将 <code>hessian-lite</code> 从依赖中移除。</li> |
| <li>Dubbo 3.2.0 版本开始在 <code>dubbo-all</code> 中不再传递 <code>gson</code>、<code>fastjson</code> 依赖,如果你的应用中需要使用 <code>gson</code>、<code>fastjson</code>,请手动将 <code>gson</code>、<code>fastjson</code> 依赖添加到应用中。</li> |
| <li>Dubbo 3.2.0 版本在 <code>dubbo-all</code> 中传递 <code>fastjson2</code> 依赖。</li> |
| </ul> |
| <hr> |
| <h2 id="5-默认内部序列化工具切换">5. 默认内部序列化工具切换</h2> |
| <p>Dubbo 3.2.0 版本开始默认<strong>内部</strong>序列化工具从 <code>fastjson</code> 切换为 <code>fastjson2</code>。</p> |
| <h4 id="q1会不会影响-rpc-请求流量">Q1:会不会影响 RPC 请求流量?</h4> |
| <p>不会。内部序列化工具为 Dubbo 内部解析参数时使用,非 RPC 传输序列化协议。</p> |
| <h4 id="q2为什么要切换默认内部序列化工具">Q2:为什么要切换默认内部序列化工具?</h4> |
| <p>Dubbo 3.2.0 版本开始默认传递依赖不再传递 <code>fastjson</code> 和 <code>gson</code>。出于兼容性考虑,默认内部序列化工具切换为 <code>fastjson2</code>。</p> |
| <h4 id="q3如果我的环境中没有-fastjson2怎么办">Q3:如果我的环境中没有 <code>fastjson2</code>,怎么办?</h4> |
| <p>Dubbo 支持多种序列化框架自动切换,如果你的环境中没有 <code>fastjson2</code>,Dubbo 会自动尝试切换到 <code>fastsjon</code> 或 <code>gson</code>。</p> |
| <h4 id="q4我想指定-dubbo-内部序列化工具怎么办">Q4:我想指定 Dubbo 内部序列化工具,怎么办?</h4> |
| <p>可以配置 <code>dubbo.json-framework.prefer</code> 参数,如 <code>-Ddubbo.json-framework.prefer=gson</code>。</p> |
| <hr> |
| <h2 id="6-triple-协议支持传递自定义异常">6. Triple 协议支持传递自定义异常</h2> |
| <p>Dubbo 3.2.0 版本开始 Triple 协议支持回传自定义异常,而不是只能回传 <code>RpcException</code>。如果服务接口会抛出异常的,在 Dubbo 3.2.0 版本以后将默认按照 Dubbo 协议一样回传自定义异常对象。</p> |
| <hr> |
| <h2 id="7-triple-协议版本号对齐">7. Triple 协议版本号对齐</h2> |
| <p>Dubbo 3.2.0 版本开始,Triple 协议的通信要求客户端和服务端的版本号和分组一致,否则会找不到服务。与原生 gRPC SDK 互通时,Dubbo 侧不能配置分组和版本号。</p> |
| <h4 id="q1dubbo-320-以前是怎么样的">Q1:Dubbo 3.2.0 以前是怎么样的?</h4> |
| <p>1)Triple 会认为空版本号和 1.0.0 版本号一致,如果您的服务端和客户端版本号不一致,但是都是空版本号或者都是 1.0.0 版本号,是可以正常通信的。 |
| 2)对于没有匹配到版本号的服务,Triple 会尝试匹配任意版本号的服务,如果匹配到任意版本号的服务,也是可以正常通信的。</p> |
| <h4 id="q2如何保证和原来行为是对齐的">Q2:如何保证和原来行为是对齐的?</h4> |
| <p>通过配置 <code>-Ddubbo.rpc.tri.ignore-1.0.0-version=true -Ddubbo.rpc.tri.resolve-fallback-to-default=true</code> 可以实现和 Dubbo 3.2.0 以前的行为。</p></description></item><item><title>Overview: 3.2 升级至 3.3</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/3.2-to-3.3-compatibility-guide/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/3.2-to-3.3-compatibility-guide/</guid><description> |
| <h2 id="功能修改点">功能修改点</h2> |
| <h3 id="1-移除了dubbo-native-plugin">1. 移除了dubbo-native-plugin</h3> |
| <p>在 3.3 版本中,移除了 dubbo-native-plugin。并且dubbo-native-plugin相关的功能都将迁移至dubbo-maven-plugin。</p> |
| <p>为什么要做这个迁移和调整?</p> |
| <ol> |
| <li>为了提升用户的使用体验,后续dubbo有关maven的插件能力都将统一使用dubbo-maven-plugin来提供。方便Dubbo用户使用和接入。而不需要一个特性对应一个插件,导致用户需要依赖多个plugin。</li> |
| <li>更加有利于后续Dubbo提供maven plugin能力时的维护和特性增强。</li> |
| </ol></description></item><item><title>Overview: 应用级服务发现</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/</guid><description/></item><item><title>Overview: 序列化协议升级</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/</guid><description> |
| <p>在 <code>3.1.0</code> 版本中,Dubbo 默认支持的序列化协议新增对 Fastjson2 的支持。部分用户可能会考虑在现有的系统中对序列化协议进行升级,但服务端和客户端版本的差异可能导致客户端并不支持服务端的序列化协议。</p> |
| <p>在 <code>3.2.0</code> 版本中, Dubbo 的服务端引入新的配置 <code>prefer-serialization</code>,该特性可以完美解决服务端序列化升级过程中可能带来的风险。</p> |
| <h3 id="最佳实践">最佳实践</h3> |
| <p>序列化协议升级,需要分两步走:</p> |
| <ul> |
| <li><strong>首先需要推动服务端的序列化协议升级,同时在服务端的暴露配置中需要添加 <code>prefer-serialization</code> 配置。</strong></li> |
| </ul> |
| <blockquote> |
| <p>比如:升级前的序列化协议是 hessian2,升级之后的序列化协议是 Fastjson2 那么在服务端的暴露配置中就应该添加如下所示的配置。</p> |
| </blockquote> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>dubbo.provider.prefer-serialization=fastjson2,hessian2 |
| </span></span><span style="display:flex;"><span>dubbo.provider.serialization=hessian2 |
| </span></span></code></pre></div><ul> |
| <li><strong>其次,客户端需要升级至和服务端相同版本</strong></li> |
| </ul> |
| <h3 id="实现原理">实现原理</h3> |
| <p>dubbo 客户端序列化协议是根据服务端的注册配置来选择的(即服务端的<code>serialization</code>配置)。在请求阶段 dubbo 会把客户端的序列化协议组装到请求头上,服务端在进行反序列化时会根据请求头来确定反序列化协议。所以,如果服务端和客户端的版本不一致就可能会出现客户端序列化不了的情况。</p> |
| <p>为了解决这个情况,<code>3.2.0</code> 在客户端序列化的时候会优先使用 <code>prefer-serialization</code> 配置的协议,如果不支持 <code>prefer-serialization</code> 相关的协议,才会使用 <code>serialization</code> 配置的协议。(可以把 <code>serialization</code> 理解为一个兜底的配置)</p></description></item><item><title>Overview: Protobuf 与 Interface</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/protobufinterface/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/protobufinterface/</guid><description> |
| <p>本文对比了Protobuf和Interface这2种IDL的差异,帮助Dubbo协议开发者了解Protobuf,为后续转到Triple协议和Grpc协议做铺垫。</p> |
| <h2 id="1-数据类型">1. 数据类型</h2> |
| <h3 id="11-基本类型">1.1. 基本类型</h3> |
| <table> |
| <thead> |
| <tr> |
| <th>ptoto类型</th> |
| <th>java类型</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>double</td> |
| <td>double</td> |
| </tr> |
| <tr> |
| <td>float</td> |
| <td>float</td> |
| </tr> |
| <tr> |
| <td>int32</td> |
| <td>int</td> |
| </tr> |
| <tr> |
| <td>int64</td> |
| <td>long</td> |
| </tr> |
| <tr> |
| <td>uint32</td> |
| <td>int[注]</td> |
| </tr> |
| <tr> |
| <td>uint64</td> |
| <td>long[注]</td> |
| </tr> |
| <tr> |
| <td>sint32</td> |
| <td>int</td> |
| </tr> |
| <tr> |
| <td>sint64</td> |
| <td>long</td> |
| </tr> |
| <tr> |
| <td>fixed32</td> |
| <td>int[注]</td> |
| </tr> |
| <tr> |
| <td>fixed64</td> |
| <td>long[注]</td> |
| </tr> |
| <tr> |
| <td>sfixed32</td> |
| <td>int</td> |
| </tr> |
| <tr> |
| <td>sfixed64</td> |
| <td>long</td> |
| </tr> |
| <tr> |
| <td>bool</td> |
| <td>boolean</td> |
| </tr> |
| <tr> |
| <td>string</td> |
| <td>String</td> |
| </tr> |
| <tr> |
| <td>bytes</td> |
| <td>ByteString</td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">注意</h4> |
| 在Java中,无符号的32位和64位整数使用它们的有符号对数来表示,顶部位只存储在符号位中。 |
| </div> |
| <h2 id="2-复合类型">2. 复合类型</h2> |
| <h3 id="21-枚举">2.1. 枚举</h3> |
| <ul> |
| <li>原始pb代码</li> |
| </ul> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span><span style="color:#719e07">enum</span> TrafficLightColor { |
| </span></span><span style="display:flex;"><span> TRAFFIC_LIGHT_COLOR_INVALID <span style="color:#719e07">=</span> <span style="color:#2aa198">0</span>; |
| </span></span><span style="display:flex;"><span> TRAFFIC_LIGHT_COLOR_UNSET <span style="color:#719e07">=</span> <span style="color:#2aa198">1</span>; |
| </span></span><span style="display:flex;"><span> TRAFFIC_LIGHT_COLOR_GREEN <span style="color:#719e07">=</span> <span style="color:#2aa198">2</span>; |
| </span></span><span style="display:flex;"><span> TRAFFIC_LIGHT_COLOR_YELLOW <span style="color:#719e07">=</span> <span style="color:#2aa198">3</span>; |
| </span></span><span style="display:flex;"><span> TRAFFIC_LIGHT_COLOR_RED <span style="color:#719e07">=</span> <span style="color:#2aa198">4</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ul> |
| <li>生成的java代码</li> |
| </ul> |
| <p><img src="https://dubbo.apache.org/imgs/docs/advanced/protobufinterface/124234531-b96c2c80-db46-11eb-8155-a77dbe059f07.png" alt="image"></p> |
| <blockquote> |
| <p>枚举是常量,因此采用大写</p> |
| </blockquote> |
| <h3 id="22-数组">2.2. 数组</h3> |
| <ul> |
| <li>原始pb代码</li> |
| </ul> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>message VipIDToRidReq { |
| </span></span><span style="display:flex;"><span> repeated uint32 vipID <span style="color:#719e07">=</span> 1; |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ul> |
| <li>生成的java代码</li> |
| </ul> |
| <p><img src="https://dubbo.apache.org/imgs/docs/advanced/protobufinterface/124234564-c4bf5800-db46-11eb-94fc-a056af6089cb.png" alt="image"></p> |
| <blockquote> |
| <p>底层实际上是1个ArrayList</p> |
| </blockquote> |
| <h3 id="23-集合">2.3. 集合</h3> |
| <p>PB不支持无序、不重复的集合,只能 <code>借用数组实现</code>,需要 <code>自行去重</code>。</p> |
| <h3 id="24-字典">2.4. 字典</h3> |
| <ul> |
| <li>原始pb代码</li> |
| </ul> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>message BatchOnlineRes { |
| </span></span><span style="display:flex;"><span> map<span style="color:#719e07">&lt;</span>uint32, uint32<span style="color:#719e07">&gt;</span> onlineMap <span style="color:#719e07">=</span> 1;<span style="color:#586e75">//在线状态</span> |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ul> |
| <li>生成的java代码</li> |
| </ul> |
| <p><img src="https://dubbo.apache.org/imgs/docs/advanced/protobufinterface/124234654-e4568080-db46-11eb-9700-b30022ebee21.png" alt="image"></p> |
| <h3 id="25-嵌套">2.5. 嵌套</h3> |
| <ul> |
| <li>原始pb代码</li> |
| </ul> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>message BatchAnchorInfoRes { |
| </span></span><span style="display:flex;"><span> map<span style="color:#719e07">&lt;</span>uint32, AnchorInfo<span style="color:#719e07">&gt;</span> list <span style="color:#719e07">=</span> 1; <span style="color:#586e75">//用户信息map列表</span> |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">/* |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75">* 对应接口的功能: 批量或单个获取用户信息 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75">*/</span> |
| </span></span><span style="display:flex;"><span>message AnchorInfo { |
| </span></span><span style="display:flex;"><span> uint32 ownerUid <span style="color:#719e07">=</span> 1 <span style="color:#719e07">[</span>json_name<span style="color:#719e07">=</span><span style="color:#2aa198">&#34;uid&#34;</span><span style="color:#719e07">]</span>; <span style="color:#586e75">//用户id</span> |
| </span></span><span style="display:flex;"><span> string nickName <span style="color:#719e07">=</span> 2 <span style="color:#719e07">[</span>json_name<span style="color:#719e07">=</span><span style="color:#2aa198">&#34;nn&#34;</span><span style="color:#719e07">]</span>; <span style="color:#586e75">//用户昵称</span> |
| </span></span><span style="display:flex;"><span> string smallAvatar <span style="color:#719e07">=</span> 3 <span style="color:#719e07">[</span>json_name<span style="color:#719e07">=</span><span style="color:#2aa198">&#34;savt&#34;</span><span style="color:#719e07">]</span>; <span style="color:#586e75">//用户头像全路径-小</span> |
| </span></span><span style="display:flex;"><span> string middleAvatar <span style="color:#719e07">=</span> 4 <span style="color:#719e07">[</span>json_name<span style="color:#719e07">=</span><span style="color:#2aa198">&#34;mavt&#34;</span><span style="color:#719e07">]</span>; <span style="color:#586e75">//用户头像全路径-中</span> |
| </span></span><span style="display:flex;"><span> string bigAvatar <span style="color:#719e07">=</span> 5 <span style="color:#719e07">[</span>json_name<span style="color:#719e07">=</span><span style="color:#2aa198">&#34;bavt&#34;</span><span style="color:#719e07">]</span>; <span style="color:#586e75">//用户头像全路径-大</span> |
| </span></span><span style="display:flex;"><span> string avatar <span style="color:#719e07">=</span> 6 <span style="color:#719e07">[</span>json_name<span style="color:#719e07">=</span><span style="color:#2aa198">&#34;avt&#34;</span><span style="color:#719e07">]</span>; <span style="color:#586e75">//用户头像</span> |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ul> |
| <li>生成的java代码</li> |
| </ul> |
| <p><img src="https://dubbo.apache.org/imgs/docs/advanced/protobufinterface/124234723-f89a7d80-db46-11eb-82d0-a8aee5322098.png" alt="image"></p> |
| <h2 id="3-字段默认值">3. 字段默认值</h2> |
| <ul> |
| <li>对于字符串,默认值为空字符串。</li> |
| <li>对于字节,默认值为空字节。</li> |
| <li>对于bools,默认值为false。</li> |
| <li>对于数字类型,默认值为零。</li> |
| <li>对于枚举,默认值为第一个定义的枚举值,它必须为0。</li> |
| <li>对于消息字段,未设置字段。 它的确切值是语言相关的。 有关详细信息,请参阅生成的代码指南。</li> |
| </ul> |
| <h2 id="4-整体结构">4. 整体结构</h2> |
| <table> |
| <thead> |
| <tr> |
| <th>Feature</th> |
| <th>Java Interface</th> |
| <th>Protobuf</th> |
| <th>备注</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>方法重载</td> |
| <td>√</td> |
| <td>×</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>泛型/模板化</td> |
| <td>√</td> |
| <td>×</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>方法继承</td> |
| <td>√</td> |
| <td>×</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>嵌套定义</td> |
| <td>√</td> |
| <td>部分支持</td> |
| <td>PB仅支持message和enum嵌套</td> |
| </tr> |
| <tr> |
| <td>import文件</td> |
| <td>√</td> |
| <td>√</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>字段为null</td> |
| <td>√</td> |
| <td>×</td> |
| <td></td> |
| </tr> |
| <tr> |
| <td>多个入参</td> |
| <td>√</td> |
| <td>×</td> |
| <td>PB仅支持单入参</td> |
| </tr> |
| <tr> |
| <td>0个入参</td> |
| <td>√</td> |
| <td>×</td> |
| <td>PB必须有入参</td> |
| </tr> |
| <tr> |
| <td>0个出参</td> |
| <td>√</td> |
| <td>×</td> |
| <td>PB必须有出参</td> |
| </tr> |
| <tr> |
| <td>入参/出参为抽象类</td> |
| <td>√</td> |
| <td>×</td> |
| <td>PB的入参/出参必须为具象类</td> |
| </tr> |
| <tr> |
| <td>入参/出参为接口</td> |
| <td>√</td> |
| <td>×</td> |
| <td>PB的入参/出参必须为具象类</td> |
| </tr> |
| <tr> |
| <td>入参/出参为基础类型</td> |
| <td>√</td> |
| <td>×</td> |
| <td>PB的入参/出参必须为结构体</td> |
| </tr> |
| </tbody> |
| </table> |
| <h2 id="5-社区资料">5. 社区资料</h2> |
| <ul> |
| <li>社区主页地址:https://developers.google.cn/protocol-buffers/</li> |
| <li>社区开源地址:https://github.com/google/protobuf</li> |
| <li>相关jar的maven:https://search.maven.org/search?q=com.google.protobuf</li> |
| </ul></description></item><item><title>Overview: Dubbo 协议迁移至 Triple 协议</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/</guid><description> |
| <h2 id="triple-协议介绍">Triple 协议介绍</h2> |
| <p>根据 Triple 设计的目标,<code>Triple</code> 协议有以下优势:</p> |
| <ul> |
| <li>具备跨语言交互的能力,传统的多语言多 SDK 模式和 Mesh 化跨语言模式都需要一种更通用易扩展的数据传输协议。</li> |
| <li>提供更完善的请求模型,除了支持传统的 Request/Response 模型(Unary 单向通信),还支持 Stream(流式通信) 和 Bidirectional(双向通信)。</li> |
| <li>易扩展、穿透性高,包括但不限于 Tracing / Monitoring 等支持,也应该能被各层设备识别,网关设施等可以识别数据报文,对 Service Mesh 部署友好,降低用户理解难度。</li> |
| <li>完全兼容 grpc,客户端/服务端可以与原生grpc客户端打通。</li> |
| <li>可以复用现有 grpc 生态下的组件, 满足云原生场景下的跨语言、跨环境、跨平台的互通需求。</li> |
| </ul> |
| <p>当前使用其他协议的 Dubbo 用户,框架提供了兼容现有序列化方式的迁移能力,在不影响线上已有业务的前提下,迁移协议的成本几乎为零。</p> |
| <p>需要新增对接 Grpc 服务的 Dubbo 用户,可以直接使用 Triple 协议来实现打通,不需要单独引入 grpc client 来完成,不仅能保留已有的 Dubbo 易用性,也能降低程序的复杂度和开发运维成本,不需要额外进行适配和开发即可接入现有生态。</p> |
| <p>对于需要网关接入的 Dubbo 用户,Triple 协议提供了更加原生的方式,让网关开发或者使用开源的 grpc 网关组件更加简单。网关可以选择不解析 payload ,在性能上也有很大提高。在使用 Dubbo 协议时,语言相关的序列化方式是网关的一个很大痛点,而传统的 HTTP 转 Dubbo 的方式对于跨语言序列化几乎是无能为力的。同时,由于 Triple 的协议元数据都存储在请求头中,网关可以轻松的实现定制需求,如路由和限流等功能。</p> |
| <blockquote> |
| <p><code>Triple</code> 协议的格式和原理请参阅 <a href="https://dubbo.apache.org/zh-cn/docs/concepts/rpc-protocol/">RPC 通信协议</a></p> |
| </blockquote> |
| <h2 id="dubbo2-协议迁移流程">Dubbo2 协议迁移流程</h2> |
| <p>Dubbo2 的用户使用 dubbo 协议 + 自定义序列化,如 hessian2 完成远程调用。</p> |
| <p>而 Grpc 的默认仅支持 Protobuf 序列化,对于 Java 语言中的多参数以及方法重载也无法支持。</p> |
| <p>Dubbo3的之初就有一条目标是完美兼容 Dubbo2,所以为了 Dubbo2 能够平滑升级, Dubbo 框架侧做了很多工作来保证升级的无感,目前默认的序列化和 Dubbo2 保持一致为<code>hessian2</code>。</p> |
| <p>所以,如果决定要升级到 Dubbo3 的 <code>Triple</code> 协议,只需要修改配置中的协议名称为 <code>tri</code> (注意: 不是triple)即可。</p> |
| <p>接下来我们我们以一个使用 Dubbo2 协议的<a href="https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration">工程</a> 来举例,如何一步一步安全的升级。</p> |
| <ol> |
| <li>仅使用 <code>dubbo</code> 协议启动 <code>provider</code> 和 <code>consumer</code>,并完成调用。</li> |
| <li>使用 <code>dubbo</code> 和 <code>tri</code> 协议 启动<code>provider</code>,以 <code>dubbo</code> 协议启动 <code>consumer</code>,并完成调用。</li> |
| <li>仅使用 <code>tri</code> 协议 启动 <code>provider</code>和 <code>consumer</code>,并完成调用。</li> |
| </ol> |
| <h3 id="定义服务">定义服务</h3> |
| <ol> |
| <li>定义接口</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">IWrapperGreeter</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//... </span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * 这是一个普通接口,没有使用 pb 序列化 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span> String <span style="color:#268bd2">sayHello</span>(String request); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ol start="2"> |
| <li>实现类如下</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">IGreeter2Impl</span> <span style="color:#268bd2">implements</span> IWrapperGreeter { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayHello</span>(String request) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;hello,&#34;</span> <span style="color:#719e07">+</span> request; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="仅使用-triple-协议">仅使用 triple 协议</h3> |
| <p>当所有的 consuemr 都升级至支持 <code>Triple</code> 协议的版本后,provider 可切换至仅使用 <code>Triple</code> 协议启动</p> |
| <p>结构如图所示: |
| <img src="https://dubbo.apache.org/imgs/v3/migration/tri/migrate-only-tri-strust.png" alt="strust"></p> |
| <p><a href="https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriProvider.java">Provider</a> |
| 和 <a href="https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriConsumer.java">Consumer</a> 完成调用,输出如下:</p> |
| <p><img src="https://dubbo.apache.org/imgs/v3/migration/tri/dubbo3-tri-migration-tri-tri-result.png" alt="result"></p> |
| <h3 id="仅使用-dubbo-协议">仅使用 dubbo 协议</h3> |
| <p>为保证兼容性,我们先将部分 provider 升级到 <code>dubbo3</code> 版本并使用 <code>dubbo</code> 协议。</p> |
| <p>使用 <code>dubbo</code> 协议启动一个 <a href="https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboProvider.java"><code>Provider</code></a> 和 <a href="https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboConsumer.java"><code>Consumer</code></a> ,完成调用,输出如下: |
| <img src="https://dubbo.apache.org/imgs/v3/migration/tri/dubbo3-tri-migration-dubbo-dubbo-result.png" alt="result"></p> |
| <h3 id="同时使用两协议">同时使用两协议</h3> |
| <p>对于线上服务的升级,不可能一蹴而就同时完成 provider 和 consumer 升级, 需要按步操作,保证业务稳定。 |
| 第二步, provider 提供双协议的方式同时支持 dubbo + tri 两种协议的客户端。</p> |
| <p>结构如图所示: |
| <img src="https://dubbo.apache.org/imgs/v3/migration/tri/migrate-dubbo-tri-strust.png" alt="strust"></p> |
| <blockquote> |
| <p>按照推荐升级步骤,provider 已经支持了tri协议,所以 dubbo3的 consumer 可以直接使用 tri 协议</p> |
| </blockquote> |
| <p>使用<code>dubbo</code>协议和<code>triple</code>协议启动<a href="https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothProvider.java"><code>Provider</code></a>和<a href="https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothConsumer.java"><code>Consumer</code></a>,完成调用,输出如下:</p> |
| <p><img src="https://dubbo.apache.org/imgs/v3/migration/tri/dubbo3-tri-migration-both-dubbo-tri-result.png" alt="result"></p> |
| <h3 id="实现原理">实现原理</h3> |
| <p>通过上面介绍的升级过程,我们可以很简单的通过修改协议类型来完成升级。框架是怎么帮我们做到这些的呢?</p> |
| <p>通过对 <code>Triple</code> 协议的介绍,我们知道Dubbo3的 <code>Triple</code> 的数据类型是 <code>protobuf</code> 对象,那为什么非 <code>protobuf</code> 的 java 对象也可以被正常传输呢。</p> |
| <p>这里 Dubbo3 使用了一个巧妙的设计,首先判断参数类型是否为 <code>protobuf</code> 对象,如果不是。用一个 <code>protobuf</code> 对象将 <code>request</code> 和 <code>response</code> 进行 wrapper,这样就屏蔽了其他各种序列化带来的复杂度。在 <code>wrapper</code> 对象内部声明序列化类型,来支持序列化的扩展。</p> |
| <p>wrapper 的<code>protobuf</code>的 IDL如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-proto" data-lang="proto"><span style="display:flex;"><span>syntax <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;proto3&#34;</span>; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">package</span> org<span style="color:#719e07">.</span>apache.dubbo.triple; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">message</span> <span style="color:#268bd2">TripleRequestWrapper</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// hessian4 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span> <span style="color:#586e75">// json |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span> <span style="color:#dc322f">string</span> serializeType <span style="color:#719e07">=</span> <span style="color:#2aa198">1</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">repeated</span> <span style="color:#dc322f">bytes</span> args <span style="color:#719e07">=</span> <span style="color:#2aa198">2</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">repeated</span> <span style="color:#dc322f">string</span> argTypes <span style="color:#719e07">=</span> <span style="color:#2aa198">3</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">message</span> <span style="color:#268bd2">TripleResponseWrapper</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">string</span> serializeType <span style="color:#719e07">=</span> <span style="color:#2aa198">1</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">bytes</span> data <span style="color:#719e07">=</span> <span style="color:#2aa198">2</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">string</span> type <span style="color:#719e07">=</span> <span style="color:#2aa198">3</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>对于请求,使用<code>TripleRequestWrapper</code>进行包装,对于响应使用<code>TripleResponseWrapper</code>进行包装。</p> |
| <blockquote> |
| <p>对于请求参数,可以看到 args 被<code>repeated</code>修饰,这是因为需要支持 java 方法的多个参数。当然,序列化只能是一种。序列化的实现沿用 Dubbo2 实现的 spi</p> |
| </blockquote> |
| <h2 id="多语言用户">多语言用户</h2> |
| <p>使用 <code>protobuf</code> 建议新服务均使用该方式,对于 Dubbo3 和 Triple 来说,主推的是使用 <code>protobuf</code> 序列化,并且使用 <code>proto</code> 定义的 <code>IDL</code> 来生成相关接口定义。以 <code>IDL</code> 做为多语言中的通用接口约定,加上 <code>Triple</code> 与 <code>Grpc</code> 的天然互通性,可以轻松地实现跨语言交互,例如 Go 语言等。</p> |
| <p>将编写好的 <code>.proto</code> 文件使用 <code>dubbo-compiler</code> 插件进行编译并编写实现类,完成方法调用:</p> |
| <p><img src="https://dubbo.apache.org/imgs/v3/migration/tri/dubbo3-tri-migration-tri-tri-result.png" alt="result"></p> |
| <p>从上面升级的例子我们可以知道,<code>Triple</code> 协议使用 <code>protbuf</code> 对象序列化后进行传输,所以对于本身就是 <code>protobuf</code> 对象的方法来说,没有任何其他逻辑。</p> |
| <p>使用 <code>protobuf</code> 插件编译后接口如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">PbGreeter</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> String JAVA_SERVICE_NAME <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;org.apache.dubbo.sample.tri.PbGreeter&#34;</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> String SERVICE_NAME <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;org.apache.dubbo.sample.tri.PbGreeter&#34;</span>; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> <span style="color:#dc322f">boolean</span> inited <span style="color:#719e07">=</span> PbGreeterDubbo.init(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> org.apache.dubbo.sample.tri.GreeterReply <span style="color:#268bd2">greet</span>(org.apache.dubbo.sample.tri.GreeterRequest request); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">default</span> CompletableFuture<span style="color:#719e07">&lt;</span>org.apache.dubbo.sample.tri.GreeterReply<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">greetAsync</span>(org.apache.dubbo.sample.tri.GreeterRequest request){ |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> CompletableFuture.supplyAsync(() <span style="color:#719e07">-&gt;</span> greet(request)); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">greetServerStream</span>(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver<span style="color:#719e07">&lt;</span>org.apache.dubbo.sample.tri.GreeterReply<span style="color:#719e07">&gt;</span> responseObserver); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> org.apache.dubbo.common.stream.StreamObserver<span style="color:#719e07">&lt;</span>org.apache.dubbo.sample.tri.GreeterRequest<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">greetStream</span>(org.apache.dubbo.common.stream.StreamObserver<span style="color:#719e07">&lt;</span>org.apache.dubbo.sample.tri.GreeterReply<span style="color:#719e07">&gt;</span> responseObserver); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h2 id="triple-新特性-stream-流">Triple 新特性 Stream 流</h2> |
| <p>Stream 是 Dubbo3 新提供的一种调用类型,在以下场景时建议使用流的方式:</p> |
| <ul> |
| <li>接口需要发送大量数据,这些数据无法被放在一个 RPC 的请求或响应中,需要分批发送,但应用层如果按照传统的多次 RPC 方式无法解决顺序和性能的问题,如果需要保证有序,则只能串行发送</li> |
| <li>流式场景,数据需要按照发送顺序处理, 数据本身是没有确定边界的</li> |
| <li>推送类场景,多个消息在同一个调用的上下文中被发送和处理</li> |
| </ul> |
| <p>Stream 分为以下三种:</p> |
| <ul> |
| <li>SERVER_STREAM(服务端流) |
| <img src="https://dubbo.apache.org/imgs/v3/migration/tri/migrate-server-stream.png" alt="SERVER_STREAM"></li> |
| <li>CLIENT_STREAM(客户端流) |
| <img src="https://dubbo.apache.org/imgs/v3/migration/tri/migrate-client-stream.png" alt="CLIENT_STREAM"></li> |
| <li>BIDIRECTIONAL_STREAM(双向流) |
| <img src="https://dubbo.apache.org/imgs/v3/migration/tri/migrate-bi-stream.png" alt="BIDIRECTIONAL_STREAM"></li> |
| </ul> |
| <blockquote> |
| <p>由于 <code>java</code> 语言的限制,BIDIRECTIONAL_STREAM 和 CLIENT_STREAM 的实现是一样的。</p> |
| </blockquote> |
| <p>在 Dubbo3 中,流式接口以 <code>SteamObserver</code> 声明和使用,用户可以通过使用和实现这个接口来发送和处理流的数据、异常和结束。</p> |
| <blockquote> |
| <p>对于 Dubbo2 用户来说,可能会对StreamObserver感到陌生,这是Dubbo3定义的一种流类型,Dubbo2 中并不存在 Stream 的类型,所以对于迁移场景没有任何影响。</p> |
| </blockquote> |
| <p>流的语义保证</p> |
| <ul> |
| <li>提供消息边界,可以方便地对消息单独处理</li> |
| <li>严格有序,发送端的顺序和接收端顺序一致</li> |
| <li>全双工,发送不需要等待</li> |
| <li>支持取消和超时</li> |
| </ul> |
| <h2 id="非-pb-序列化的流">非 PB 序列化的流</h2> |
| <ol> |
| <li>api</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">IWrapperGreeter</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHelloStream</span>(StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> response); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">sayHelloServerStream</span>(String request, StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> response); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><blockquote> |
| <p>Stream 方法的方法入参和返回值是严格约定的,为防止写错而导致问题,Dubbo3 框架侧做了对参数的检查, 如果出错则会抛出异常。 |
| 对于 <code>双向流(BIDIRECTIONAL_STREAM)</code>, 需要注意参数中的 <code>StreamObserver</code> 是响应流,返回参数中的 <code>StreamObserver</code> 为请求流。</p> |
| </blockquote> |
| <ol start="2"> |
| <li>实现类</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">WrapGreeterImpl</span> <span style="color:#268bd2">implements</span> WrapGreeter { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//...</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHelloStream</span>(StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> response) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#719e07">new</span> StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onNext</span>(String data) { |
| </span></span><span style="display:flex;"><span> System.out.println(data); |
| </span></span><span style="display:flex;"><span> response.onNext(<span style="color:#2aa198">&#34;hello,&#34;</span><span style="color:#719e07">+</span>data); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onError</span>(Throwable throwable) { |
| </span></span><span style="display:flex;"><span> throwable.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onCompleted</span>() { |
| </span></span><span style="display:flex;"><span> System.out.println(<span style="color:#2aa198">&#34;onCompleted&#34;</span>); |
| </span></span><span style="display:flex;"><span> response.onCompleted(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> }; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">sayHelloServerStream</span>(String request, StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> response) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">for</span> (<span style="color:#dc322f">int</span> i <span style="color:#719e07">=</span> 0; i <span style="color:#719e07">&lt;</span> 10; i<span style="color:#719e07">++</span>) { |
| </span></span><span style="display:flex;"><span> response.onNext(<span style="color:#2aa198">&#34;hello,&#34;</span> <span style="color:#719e07">+</span> request); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> response.onCompleted(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ol start="3"> |
| <li>调用方式</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>delegate.sayHelloServerStream(<span style="color:#2aa198">&#34;server stream&#34;</span>, <span style="color:#719e07">new</span> StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onNext</span>(String data) { |
| </span></span><span style="display:flex;"><span> System.out.println(data); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onError</span>(Throwable throwable) { |
| </span></span><span style="display:flex;"><span> throwable.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onCompleted</span>() { |
| </span></span><span style="display:flex;"><span> System.out.println(<span style="color:#2aa198">&#34;onCompleted&#34;</span>); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>}); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> request <span style="color:#719e07">=</span> delegate.sayHelloStream(<span style="color:#719e07">new</span> StreamObserver<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onNext</span>(String data) { |
| </span></span><span style="display:flex;"><span> System.out.println(data); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onError</span>(Throwable throwable) { |
| </span></span><span style="display:flex;"><span> throwable.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onCompleted</span>() { |
| </span></span><span style="display:flex;"><span> System.out.println(<span style="color:#2aa198">&#34;onCompleted&#34;</span>); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>}); |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">for</span> (<span style="color:#dc322f">int</span> i <span style="color:#719e07">=</span> 0; i <span style="color:#719e07">&lt;</span> n; i<span style="color:#719e07">++</span>) { |
| </span></span><span style="display:flex;"><span> request.onNext(<span style="color:#2aa198">&#34;stream request&#34;</span> <span style="color:#719e07">+</span> i); |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span>request.onCompleted(); |
| </span></span></code></pre></div><h2 id="protobuf-序列化的流">Protobuf 序列化的流</h2> |
| <p>对于 <code>Protobuf</code> 序列化方式,推荐编写 <code>IDL</code> 使用 <code>compiler</code> 插件进行编译生成。生成的代码大致如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">PbGreeter</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> String JAVA_SERVICE_NAME <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;org.apache.dubbo.sample.tri.PbGreeter&#34;</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> String SERVICE_NAME <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;org.apache.dubbo.sample.tri.PbGreeter&#34;</span>; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> <span style="color:#dc322f">boolean</span> inited <span style="color:#719e07">=</span> PbGreeterDubbo.init(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//...</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">greetServerStream</span>(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver<span style="color:#719e07">&lt;</span>org.apache.dubbo.sample.tri.GreeterReply<span style="color:#719e07">&gt;</span> responseObserver); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> org.apache.dubbo.common.stream.StreamObserver<span style="color:#719e07">&lt;</span>org.apache.dubbo.sample.tri.GreeterRequest<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">greetStream</span>(org.apache.dubbo.common.stream.StreamObserver<span style="color:#719e07">&lt;</span>org.apache.dubbo.sample.tri.GreeterReply<span style="color:#719e07">&gt;</span> responseObserver); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h2 id="流的实现原理">流的实现原理</h2> |
| <p><code>Triple</code>协议的流模式是怎么支持的呢?</p> |
| <ul> |
| <li> |
| <p>从协议层来说,<code>Triple</code> 是建立在 <code>HTTP2</code> 基础上的,所以直接拥有所有 <code>HTTP2</code> 的能力,故拥有了分 <code>stream</code> 和全双工的能力。</p> |
| </li> |
| <li> |
| <p>框架层来说,<code>StreamObserver</code> 作为流的接口提供给用户,用于入参和出参提供流式处理。框架在收发 stream data 时进行相应的接口调用, 从而保证流的生命周期完整。</p> |
| </li> |
| </ul> |
| <h2 id="triple-与应用级注册发现">Triple 与应用级注册发现</h2> |
| <p>关于 Triple 协议的应用级服务注册和发现和其他语言是一致的,可以通过下列内容了解更多。</p> |
| <ul> |
| <li><a href="https://dubbo.apache.org/zh-cn/docs/concepts/service-discovery/">服务发现</a></li> |
| <li><a href="https://dubbo.apache.org/zh-cn/docs/migration/migration-service-discovery/">应用级地址发现迁移指南</a></li> |
| </ul> |
| <h2 id="与-grpc-互通">与 GRPC 互通</h2> |
| <p>通过对于协议的介绍,我们知道 <code>Triple</code> 协议是基于 <code>HTTP2</code> 并兼容 <code>GRPC</code>。为了保证和验证与<code>GRPC</code>互通能力,Dubbo3 也编写了各种从场景下的测试。详细的可以通过<a href="https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/README.MD">这里</a> 了解更多。</p> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">未来: Everything on Stub</h4> |
| <p>用过 <code>Grpc</code> 的同学应该对 <code>Stub</code> 都不陌生。 |
| Grpc 使用 <code>compiler</code> 将编写的 <code>proto</code> 文件编译为相关的 protobuf 对象和相关 rpc 接口。默认的会同时生成几种不同的 <code>stub</code></p> |
| <ul> |
| <li>blockingStub</li> |
| <li>futureStub</li> |
| <li>reactorStub</li> |
| <li>&hellip;</li> |
| </ul> |
| <p><code>stub</code> 用一种统一的使用方式帮我们屏蔽了不同调用方式的细节。不过目前 <code>Dubbo3</code> 暂时只支持传统定义接口并进行调用的使用方式。</p> |
| <p>在不久的未来,<code>Triple</code> 也将实现各种常用的 <code>Stub</code>,让用户写一份<code>proto</code>文件,通过 <code>comipler</code> 可以在任意场景方便的使用,请拭目以待。</p> |
| </div></description></item><item><title>Overview: 查看历史版本文档</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/version/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/version/</guid><description> |
| <section id="section-0" style=""> |
| <div class="td-content list-page"> |
| <div class="lead"></div><header class="article-meta"> |
| </header><div class="row"> |
| <div class="col-sm col-md-6 mb-4 mb-md-0"> |
| <div class="h-100 card shadow" href="#"> |
| <div class="card-body"> |
| <h4 class="card-title"> |
| <a target="_blank" href='https://dubbo.apache.org/zh-cn/docs/'>Early 3.0 Version</a> |
| </h4> |
| <p>早期 3.0 版本文档</p> |
| </div> |
| </div> |
| </div> |
| <div class="col-sm col-md-6 mb-4 mb-md-0"> |
| <div class="h-100 card shadow"> |
| <div class="card-body"> |
| <h4 class="card-title"> |
| <a target="_blank" href='https://dubbo.apache.org/zh-cn/docsv2.7/'>2.7.x Version</a> |
| </h4> |
| <p>2.7.x 版本文档</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <hr> |
| </div> |
| </section></description></item></channel></rss> |