blob: da1ebb58b476dfd4e20031692b208c7ee02d3c57 [file] [log] [blame]
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Apache Dubbo – 社区动态</title><link>https://dubbo.apache.org/zh-cn/blog/news/</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/blog/news/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: Dubbo Java 3.1.4 正式发布</title><link>https://dubbo.apache.org/zh-cn/blog/2022/12/01/dubbo-java-3.1.4-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</link><pubDate>Thu, 01 Dec 2022 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2022/12/01/dubbo-java-3.1.4-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</guid><description>
&lt;p>Dubbo 3.1.4 版本是目前 Dubbo 3 的最新稳定版本,我们建议所有的用户都升级到最新的稳定版本。&lt;/p>
&lt;h1 id="dubbo-314">Dubbo 3.1.4&lt;/h1>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/3-1-4.png" alt="image.png">&lt;/p>
&lt;h3 id="新特性">新特性&lt;/h3>
&lt;ul>
&lt;li>Dubbo QoS 支持指定白名单 IP 列表访问所有命令&lt;/li>
&lt;/ul>
&lt;h3 id="bugfix">Bugfix&lt;/h3>
&lt;ul>
&lt;li>修复在泛化调用时 Dubbo Metrics 采集方法名错误&lt;/li>
&lt;li>修复使用 Zookeeper 作为元数据中心时,上报接口映射可能存在相互覆盖的问题&lt;/li>
&lt;li>修复 timeout countdown 在 Triple 协议的支持&lt;/li>
&lt;li>修复 timeout countdown 存在透传的问题&lt;/li>
&lt;li>修复多注册中心请求时,由于没有可用的地址导致的 NPE 问题&lt;/li>
&lt;li>修复 Mesh 模式下 Triple 获取 remoteApplicationName 为空的问题&lt;/li>
&lt;li>修复 GraalVM Native Image 的支持&lt;/li>
&lt;li>修复端口复用时无 SSL 连接导致的 NPE 异常&lt;/li>
&lt;li>完善 JDK 编译器报错日志的输出格式&lt;/li>
&lt;li>修复 MetadataReportConfig 部分配置时应用无法启动的问题&lt;/li>
&lt;li>修复 dubbo.reference 作为默认参数在 3.x 版本中不生效的问题&lt;/li>
&lt;li>完善 Zookeeper 连接失败的日志&lt;/li>
&lt;li>修复 ReferenceConfig 中配置的 ClassLoader 可能被覆盖的问题&lt;/li>
&lt;li>修复部分属性在应用级服务发现时被缓存在实例级的地址中导致方法级配置失效的问题&lt;/li>
&lt;li>修复 Triple 协议 onError 异常的问题&lt;/li>
&lt;/ul>
&lt;h3 id="faq">FAQ&lt;/h3>
&lt;p>本次发布中有 3 个提交涉及异常日志 FAQ 的完善。关于错误码机制请参考官网错误码机制介绍一文。(https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/faq/intro/)&lt;/p>
&lt;h3 id="代码优化">代码优化&lt;/h3>
&lt;p>本次发布中有 11 个提交涉及代码质量的优化。&lt;/p>
&lt;h3 id="依赖升级">依赖升级&lt;/h3>
&lt;ul>
&lt;li>升级 fastjson2: 2.0.14 -&amp;gt; 2.0.21&lt;/li>
&lt;li>升级 resteasy-jaxrs: 3.0.19.Final -&amp;gt; 3.0.20.Final&lt;/li>
&lt;/ul>
&lt;h3 id="贡献者">贡献者&lt;/h3>
&lt;p>Dubbo 感谢以下贡献者对本次发布的贡献:@cnjxzhao, @CrazyHZM, @EarthChen, @gold-fisher, @IncrementalRefinement, @Koooooo-7, @ShenFeng312, @tonycody, @twz007, @win120a, @wlazjr&lt;/p>
&lt;h3 id="新贡献者">新贡献者&lt;/h3>
&lt;ul>
&lt;li>@twz007 在 PR #11012 提交了第一个贡献&lt;/li>
&lt;li>@IncrementalRefinement 在 PR #11046 提交了第一个贡献&lt;/li>
&lt;li>@gold-fisher 在 PR #11058 提交了第一个贡献&lt;/li>
&lt;li>@wlazjr 在 PR #11084 提交了第一个贡献&lt;/li>
&lt;li>@ShenFeng312 在 PR #11102 提交了第一个贡献&lt;/li>
&lt;/ul>
&lt;h1 id="未来版本规划">未来版本规划&lt;/h1>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/release-roadmap.png" alt="image.png">&lt;/p>
&lt;p>Dubbo 版本的发布规划以及在《&lt;a href="https://mp.weixin.qq.com/s?__biz=MzIwODYwNTA4MA==&amp;amp;mid=2247484424&amp;amp;idx=1&amp;amp;sn=2f5ff4846f7dafad325f78fd8cf4d1fc&amp;amp;chksm=9701deffa07657e9a46eb97bb859770b4856599566b992724013a848a730f394702938e72404&amp;amp;token=1547029975&amp;amp;lang=zh_CN#rd">聚焦稳定性,Dubbo 发版规划公布&lt;/a>》一文中正式发布,欢迎查看。&lt;/p></description></item><item><title>Blog: 聚焦稳定性,Dubbo Java 发版规划公布</title><link>https://dubbo.apache.org/zh-cn/blog/2022/10/22/%E8%81%9A%E7%84%A6%E7%A8%B3%E5%AE%9A%E6%80%A7dubbo-java-%E5%8F%91%E7%89%88%E8%A7%84%E5%88%92%E5%85%AC%E5%B8%83/</link><pubDate>Sat, 22 Oct 2022 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2022/10/22/%E8%81%9A%E7%84%A6%E7%A8%B3%E5%AE%9A%E6%80%A7dubbo-java-%E5%8F%91%E7%89%88%E8%A7%84%E5%88%92%E5%85%AC%E5%B8%83/</guid><description>
&lt;h2 id="dubbo-简介">Dubbo 简介&lt;/h2>
&lt;p>Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。&lt;/p>
&lt;h2 id="我应该如何选择版本">我应该如何选择版本?&lt;/h2>
&lt;p>对于这个问题,一直以来 Dubbo 都没有很好地去回答。究其原因保证所有版本的稳定性是一件非常有挑战的事情。比如在 Dubbo 2.7 的一些版本中,出现了一些前后不兼容的问题,给一些用户升级带来了困扰。为此,很多用户从保障稳定性的视角出发,选择了更保守的策略,即生产环境采用被采用最多的版本,此后就不再更新,避免升级过程中出现意外。&lt;/p>
&lt;p>但是这种方式无疑是有问题的,一方面这将导致永远无法用上社区新的功能,得到技术演进的红利;另一方面,对于安全漏洞和带来不稳定因素的 bug 等已知问题如果不升级永远会存在,久而久之将给应用带来巨大的风险,很有可能导致严重的安全生产事故。&lt;/p>
&lt;p>因此,为了更好地回答这个问题,Dubbo 制定了未来的版本迭代规划,明确版本的稳定性维护机制,提升开发者使用 Dubbo 的信心。&lt;/p>
&lt;h2 id="现状">现状&lt;/h2>
&lt;p>在此前,Dubbo 总共维护了 2.6.x、2.7.x 以及 3.x 三个大版本,其中 2.7.x 为捐献进入 Apache 基金会之后的版本。&lt;/p>
&lt;p>2.6.x 在去年已经宣布生命周期结束(EOL)了,而 2.7.x 累计维护了四年的时间了。这四年的时间里,2.7.x 版本经历了多次大的修改,如 2.7.3 版本中对 Nacos 的注册方式进行了修改、2.7.6 版本中添加了应用级服务发现、2.7.9 版本中对应用级服务发现进行大的重构等。&lt;/p>
&lt;p>这些修改都对 2.7.x 版本的稳定性带来了巨大的风险隐患,导致 2.7.x 中很多版本或多或少存在不同的问题,用户无法选择一个最稳定的版本进行使用。&lt;/p>
&lt;p>因此,我们希望在 3.x 版本中将这种不稳定的情况通过发版机制给收敛掉,提高 Dubbo 版本的稳定性。&lt;/p>
&lt;h2 id="未来总体规划">未来总体规划&lt;/h2>
&lt;p>在接下来,Dubbo 将以每 6 个月为一个周期,对每个版本包括了新功能合入、稳定性维护以及安全漏洞修复三个大方向的内容。&lt;/p>
&lt;p>新功能合入是指将 Dubbo 开发过程中所有新的特性、性能优化、破坏性修改都会被合入的行为。由于新功能是需要一段时间迭代稳定的,所以新功能的合入会给对应版本带来不稳定因素,因此只能在每个版本最开始的时候进行。&lt;/p>
&lt;p>稳定性维护是指修复&lt;strong>已有&lt;/strong>功能的非预期行为,进一步提升版本的稳定性。特别的,对于一些大的问题修复,如功能需要整体重构的,或者回带来破坏性影响的提交将被视为新功能提交,执行新功能合入的流程。避免因为修复一个问题而来带更多问题的严重后果。&lt;/p>
&lt;p>安全维护是指修复使用中的安全风险问题,这一块主要是解决来自白帽子提交的漏洞问题。&lt;/p>
&lt;p>新功能合入在每个版本中会持续 &lt;strong>6&lt;/strong> 个月,稳定性维护在每个版本中会持续 &lt;strong>12&lt;/strong> 个月,安全维护在每个版本中会持续 &lt;strong>18&lt;/strong> 个月。&lt;/p>
&lt;p>因此,从整体迭代规划来看,每 6 个月 Dubbo 会开始一个新的版本迭代,与之同时的,也会有一个版本宣布生命周期结束(EOL)。&lt;/p>
&lt;h2 id="逐版本维护规划">逐版本维护规划&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/release-roadmap.png" alt="image.png">&lt;/p>
&lt;p>上图为具体到每个版本在每个时间点的维护状态图。&lt;/p>
&lt;p>对于 Dubbo 2.7 以及 3.0 版本,目前已经进入了安全维护阶段,将在 2023 年 3 月宣布版本维护周期结束。&lt;/p>
&lt;p>对于 Dubbo 3.1 版本,目前已经是稳定性维护阶段,如前一小节所述,目前只会继续合入和稳定性修改的修改。处于稳定性维护阶段的版本也是社区推荐生产使用的最新版本。稳定性维护工作将持续到 2023 年 3 月,在此之后会有持续 6 个月的安全维护阶段,最终在 2023 年 9 月结束其版本的生命周期。&lt;/p>
&lt;p>对于 Dubbo 3.2 版本,目前仍处在新功能合入的阶段,发布的是 beta 版本。此阶段适合一些尝鲜使用,版本稳定性相较于已经进入仅稳定性维护阶段的版本稍欠。在 2023 年 3 月,Dubbo 3.2 将结束新功能合入周期,进行充分的稳定性验证,并正式发布生产可用的 GA 版本。此后在 2023 年 9 月之前会进行稳定性的维护,在 2024 年 3 月结束版本的生命周期。&lt;/p>
&lt;p>对于 Dubbo 3.3 版本,将在 2023 年 3 月紧随着 3.2 版本结束新功能合入阶段后正式开始开发。因此,Dubbo 3.3 版本的第一个 beta release 也将会在 2023 年 3 月发布。同样的,经过 6 个月的新功能合入阶段之后,Dubbo 3.3 版本将会在 2023 年 9 月正式发布生产可用 GA 版本,同时进入稳定性维护阶段。之后在 2024 年 3 月进入安全维护阶段,在 2024 年 9 月结束版本的生命周期。&lt;/p>
&lt;h2 id="总结">总结&lt;/h2>
&lt;p>对于绝大多数的生产用户,我们建议使用&lt;strong>当前处于仅稳定性维护阶段的版本的最新小版本&lt;/strong>。如在 2022 年 9 月至 2023 年 3 月这段时间,Dubbo 3.1 是处于仅稳定性维护阶段的,因此首选 Dubbo 3.1 版本。而对于如 3.1.0、3.1.1、3.1.2 等的 Dubbo 3.1.x 的多个小版本,我们建议直接使用最新的小版本。由于各个小版本之间仅包含稳定性修复,所以越往后的版本是越稳定的。&lt;/p>
&lt;p>对于愿意尝鲜、体验新功能的用户,可以直接基于最新的开发版本进行测试。即使是开发版本,Dubbo 也有一整套的质量保障机制,如果使用过程中遇到问题,欢迎向社区提交反馈。&lt;/p>
&lt;p>目前,阿里巴巴集团已经基于 Dubbo 3.0 的稳定版本完美支撑了整个核心电商今年双十一的所有调用,现在也正在升级到 Dubbo 3.1 这个最新的稳定版本上来。我们欢迎更多的用户一起升级到 Dubbo 3.1 版本上,在升级过程中可以参考官网给出的升级指南,遇到任何问题也可以通过 issue、微信群、钉钉群及时反馈社区,我们将尽全力协助。&lt;/p>
&lt;h2 id="更多">更多&lt;/h2>
&lt;p>在版本规划的方向上,除了本次发布的迭代线路图,Dubbo 还将通过一系列的机制保障用户的使用体验是连续的、稳定的。在大版本升级方面,Dubbo 将建设&lt;strong>完善的版本升级指南&lt;/strong>,如 Dubbo 3.1 版本升级到 Dubbo 3.2 版本中的重大修改点,让用户在升级的时候能够清晰的了解其中的风险点,更好的规划升级节奏。&lt;/p>
&lt;p>此外,对于目前人在大范围使用的 Dubbo 2.7 版本,在近期 Dubbo 社区也将推出&lt;strong>针对 Dubbo 2.7 版本的升级的指南与工具&lt;/strong>,通过工程化的方式让所有的 Dubbo 2.7 用户都可以提前查出所有的版本差异点,平滑升级到 Dubbo 3 上来。&lt;/p></description></item><item><title>Blog: Dubbo Java 3.0.2 发版公告</title><link>https://dubbo.apache.org/zh-cn/blog/2021/07/18/dubbo-java-3.0.2-%E5%8F%91%E7%89%88%E5%85%AC%E5%91%8A/</link><pubDate>Sun, 18 Jul 2021 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2021/07/18/dubbo-java-3.0.2-%E5%8F%91%E7%89%88%E5%85%AC%E5%91%8A/</guid><description>
&lt;h2 id="新特性">新特性&lt;/h2>
&lt;ul>
&lt;li>支持通过 @DubboService 注解暴露泛化服务&lt;/li>
&lt;li>元数据中心xml格式的配置支持 protocol 和 port 属性&lt;/li>
&lt;li>兼容 curator5 以上的版本&lt;/li>
&lt;li>点对点调用支持*通配符进行匹配, 一个提供者地址可对应多个接口&lt;/li>
&lt;li>为应用级别的服务发现增加动态配置去进行规则覆盖&lt;/li>
&lt;li>对提供者测的动态配置覆盖规则提供开关,可以使提供者无视动态配置,不重新暴露&lt;/li>
&lt;li>支持 native image&lt;/li>
&lt;li>提供取消执行 shutdown hook 的开关&lt;/li>
&lt;li>支持 Kubernetes Mesh 的服务治理规则&lt;/li>
&lt;li>Netty 连接支持 SSL 配置&lt;/li>
&lt;/ul>
&lt;h2 id="bug-修复">Bug 修复&lt;/h2>
&lt;ul>
&lt;li>DubboBootStrap start 重复调用后,动态配置被覆盖&lt;/li>
&lt;li>动态配置规则被删除后,依然生效&lt;/li>
&lt;li>triple 协议在暴露时会抛出空指针异常&lt;/li>
&lt;li>ConfigCenterConfig.setAddress 方法会覆盖掉 username 属性&lt;/li>
&lt;li>DefaultFuture.closeChannel 会销毁掉消费端测的线程池&lt;/li>
&lt;li>TripleClientHandler.writeRequest 抛出空指针异常&lt;/li>
&lt;li>解析3.0迁移规则异常时会抛出空指针异常&lt;/li>
&lt;li>Activated Extensions 的顺序性问题&lt;/li>
&lt;li>URLAddress.parse 方法在解析 ipv6 地址时存在问题&lt;/li>
&lt;li>用户自定义的参数在 properties 配置中不生效&lt;/li>
&lt;li>同时使用 API 模式和 Spring 模式配置时属性,Config Id 存在覆盖问题&lt;/li>
&lt;li>应用级别服务发现在启动时不生效&lt;/li>
&lt;li>Nacos 注册中心无法动态感知提供者的数量变化&lt;/li>
&lt;li>${dubbo.application} 在 xml 文件中无法被 spring 的 placeholder 规则给解析替换&lt;/li>
&lt;li>获取实例参数的顺序问题,先去获取了实例级别参数,再去获取接口级别参数&lt;/li>
&lt;li>当 DubboConfigBeanInitializer 不存在时,注册应用启动监听器会抛出异常&lt;/li>
&lt;li>Mock 时 参数中包含 &amp;lsquo;:&amp;rsquo; 或者 &amp;lsquo;=&amp;rsquo; 字符时,不生效&lt;/li>
&lt;li>删除 Mesh 规则时空指针异常&lt;/li>
&lt;/ul>
&lt;h2 id="优化">优化&lt;/h2>
&lt;ul>
&lt;li>抓住 RemovalTask 的异常,保证信号量能够释放&lt;/li>
&lt;li>通过 唯一 service name 检查 ReferenceConfig/ServiceConfig 是否重复&lt;/li>
&lt;li>优化生成随机数的性能&lt;/li>
&lt;li>如果用户使用接口级别去做服务发现,不发布应用与接口的映射数据到元数据中心&lt;/li>
&lt;li>使用 StringBuilder#append(Char) 提升性能&lt;/li>
&lt;li>保证 GRPC 编译的类文件中接口的顺序&lt;/li>
&lt;li>优化 reference bean 的占位符解析&lt;/li>
&lt;li>MergeableClusterInvoker 中使用 CompletableFuture#get(long, TimeUnit) 去提升性能&lt;/li>
&lt;li>内置服务 MetadataService 不延迟暴露&lt;/li>
&lt;li>优化 ConfigBean 和 Bootstrap 的启动逻辑&lt;/li>
&lt;li>优化 Config 检查是否重复的逻辑&lt;/li>
&lt;li>使用 Ring 数据结构去进行注册通知&lt;/li>
&lt;li>优化动态配置的初始化逻辑&lt;/li>
&lt;li>ConfigManager 使用 ConcurrentHashMap 去移除锁逻辑,提升 equals 和 toString 性能&lt;/li>
&lt;li>优化 MetadataInfo equals 方法 以及 Instance Listener&lt;/li>
&lt;li>优化异步 export/refer 逻辑&lt;/li>
&lt;li>使用 TreeSet 数据结构保证应用级别服务发现时应用名称的顺序一致&lt;/li>
&lt;li>RegistryNotifier 的第一个十次通知不延迟&lt;/li>
&lt;li>dubbo-compile 编译使用新的格式生成 stub&lt;/li>
&lt;li>Mesh 服务治理规则在动态配置中心的分组和其他规则分组统一,由 DEFAULT_GROUP 改成 dubbo&lt;/li>
&lt;li>使用 nacos 用作注册中心时,可以在注册中心地址中使用参数来改变在 nacos 中的分组&lt;/li>
&lt;li>计算 ServiceInfo 的 reversion 时,移除运行时参数,避免生成多个 reversion&lt;/li>
&lt;li>Nacos 注册中心抛出异常时,将异常封装称 RpcException 抛出&lt;/li>
&lt;li>禁止动态配置中心对一些权限参数进行动态修改&lt;/li>
&lt;li>优化 Config Bean 的初始化流程,并兼容 spring 3.x/4.1.x&lt;/li>
&lt;li>Bootstrap.start 方法可重入,暴露或引用新的服务&lt;/li>
&lt;li>将 org.apache.dubbo 包中的类默认添加到白名单中&lt;/li>
&lt;li>保证生成的 Config 的 Id 唯一,并检查 Config 是否之前存在&lt;/li>
&lt;li>Javaassist 兼容改变 override 声明字段&lt;/li>
&lt;li>重构解码时的检查逻辑,当找不到 path, version 对应的提供者是,抛出异常&lt;/li>
&lt;li>当 ApplicationModel 为 null 时,兼容 adaptive extensions&lt;/li>
&lt;/ul>
&lt;h2 id="代码质量提升">代码质量提升&lt;/h2>
&lt;p>感谢以下提高 Apache Dubbo 的稳定性的贡献。&lt;/p>
&lt;p>&lt;a href="https://github.com/apache/dubbo/pull/8111">#8111&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8147">#8147&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8164">#8164&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8177">#8177&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8180">#8180&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8161">#8161&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8183">#8183&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8205">#8205&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8173">#8173&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8219">#8219&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8228">#8228&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8232">#8232&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8230">#8230&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8236">#8236&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8260">#8260&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8262">#8262&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8252">#8252&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8246">#8246&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8208">#8208&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8278">#8278&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8267">#8267&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8277">#8277&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8291">#8291&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8296">#8296&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8302">#8302&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8175">#8175&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8319">#8319&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8309">#8309&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8336">#8336&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8332">#8332&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8328">#8328&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8355">#8355&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8396">#8396&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8401">#8401&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8395">#8395&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8415">#8415&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8406">#8406&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8411">#8411&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8418">#8418&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8439">#8439&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8404">#8404&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8443">#8443&lt;/a>&lt;/p>
&lt;h2 id="maven依赖变化">Maven依赖变化&lt;/h2>
&lt;ul>
&lt;li>移除依赖: org.eclipse.collections:eclipse-collections&lt;/li>
&lt;li>移除依赖: com.google.guava:guava&lt;/li>
&lt;li>jetty: 9.4.11.v20180605 -&amp;gt; 9.4.43.v20210629&lt;/li>
&lt;li>apollo client: 1.1.1 -&amp;gt; 1.8.0&lt;/li>
&lt;li>snakeyaml: 1.20 -&amp;gt; 1.29&lt;/li>
&lt;li>tomcat embed: 8.5.31 -&amp;gt; 8.5.69&lt;/li>
&lt;li>nacos client: 2.0.0 -&amp;gt; 2.0.2&lt;/li>
&lt;li>swagger: 1.5.19 -&amp;gt; 1.5.24&lt;/li>
&lt;li>hessian_lite: 3.2.8 -&amp;gt; 3.2.11&lt;/li>
&lt;/ul></description></item><item><title>Blog: Dubbo Java 3.1.3 正式发布</title><link>https://dubbo.apache.org/zh-cn/blog/2022/07/18/dubbo-java-3.1.3-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</link><pubDate>Mon, 18 Jul 2022 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2022/07/18/dubbo-java-3.1.3-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</guid><description>
&lt;h2 id="dubbo-313">Dubbo 3.1.3&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/3-1-3.png" alt="image.png">&lt;/p>
&lt;h3 id="修改内容">修改内容&lt;/h3>
&lt;ul>
&lt;li>修复本地调用的过程中 Filter 顺序异常的问题&lt;/li>
&lt;li>支持导入协议配置项到 MetadataService&lt;/li>
&lt;li>支持在发布 MetadataService 时自动选择可用端口&lt;/li>
&lt;li>完善错误码内容&lt;/li>
&lt;li>泛化调用下支持一致性哈希负载均衡&lt;/li>
&lt;li>修复泛化调用时反序列化异常的问题&lt;/li>
&lt;li>修复由于 JVM Methods 顺序不一致导致的应用级元数据无法复用的问题&lt;/li>
&lt;li>默认关闭端口复用能力,修复 remoting 组建找不到 SPI 的问题&lt;/li>
&lt;li>修复由于引用计数异常导致的 safe gard 问题&lt;/li>
&lt;li>删除 Nacos 注册中心组建中使用的 guava 依赖&lt;/li>
&lt;li>修复接口级使用 Nacos 注册中心时由于地址聚合导致的无法下线的问题&lt;/li>
&lt;li>多个代码质量优化提交&lt;/li>
&lt;/ul>
&lt;h3 id="新贡献者">新贡献者&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://github.com/zhangzq7">@zhangzq7&lt;/a> 在 &lt;a href="https://github.com/apache/dubbo/pull/10847">#10847&lt;/a> 中提交了第一个贡献&lt;/li>
&lt;li>&lt;a href="https://github.com/akaakking">@akaakking&lt;/a> 在 &lt;a href="https://github.com/apache/dubbo/pull/10799">#10799&lt;/a> 中提交了第一个贡献&lt;/li>
&lt;li>&lt;a href="https://github.com/wxbty">@wxbty&lt;/a> 在 &lt;a href="https://github.com/apache/dubbo/pull/10921">#10921&lt;/a> 中提交了第一个贡献&lt;/li>
&lt;li>&lt;a href="https://github.com/haoxz11">@haoxz11&lt;/a> 在 &lt;a href="https://github.com/apache/dubbo/pull/10937">#10937&lt;/a> 中提交了第一个贡献&lt;/li>
&lt;/ul>
&lt;h3 id="新贡献者-1">新贡献者&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://github.com/weixsun">@weixsun&lt;/a> 在 &lt;a href="https://github.com/apache/dubbo/pull/10941">#10941&lt;/a> 中提交了第一个贡献&lt;/li>
&lt;/ul>
&lt;h2 id="未来的版本规划">未来的版本规划&lt;/h2>
&lt;p>3.0、3.1、3.2 有什么区别?未来会怎么发展?发版周期是怎么样的?更多的版本迭代规划也将在近期推出,欢迎关注 Apache Dubbo 官方公众号获取最新的信息。&lt;/p></description></item><item><title>Blog: Dubbo Java 3.2.0-beta.3 正式发布</title><link>https://dubbo.apache.org/zh-cn/blog/2022/12/18/dubbo-java-3.2.0-beta.3-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</link><pubDate>Sun, 18 Dec 2022 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2022/12/18/dubbo-java-3.2.0-beta.3-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</guid><description>
&lt;p>Dubbo 3.2.0-beta.3 版本是目前 Dubbo 3 的最新特性版本,包括了如 Spring Boot 3、JDK 17、服务粒度的线程池隔离等新特性的支持,欢迎大家尝鲜使用。&lt;/p>
&lt;h1 id="dubbo-320-beta3">Dubbo 3.2.0-beta.3&lt;/h1>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/3-2-0-beta-3.png" alt="image.png">&lt;/p>
&lt;p>&lt;strong>注:Dubbo 3.2.0-beta.3 的代码基础和 Dubbo 3.1.4 完全一致,因此在 Dubbo 3.1.4 中包括的所有修改内容,在 Dubbo 3.2.0-beta.3 中也同样存在,后续说明中对于重复的内容讲不再赘述。&lt;/strong>&lt;/p>
&lt;h3 id="新特性">新特性&lt;/h3>
&lt;ul>
&lt;li>支持使用 jackson 作为Dubbo 内部的 JSON 序列化方式&lt;/li>
&lt;li>优化 Dubbo Logger 的选择逻辑,在存在多种日志框架的情况下会尝试读取其配置,选择一个有效的日志框架,解决在 SpringBoot 等场景下 Dubbo 日志不输出的问题。&lt;/li>
&lt;li>Triple 协议支持客户端流控&lt;/li>
&lt;li>支持发布 Dubbo Metrics 数据到 Spring Boot 的 Endpoints 上&lt;/li>
&lt;li>支持可选关闭线程池满时的线程 Dump 以及支持配置 Dump 的结果输出路径&lt;/li>
&lt;li>xDS 实现支持路由规则的解析&lt;/li>
&lt;li>支持 Dubbo QoS 命令安全性分级,默认对外暴露存活检测的端口,支持 Kubernetes 的原生接入&lt;/li>
&lt;li>支持基于 P2C 的自适应负载均衡&lt;/li>
&lt;/ul>
&lt;h3 id="bugfix">Bugfix&lt;/h3>
&lt;ul>
&lt;li>修复默认 Metadata 缓存未开启的问题&lt;/li>
&lt;li>修复 Metrics 指标资源路径错误的问题&lt;/li>
&lt;li>完善线程池隔离的配置,默认采用共享线程池,避免创建过多的线程&lt;/li>
&lt;li>完善 prefer-serialization 的选择逻辑,提供向前兼容的能力&lt;/li>
&lt;li>修复 Triple 协议传输时未携带版本号导致版本调用错误的问题&lt;/li>
&lt;li>完善 GraalVM Native Image 的支持&lt;/li>
&lt;/ul>
&lt;h3 id="性能优化">性能优化&lt;/h3>
&lt;ul>
&lt;li>优化在连接数高时由于获取 channels 数量导致的资源占用问题&lt;/li>
&lt;/ul>
&lt;h3 id="代码优化">代码优化&lt;/h3>
&lt;p>本次发布中有 5 个提交涉及代码质量的优化。&lt;/p>
&lt;h3 id="贡献者">贡献者&lt;/h3>
&lt;p>Dubbo 感谢以下贡献者对本次发布的贡献:@AlbumenJ, @asa3311, @conghuhu, @CrazyHZM, @gitchenjh, @haoyann, @JavaHello, @Koooooo-7, @nannanfighting, @ningboliu, @shanuo0312, @songxiaosheng, @tonycody, @XDanwar&lt;/p>
&lt;h3 id="新贡献者">新贡献者&lt;/h3>
&lt;ul>
&lt;li>@JavaHello 在 PR #10970 提交了第一个贡献&lt;/li>
&lt;li>@songxiaosheng 在 PR #10997提交了第一个贡献&lt;/li>
&lt;li>@Koooooo-7 在 PR #11051 提交了第一个贡献&lt;/li>
&lt;li>@ningboliu 在 PR #10745 提交了第一个贡献&lt;/li>
&lt;li>@XDanwar 在 PR #11063 提交了第一个贡献&lt;/li>
&lt;/ul>
&lt;h1 id="未来版本规划">未来版本规划&lt;/h1>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/release-roadmap.png" alt="image.png">&lt;/p>
&lt;p>Dubbo 版本的发布规划以及在《&lt;a href="https://mp.weixin.qq.com/s?__biz=MzIwODYwNTA4MA==&amp;amp;mid=2247484424&amp;amp;idx=1&amp;amp;sn=2f5ff4846f7dafad325f78fd8cf4d1fc&amp;amp;chksm=9701deffa07657e9a46eb97bb859770b4856599566b992724013a848a730f394702938e72404&amp;amp;token=1547029975&amp;amp;lang=zh_CN#rd">聚焦稳定性,Dubbo 发版规划公布&lt;/a>》一文中正式发布,欢迎查看。&lt;/p></description></item><item><title>Blog: Dubbo 3.2.0-beta.2 正式发布</title><link>https://dubbo.apache.org/zh-cn/blog/2022/11/18/dubbo-3.2.0-beta.2-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</link><pubDate>Fri, 18 Nov 2022 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2022/11/18/dubbo-3.2.0-beta.2-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</guid><description>
&lt;h2 id="dubbo-320-beta2">Dubbo 3.2.0-beta.2&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/3-2-0-beta-2.png" alt="image.png">&lt;/p>
&lt;h3 id="修改内容">修改内容&lt;/h3>
&lt;ul>
&lt;li>切换到在用户线程序列化,提升协议性能&lt;/li>
&lt;li>支持 Netty3 的端口复用&lt;/li>
&lt;li>修复存在多个用户配置的 providedBy 时不生效的问题&lt;/li>
&lt;li>支持 istio 的 first-party-jwt 能力&lt;/li>
&lt;li>删除 fastjson 和 gson 的传递依赖&lt;/li>
&lt;li>支持可选 appResponse 不透传的能力&lt;/li>
&lt;li>切换到 Fastjson2 为默认序列化依赖&lt;/li>
&lt;li>完善注册中心推送的日志&lt;/li>
&lt;li>修复路由刷新时机早于服务目录刷新时机的问题&lt;/li>
&lt;li>关闭地址推空保护&lt;/li>
&lt;li>更新支持 GraalVM Native 的 SPI 生成代码&lt;/li>
&lt;li>支持使用 plain text 模式传输 xds 通道&lt;/li>
&lt;li>支持 Nacos 批量注册,修复多注册覆盖的问题&lt;/li>
&lt;li>支持 Spring Framework 6 and Spring Boot 3&lt;/li>
&lt;li>多个代码质量优化提交&lt;/li>
&lt;li>前述 Dubbo 3.1.3 的所有修改内容&lt;/li>
&lt;/ul>
&lt;h3 id="新贡献者">新贡献者&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://github.com/weixsun">@weixsun&lt;/a> 在 &lt;a href="https://github.com/apache/dubbo/pull/10941">#10941&lt;/a> 中提交了第一个贡献&lt;/li>
&lt;/ul>
&lt;h2 id="未来的版本规划">未来的版本规划&lt;/h2>
&lt;p>3.0、3.1、3.2 有什么区别?未来会怎么发展?发版周期是怎么样的?更多的版本迭代规划也将在近期推出,欢迎关注 Apache Dubbo 官方公众号获取最新的信息。&lt;/p></description></item><item><title>Blog: Dubbo Java 2.7.14 发版公告</title><link>https://dubbo.apache.org/zh-cn/blog/2020/05/18/dubbo-java-2.7.14-%E5%8F%91%E7%89%88%E5%85%AC%E5%91%8A/</link><pubDate>Mon, 18 May 2020 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2020/05/18/dubbo-java-2.7.14-%E5%8F%91%E7%89%88%E5%85%AC%E5%91%8A/</guid><description>
&lt;h2 id="变动项">变动项&lt;/h2>
&lt;ul>
&lt;li>为 ServiceDiscovery 增加动态配置中心的覆盖规则。(#8389)&lt;/li>
&lt;li>修复当 mock 参数中包含 &amp;lsquo;:&amp;rsquo; 或者 &amp;lsquo;=&amp;rsquo; 符号时无法正常使用的问题。(#8379)&lt;/li>
&lt;li>修复 zone 参数对 ZoneAwareClusterInvoker 配置无法生效的问题。(#8521)&lt;/li>
&lt;li>为序列化白名单检查增加开关,默认为 true。(#8537)&lt;/li>
&lt;li>修复当请求超时时序列化检查的空指针异常。(#8587)&lt;/li>
&lt;li>修复 NetUtils.ignoreNetworkInterface 无法处理网卡中包含 &amp;lsquo;(&amp;rsquo; 符号的问题。(#8629)&lt;/li>
&lt;li>统一获取本地地址的方式。(#8679)&lt;/li>
&lt;li>修复当重试参数为0,依旧会重试1次的问题。(#8743)&lt;/li>
&lt;li>当清除未使用的 invoker 时,立即关闭客户端。(#8756)&lt;/li>
&lt;li>修复 destroy 方法以及 doOverrideIfNecessary 中的异常。(#8683)&lt;/li>
&lt;li>DefaultFuture.closeChannel 根据日志级别选择是否打印请求的详细数据。(#8778)&lt;/li>
&lt;li>使用 MapUtils 替换 AttachmentsAdapter(#8772)&lt;/li>
&lt;/ul>
&lt;h2 id="maven依赖变化">Maven依赖变化&lt;/h2>
&lt;ul>
&lt;li>netty4: 4.1.51.Final -&amp;gt; 4.1.66.Final&lt;/li>
&lt;li>netty4_ssl: 2.0.39.Final -&amp;gt; 2.0.40.Final&lt;/li>
&lt;li>http_client: 4.5.3 -&amp;gt; 4.5.13&lt;/li>
&lt;li>jetty: 9.4.11.v20180605 -&amp;gt; 9.4.43.v20210629&lt;/li>
&lt;li>apollo_client: 1.1.1 -&amp;gt; 1.8.0&lt;/li>
&lt;li>tomcat_embed: 8.5.31-&amp;gt; 9.0.48&lt;/li>
&lt;li>commons_io: 2.6 -&amp;gt; 2.7&lt;/li>
&lt;li>curator: 5.0.0 -&amp;gt; 5.1.0&lt;/li>
&lt;li>hessian_lite: 3.2.8 -&amp;gt; 3.2.11&lt;/li>
&lt;/ul></description></item><item><title>Blog: Dubbo Go 1.5.1</title><link>https://dubbo.apache.org/zh-cn/blog/1/01/01/dubbo-go-1.5.1/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/1/01/01/dubbo-go-1.5.1/</guid><description>
&lt;p>近期我们发布了 dubbo-go v1.5.1,虽然是 v1.5 的一个子版本,但相比于 v1.5.0, 社区还是投入了很大人力添加了如下重大改进。&lt;/p>
&lt;h2 id="1-应用维度注册模型">1 应用维度注册模型&lt;/h2>
&lt;p>在新模型 release 后,我们发现 Provider 每个 URL 发布元数据都会注册 ServiceInstance,影响性能需要优化。&lt;/p>
&lt;p>我们的优化方案是:&lt;/p>
&lt;p>去除 ServiceDiscoveryRegistry 中注册 ServiceInstance 的代码,在 config_loader 中的loadProviderConfig 方法的最后注册 ServiceInstance&lt;/p>
&lt;p>具体步骤:&lt;/p>
&lt;ol>
&lt;li>获取所有注册的 Registry,过滤出 ServiceDiscoveryRegistry,拿取所有 ServiceDiscovery。&lt;/li>
&lt;li>创建 ServiceInstance。&lt;/li>
&lt;li>每个 ServiceDiscovery 注册 ServiceInstance。&lt;/li>
&lt;/ol>
&lt;p>保证 Provider 在注册成功之后,才暴露元数据信息。&lt;/p>
&lt;h2 id="2-支持基于-seata-的事务">2 支持基于 Seata 的事务&lt;/h2>
&lt;p>基于 Seata 扩展实现。通过增加过滤器,在服务端接收 xid 并结合 &lt;a href="https://github.com/seata-golang/seata-golang">seata-golang&lt;/a> 达到支持分布式事务的目的。 从而使 Dubbo-go 在分布式场景下,让用户有更多的选择,能适应更多的个性化场景。&lt;/p>
&lt;p>我们在 dubbo-samples 中给出了 &lt;a href="https://github.com/apache/dubbo-go-samples/tree/1.5/seata">事务测试用例&lt;/a> 。&lt;/p>
&lt;h2 id="3-多注册中心集群负载均衡">3 多注册中心集群负载均衡&lt;/h2>
&lt;p>对于多注册中心订阅的场景,选址时的多了一层注册中心集群间的负载均衡:&lt;/p>
&lt;p>在 Cluster Invoker 这一级,我们支持的选址策略有:&lt;/p>
&lt;ul>
&lt;li>指定优先级&lt;/li>
&lt;li>同 zone 优先&lt;/li>
&lt;li>权重轮询&lt;/li>
&lt;/ul>
&lt;h2 id="4-传输链路安全性">4 传输链路安全性&lt;/h2>
&lt;p>该版本在传输链路的安全性上做了尝试,对于内置的 Dubbo getty Server 提供了基于 TLS 的安全链路传输机制。&lt;/p>
&lt;p>为尽可能保证应用启动的灵活性,TLS Cert 的指定通过配置文件方式,具体请参见 Dubbo-go 配置读取规则与 TLS 示例:&lt;/p>
&lt;h2 id="5-路由功能增强">5 路由功能增强&lt;/h2>
&lt;p>本次路由功能重点支持了 动态标签路由 和 应用/服务级条件路由。&lt;/p>
&lt;h3 id="51-动态标签路由">5.1 动态标签路由&lt;/h3>
&lt;p>标签路由通过将某一个或多个服务的提供者划分到同一个分组,约束流量只在指定分组中流转,从而实现流量隔离的目的,可以作为蓝绿发布、灰度发布等场景的能力基础。&lt;/p>
&lt;p>标签主要是指对 Provider 端应用实例的分组,目前有两种方式可以完成实例分组,分别是&lt;code>动态规则打标&lt;/code>和&lt;code>静态规则打标&lt;/code>,其中动态规则相较于静态规则优先级更高,而当两种规则同时存在且出现冲突时,将以动态规则为准。&lt;/p>
&lt;h4 id="511-动态规则打标">5.1.1 动态规则打标&lt;/h4>
&lt;p>可随时在&lt;a href="https://dubbo.apache.org/zh-cn/docsv2.7/user/examples/routing-rule/">服务治理控制台&lt;/a>下发标签归组规则&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-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># governance-tagrouter-provider应用增加了两个标签分组tag1和tag2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># tag1包含一个实例 127.0.0.1:20880&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># tag2包含一个实例 127.0.0.1:20881&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:#268bd2">force&lt;/span>: &lt;span style="color:#cb4b16">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">runtime&lt;/span>: &lt;span style="color:#cb4b16">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">enabled&lt;/span>: &lt;span style="color:#cb4b16">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">key&lt;/span>: governance-tagrouter-provider
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">tags&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#268bd2">name&lt;/span>: tag1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">addresses&lt;/span>: [&lt;span style="color:#2aa198">&amp;#34;127.0.0.1:20880&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#268bd2">name&lt;/span>: tag2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">addresses&lt;/span>: [&lt;span style="color:#2aa198">&amp;#34;127.0.0.1:20881&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="512-静态规则打标">5.1.2 静态规则打标&lt;/h4>
&lt;p>可以在 server 配置文件的 tag 字段里设置&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-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#2aa198">&amp;#34;UserProvider&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">registry&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;hangzhouzk&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">protocol &lt;/span>: &lt;span style="color:#2aa198">&amp;#34;dubbo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">interface &lt;/span>: &lt;span style="color:#2aa198">&amp;#34;com.ikurento.user.UserProvider&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">loadbalance&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;random&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">warmup&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;100&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">tag&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;beijing&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">cluster&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;failover&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">methods&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#268bd2">name&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;GetUser&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">retries&lt;/span>: &lt;span style="color:#2aa198">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">loadbalance&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;random&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>consumer 添加 tag 至 attachment 即可&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>ctx &lt;span style="color:#719e07">:=&lt;/span> context.&lt;span style="color:#268bd2">Background&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>attachment &lt;span style="color:#719e07">:=&lt;/span> &lt;span style="color:#b58900">make&lt;/span>(&lt;span style="color:#268bd2">map&lt;/span>[&lt;span style="color:#dc322f">string&lt;/span>]&lt;span style="color:#dc322f">string&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>attachment[&lt;span style="color:#2aa198">&amp;#34;dubbo.tag&amp;#34;&lt;/span>] = &lt;span style="color:#2aa198">&amp;#34;beijing&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ctx = context.&lt;span style="color:#268bd2">WithValue&lt;/span>(ctx, constant.AttachmentKey, attachment)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>err &lt;span style="color:#719e07">:=&lt;/span> userProvider.&lt;span style="color:#268bd2">GetUser&lt;/span>(ctx, []&lt;span style="color:#268bd2">interface&lt;/span>{}{&lt;span style="color:#2aa198">&amp;#34;A001&amp;#34;&lt;/span>}, user)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>请求标签的作用域为每一次 invocation,使用 attachment 来传递请求标签,注意保存在 attachment 中的值将会在一次完整的远程调用中持续传递,得益于这样的特性,我们只需要在起始调用时,通过一行代码的设置,达到标签的持续传递。&lt;/p>
&lt;h4 id="513-规则详解">5.1.3 规则详解&lt;/h4>
&lt;h5 id="格式">格式&lt;/h5>
&lt;ul>
&lt;li>&lt;code>Key&lt;/code>明确规则体作用到哪个应用。&lt;strong>必填&lt;/strong>。&lt;/li>
&lt;li>&lt;code>enabled=true&lt;/code> 当前路由规则是否生效,可不填,缺省生效。&lt;/li>
&lt;li>&lt;code>force=false&lt;/code> 当路由结果为空时,是否强制执行,如果不强制执行,路由结果为空的路由规则将自动失效,可不填,缺省为 &lt;code>false&lt;/code>。&lt;/li>
&lt;li>&lt;code>runtime=false&lt;/code> 是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,必须设为 &lt;code>true&lt;/code>,需要注意设置会影响调用的性能,可不填,缺省为 &lt;code>false&lt;/code>。&lt;/li>
&lt;li>&lt;code>priority=1&lt;/code> 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为 &lt;code>0&lt;/code>。&lt;/li>
&lt;li>&lt;code>tags&lt;/code> 定义具体的标签分组内容,可定义任意n(n&amp;gt;=1)个标签并为每个标签指定实例列表。&lt;strong>必填&lt;/strong>&lt;/li>
&lt;li>
&lt;ul>
&lt;li>name, 标签名称&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>addresses, 当前标签包含的实例列表&lt;/li>
&lt;/ul>
&lt;h5 id="降级约定">降级约定&lt;/h5>
&lt;ol>
&lt;li>&lt;code>dubbo.tag=tag1&lt;/code> 时优先选择 标记了 &lt;code>tag=tag1&lt;/code> 的 provider。若集群中不存在与请求标记对应的服务,默认将降级请求 tag 为空的 provider;如果要改变这种默认行为,即找不到匹配 tag1 的 provider 返回异常,需设置&lt;code>dubbo.force.tag=true&lt;/code>。&lt;/li>
&lt;li>&lt;code>dubbo.tag&lt;/code> 未设置时,只会匹配 tag 为空的 provider。即使集群中存在可用的服务,若 tag 不匹配也就无法调用,这与约定 1 不同,携带标签的请求可以降级访问到无标签的服务,但不携带标签/携带其他种类标签的请求永远无法访问到其他标签的服务。&lt;/li>
&lt;/ol>
&lt;h3 id="52-应用服务级条件路由">5.2 应用/服务级条件路由&lt;/h3>
&lt;p>您可以在路由规则配置中配置多个条件路由及其粒度&lt;/p>
&lt;p>Sample:&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-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># dubbo router yaml configure file&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">routerRules&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#268bd2">scope&lt;/span>: application
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">key&lt;/span>: BDTService
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">priority&lt;/span>: &lt;span style="color:#2aa198">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">enable&lt;/span>: &lt;span style="color:#cb4b16">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">force&lt;/span>: &lt;span style="color:#cb4b16">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">conditions &lt;/span>: [&lt;span style="color:#2aa198">&amp;#34;host = 192.168.199.208 =&amp;gt; host = 192.168.199.208 &amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#268bd2">scope&lt;/span>: service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">key&lt;/span>: com.ikurento.user.UserProvider
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">priority&lt;/span>: &lt;span style="color:#2aa198">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">force&lt;/span>: &lt;span style="color:#cb4b16">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">conditions &lt;/span>: [&lt;span style="color:#2aa198">&amp;#34;host = 192.168.199.208 =&amp;gt; host = 192.168.199.208 &amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="521-规则详解">5.2.1 规则详解&lt;/h4>
&lt;h5 id="各字段含义">各字段含义&lt;/h5>
&lt;ul>
&lt;li>scope表示路由规则的作用粒度,scope的取值会决定key的取值。必填。&lt;/li>
&lt;li>
&lt;ul>
&lt;li>service 服务粒度&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>application 应用粒度&lt;/li>
&lt;li>Key明确规则体作用在哪个服务或应用。必填。&lt;/li>
&lt;li>
&lt;ul>
&lt;li>scope=service时,key取值为[{group}/]{service}[:{version}]的组合&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>scope=application时,key取值为application名称&lt;/li>
&lt;li>enabled=true 当前路由规则是否生效,可不填,缺省生效。&lt;/li>
&lt;li>force=false 当路由结果为空时,是否强制执行,如果不强制执行,路由结果为空的路由规则将自动失效,可不填,缺省为 false。&lt;/li>
&lt;li>runtime=false 是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,必须设为 true,需要注意设置会影响调用的性能,可不填,缺省为 false。&lt;/li>
&lt;li>priority=1 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为 0。&lt;/li>
&lt;li>conditions 定义具体的路由规则内容。必填。&lt;/li>
&lt;/ul>
&lt;h2 id="6-回顾与展望">6 回顾与展望&lt;/h2>
&lt;p>Dubbo-go 处于一个比较稳定成熟的状态。目前新版本正处于往云原生方向的尝试,应用服务维度注册是首先推出的功能,这是一个和之前模型完全不一样的新注册模型。该版本是我们朝云原生迈进新一步的关键版本。除此之外,包含在该版本也有一些之前提到的优化。&lt;/p>
&lt;p>下一个版本 v1.5.2,本次的关注重点以通信模型改进为主,除此之外,与 2.7.x 的兼容性、易用性及质量保证也是本次关注的信息。&lt;/p>
&lt;p>在&lt;strong>服务发现&lt;/strong>,会支持更加多的方式,如:文件、Consul。 从而使 Dubbo-go 在服务发现场景下,让用户有更多的选择,能适应更多的个性化场景。&lt;/p>
&lt;p>另外 &lt;strong>易用性及质量保证&lt;/strong>,主要关注的是 samples 与自动化构建部分。可降低用户上手 Dubbo-go 的难度,提高代码质量。&lt;/p>
&lt;p>目前下一个版本正在紧锣密鼓的开发中,具体规划及任务清单&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> ,都已经在 Github 上体现。&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://github.com/apache/dubbo-go/projects/10">https://github.com/apache/dubbo-go/projects/10&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Blog: Dubbo Go Hessian2 v1.7.0</title><link>https://dubbo.apache.org/zh-cn/blog/1/01/01/dubbo-go-hessian2-v1.7.0/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/1/01/01/dubbo-go-hessian2-v1.7.0/</guid><description>
&lt;p>Dubbo-go-hessian2 v1.7.0已发布,详见 &lt;a href="https://github.com/apache/dubbo-go-hessian2/releases/tag/v1.7.0">https://github.com/apache/dubbo-go-hessian2/releases/tag/v1.7.0&lt;/a>, 以下对这次更新内容进行详细整理。&lt;/p>
&lt;p>另外v1.6.3 将 attachment 类型由 map[string]stiring 改为map[string]interface{} 导致版本不兼容问题,这部分已还原,后续的计划是将dubbo协议的request/response对象整体迁移到dubbogo项目中进行迭代修改, hessian2中将不再改动到request/response对象。&lt;/p>
&lt;h2 id="1-new-features">1. New Features&lt;/h2>
&lt;h3 id="11-add-getstacktrace-method-into-throwabler-and-its-implements-207httpsgithubcomapachedubbo-go-hessian2pull207">1.1 add GetStackTrace method into Throwabler and its implements. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/207">#207&lt;/a>&lt;/h3>
&lt;p>go语言client请求java语言服务时,如果java语言抛出了异常,异常对应的堆栈信息是被保存在StackTraceElement中。&lt;/p>
&lt;p>这个异常信息在日志中最好能被打印出来,以方便客户端排查问题,所以在Throwabler和对应子类中增加了StackTraceElement的获取。&lt;/p>
&lt;p>注:其实还有一种更好的方法,所有的具体的异常类型都包含java_exception/exception.go的Throwable struct。这样只需要在Throwable中增加GetStackTrace方法就可以了。但是这种方式需要更多的测试验证,改动的逻辑相对会复杂一些。但是代码会更整洁。 这里先不用这种方法。&lt;/p>
&lt;h3 id="12-catch-user-defined-exceptions-208httpsgithubcomapachedubbo-go-hessian2pull208">1.2 catch user defined exceptions. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/208">#208&lt;/a>&lt;/h3>
&lt;p>golang中增加一个java中Exception对象的序列化输出方法:&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">JavaException&lt;/span>() []&lt;span style="color:#dc322f">byte&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e &lt;span style="color:#719e07">:=&lt;/span> hessian.&lt;span style="color:#268bd2">NewEncoder&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exception &lt;span style="color:#719e07">:=&lt;/span> java_exception.&lt;span style="color:#268bd2">NewException&lt;/span>(&lt;span style="color:#2aa198">&amp;#34;java_exception&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e.&lt;span style="color:#268bd2">Encode&lt;/span>(exception)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> e.&lt;span style="color:#268bd2">Buffer&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在output/output.go 提供调用入口:添加如下函数初始化声明&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">init&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> funcMap[&lt;span style="color:#2aa198">&amp;#34;JavaException&amp;#34;&lt;/span>] = testfuncs.JavaException
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>java代码中增加调用go方法序列化结果:&lt;/p>
&lt;p>&lt;strong>说明&lt;/strong>: Assert.assertEquals 不能直接比较Exception对象是否相等&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:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * test java java.lang.Exception object and go java_exception Exception struct
&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:#268bd2">@Test&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">testException&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Exception exception &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> Exception(&lt;span style="color:#2aa198">&amp;#34;java_exception&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Object javaException &lt;span style="color:#719e07">=&lt;/span> GoTestUtil.readGoObject(&lt;span style="color:#2aa198">&amp;#34;JavaException&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (javaException &lt;span style="color:#719e07">instanceof&lt;/span> Exception) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Assert.assertEquals(exception.getMessage(), ((Exception) javaException).getMessage());
&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;/code>&lt;/pre>&lt;/div>&lt;h3 id="13-support-java8-time-object-212httpsgithubcomapachedubbo-go-hessian2pull212-221httpsgithubcomapachedubbo-go-hessian2pull221">1.3 support java8 time object. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/212">#212&lt;/a>, &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/221">#221&lt;/a>&lt;/h3>
&lt;p>golang中增加一个java8对象的序列化输出方法:&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">// test java8 java.time.Year
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">Java8TimeYear&lt;/span>() []&lt;span style="color:#dc322f">byte&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e &lt;span style="color:#719e07">:=&lt;/span> hessian.&lt;span style="color:#268bd2">NewEncoder&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> year &lt;span style="color:#719e07">:=&lt;/span> java8_time.Year{Year: &lt;span style="color:#2aa198">2020&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e.&lt;span style="color:#268bd2">Encode&lt;/span>(year)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> e.&lt;span style="color:#268bd2">Buffer&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">// test java8 java.time.LocalDate
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">Java8LocalDate&lt;/span>() []&lt;span style="color:#dc322f">byte&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e &lt;span style="color:#719e07">:=&lt;/span> hessian.&lt;span style="color:#268bd2">NewEncoder&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> date &lt;span style="color:#719e07">:=&lt;/span> java8_time.LocalDate{Year: &lt;span style="color:#2aa198">2020&lt;/span>, Month: &lt;span style="color:#2aa198">9&lt;/span>, Day: &lt;span style="color:#2aa198">12&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e.&lt;span style="color:#268bd2">Encode&lt;/span>(date)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> e.&lt;span style="color:#268bd2">Buffer&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在output/output.go 提供调用入口:添加函数初始化声明&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">init&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> funcMap[&lt;span style="color:#2aa198">&amp;#34;Java8TimeYear&amp;#34;&lt;/span>] = testfuncs.Java8TimeYear
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> funcMap[&lt;span style="color:#2aa198">&amp;#34;Java8LocalDate&amp;#34;&lt;/span>] = testfuncs.Java8LocalDate
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>java代码中增加调用go方法序列化结果:&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:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * test java8 java.time.* object and go java8_time/* struct
&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:#268bd2">@Test&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">testJava8Year&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Year year &lt;span style="color:#719e07">=&lt;/span> Year.of(2020);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Assert.assertEquals(year
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> , GoTestUtil.readGoObject(&lt;span style="color:#2aa198">&amp;#34;Java8TimeYear&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> LocalDate localDate &lt;span style="color:#719e07">=&lt;/span> LocalDate.of(2020, 9, 12);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Assert.assertEquals(localDate, GoTestUtil.readGoObject(&lt;span style="color:#2aa198">&amp;#34;Java8LocalDate&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="14-support-test-golang-encoding-data-in-java-213httpsgithubcomapachedubbo-go-hessian2pull213">1.4 support test golang encoding data in java. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/213">#213&lt;/a>&lt;/h3>
&lt;p>为了更好的测试验证hessian库,原来已经支持在golang中测试java的序列化数据,现在增加在java中测试golang的序列化数据,实现双向测试验证。&lt;/p>
&lt;p>golang中增加序列化输出方法:&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">HelloWorldString&lt;/span>() []&lt;span style="color:#dc322f">byte&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e &lt;span style="color:#719e07">:=&lt;/span> hessian.&lt;span style="color:#268bd2">NewEncoder&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e.&lt;span style="color:#268bd2">Encode&lt;/span>(&lt;span style="color:#2aa198">&amp;#34;hello world&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> e.&lt;span style="color:#268bd2">Buffer&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>将该方法注册到output/output.go中&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// add all output func here
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> &lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">init&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> funcMap[&lt;span style="color:#2aa198">&amp;#34;HelloWorldString&amp;#34;&lt;/span>] = testfuncs.HelloWorldString
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>output/output.go 提供调用入口:&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">main&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> flag.&lt;span style="color:#268bd2">Parse&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> &lt;span style="color:#719e07">*&lt;/span>funcName &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#2aa198">&amp;#34;&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> _, _ = fmt.&lt;span style="color:#268bd2">Fprintln&lt;/span>(os.Stderr, &lt;span style="color:#2aa198">&amp;#34;func name required&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> os.&lt;span style="color:#268bd2">Exit&lt;/span>(&lt;span style="color:#2aa198">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> f, exist &lt;span style="color:#719e07">:=&lt;/span> funcMap[&lt;span style="color:#719e07">*&lt;/span>funcName]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> !exist {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> _, _ = fmt.&lt;span style="color:#268bd2">Fprintln&lt;/span>(os.Stderr, &lt;span style="color:#2aa198">&amp;#34;func name not exist: &amp;#34;&lt;/span>, &lt;span style="color:#719e07">*&lt;/span>funcName)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> os.&lt;span style="color:#268bd2">Exit&lt;/span>(&lt;span style="color:#2aa198">1&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:#719e07">defer&lt;/span> &lt;span style="color:#268bd2">func&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> err &lt;span style="color:#719e07">:=&lt;/span> &lt;span style="color:#b58900">recover&lt;/span>(); err &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">nil&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> _, _ = fmt.&lt;span style="color:#268bd2">Fprintln&lt;/span>(os.Stderr, &lt;span style="color:#2aa198">&amp;#34;error: &amp;#34;&lt;/span>, err)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> os.&lt;span style="color:#268bd2">Exit&lt;/span>(&lt;span style="color:#2aa198">1&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>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> _, err &lt;span style="color:#719e07">:=&lt;/span> os.Stdout.&lt;span style="color:#268bd2">Write&lt;/span>(&lt;span style="color:#268bd2">f&lt;/span>()); err &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">nil&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> _, _ = fmt.&lt;span style="color:#268bd2">Fprintln&lt;/span>(os.Stderr, &lt;span style="color:#2aa198">&amp;#34;call error: &amp;#34;&lt;/span>, err)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> os.&lt;span style="color:#268bd2">Exit&lt;/span>(&lt;span style="color:#2aa198">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> os.&lt;span style="color:#268bd2">Exit&lt;/span>(&lt;span style="color:#2aa198">0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>java代码中增加调用go方法序列化结果:&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">class&lt;/span> &lt;span style="color:#268bd2">GoTestUtil&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> Object &lt;span style="color:#268bd2">readGoObject&lt;/span>(String func) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> System.out.println(&lt;span style="color:#2aa198">&amp;#34;read go data: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> func);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Process process &lt;span style="color:#719e07">=&lt;/span> Runtime.getRuntime()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .exec(&lt;span style="color:#2aa198">&amp;#34;go run output/output.go -func_name=&amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> func,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cb4b16">null&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">new&lt;/span> File(&lt;span style="color:#2aa198">&amp;#34;..&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">int&lt;/span> exitValue &lt;span style="color:#719e07">=&lt;/span> process.waitFor();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (exitValue &lt;span style="color:#719e07">!=&lt;/span> 0) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Assert.fail(readString(process.getErrorStream()));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> InputStream is &lt;span style="color:#719e07">=&lt;/span> process.getInputStream();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Hessian2Input input &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> Hessian2Input(is);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> input.readObject();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Exception e) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> e.printStackTrace();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#cb4b16">null&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>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> String &lt;span style="color:#268bd2">readString&lt;/span>(InputStream in) &lt;span style="color:#268bd2">throws&lt;/span> IOException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> StringBuilder out &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> StringBuilder();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> InputStreamReader reader &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> InputStreamReader(in, StandardCharsets.UTF_8);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">char&lt;/span>&lt;span style="color:#719e07">[]&lt;/span> buffer &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> &lt;span style="color:#dc322f">char&lt;/span>&lt;span style="color:#719e07">[&lt;/span>4096&lt;span style="color:#719e07">]&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">int&lt;/span> bytesRead;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">while&lt;/span> ((bytesRead &lt;span style="color:#719e07">=&lt;/span> reader.read(buffer)) &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#719e07">-&lt;/span>1) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> out.append(buffer, 0, bytesRead);
&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:#719e07">return&lt;/span> out.toString();
&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;/code>&lt;/pre>&lt;/div>&lt;p>增加java测试代码:&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">@Test&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">testHelloWordString&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Assert.assertEquals(&lt;span style="color:#2aa198">&amp;#34;hello world&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> , GoTestUtil.readGoObject(&lt;span style="color:#2aa198">&amp;#34;HelloWorldString&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="15-support-javasqltime--javasqldate-219httpsgithubcomapachedubbo-go-hessian2pull219">1.5 support java.sql.Time &amp;amp; java.sql.Date. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/219">#219&lt;/a>&lt;/h3>
&lt;p>增加了 java 类 java.sql.Time, java.sql.Date 支持,分别对应到hessian.Time 和 hessian.Date, 详见 &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/219/files">https://github.com/apache/dubbo-go-hessian2/pull/219/files&lt;/a>。&lt;/p>
&lt;h2 id="2-enhancement">2. Enhancement&lt;/h2>
&lt;h3 id="21-export-function-encnull-225httpsgithubcomapachedubbo-go-hessian2pull225">2.1 Export function EncNull. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/225">#225&lt;/a>&lt;/h3>
&lt;p>开放 hessian.EncNull 方法,以便用户特定情况下使用。&lt;/p>
&lt;h2 id="3-bugfixes">3. Bugfixes&lt;/h2>
&lt;h3 id="31-fix-enum-encode-error-in-request-203httpsgithubcomapachedubbo-go-hessian2pull203">3.1 fix enum encode error in request. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/203">#203&lt;/a>&lt;/h3>
&lt;p>原来在 dubbo request 对象中没有判断 enum 类型的情况,此pr增加了判断是不是POJOEnum类型。详见 &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/203/files">https://github.com/apache/dubbo-go-hessian2/pull/203/files&lt;/a>&lt;/p>
&lt;h3 id="32-fix-byte-field-decoding-issue-216httpsgithubcomapachedubbo-go-hessian2pull216">3.2 fix []byte field decoding issue. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/216">#216&lt;/a>&lt;/h3>
&lt;p>v1.7.0 之前如果 struct中包含[]byte字段时无法反序列化, 报错“error list tag: 0x29”,主要原因是被当做list进行处理,对于这种情况应该按照binary数据进行处理即可。&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">type&lt;/span> Circular &lt;span style="color:#268bd2">struct&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Num &lt;span style="color:#dc322f">int&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Previous &lt;span style="color:#719e07">*&lt;/span>Circular
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Next &lt;span style="color:#719e07">*&lt;/span>Circular
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ResponseDataBytes []&lt;span style="color:#dc322f">byte&lt;/span> &lt;span style="color:#586e75">// &amp;lt;----
&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:#268bd2">func&lt;/span> (Circular) &lt;span style="color:#268bd2">JavaClassName&lt;/span>() &lt;span style="color:#dc322f">string&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#2aa198">&amp;#34;com.company.Circular&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="33-fix-decoding-error-for-map-in-map-229httpsgithubcomapachedubbo-go-hessian2pull229">3.3 fix decoding error for map in map. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/229">#229&lt;/a>&lt;/h3>
&lt;p>v1.7.0 之前嵌套map无法正确解析,主要原因是对应的map对象被当做一个数据类型却未被自动加到类引用列表中,而嵌套map类信息是同一类型的引用,去类引用列表找,找不到就报错了。 解决这个问题的方法就是遇到map类对象,也将其加入到类引用列表中即可。 问题详细参考 &lt;a href="https://github.com/apache/dubbo-go-hessian2/issues/119">#119&lt;/a>.&lt;/p>
&lt;h3 id="34-fix-fields-name-mismatch-in-duration-class-234httpsgithubcomapachedubbo-go-hessian2pull234">3.4 fix fields name mismatch in Duration class. &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/234">#234&lt;/a>&lt;/h3>
&lt;p>这个 PR 解决了Duration对象中字段错误定义,原来是&amp;quot;second/nano&amp;quot;, 应该是&amp;quot;seconds/nanos&amp;quot;。&lt;/p>
&lt;p>同时改善了测试验证数据。之前使用0作为int字段的测试数据,这是不准确的,因为int类型默认值就是0.&lt;/p></description></item><item><title>Blog: IntelliJ IDEA❤️Apache Dubbo,IDEA官方插件正式发布!</title><link>https://dubbo.apache.org/zh-cn/blog/2023/10/23/intellij-idea%EF%B8%8Fapache-dubboidea%E5%AE%98%E6%96%B9%E6%8F%92%E4%BB%B6%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</link><pubDate>Mon, 23 Oct 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/10/23/intellij-idea%EF%B8%8Fapache-dubboidea%E5%AE%98%E6%96%B9%E6%8F%92%E4%BB%B6%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</guid><description>
&lt;p>最受欢迎的 Java 集成开发环境 IntelliJ IDEA 与开源微服务框架 Apache Dubbo 社区强强合作,给广大微服务开发者带来了福音。与 IntelliJ IDEA 2023.2 版本一起,&lt;strong>Jetbrains 官方发布了一款全新插件 - Apache Dubbo in Spring Framework&lt;/strong>。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/10/plugin/img_6.png" alt="IntelliJ IDEA loves️ Apache Dubbo">&lt;/p>
&lt;p>这款插件可以帮助开发者解决 Dubbo 项目初始化问题,同时方便识别项目开发过程中的 Dubbo 服务及其依赖关系,基于 Apache Dubbo 的微服务开发将变得非常简单。&lt;/p>
&lt;h2 id="安装插件">安装插件&lt;/h2>
&lt;p>在安装 Apache Dubbo 插件之前,请确保您使用的 IntelliJ IDEA 为 2023.2 及以上版本。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/10/plugin/img.png" alt="image.png">&lt;/p>
&lt;p>有两种方式可以完成 Apache Dubbo 插件的安装&lt;/p>
&lt;h3 id="方式一">方式一&lt;/h3>
&lt;p>使用浏览器打开插件 &lt;a href="https://plugins.jetbrains.com/plugin/20938-apache-dubbo-in-spring-framework">Apache Dubbo in Spring Framework&lt;/a> 官方地址,在页面右上角,点击 “Install to IntelliJ IDEA 2023.2” 按钮即可完成插件安装。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/10/plugin/img_1.png" alt="image.png">&lt;/p>
&lt;h3 id="方式二">方式二&lt;/h3>
&lt;p>打开 Preferences -&amp;gt; Plugins,输入 &amp;lsquo;Apache Dubbo&amp;rsquo; 搜索插件,安装即可。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/10/plugin/img_2.png" alt="image.png">&lt;/p>
&lt;h2 id="使用插件新建应用">使用插件新建应用&lt;/h2>
&lt;p>插件安装完成,接下来,我们看一下如何使用插件创建和开发 Apache Dubbo 微服务应用。&lt;/p>
&lt;h3 id="打开弹窗">打开弹窗&lt;/h3>
&lt;p>通过 &amp;ldquo;File -&amp;gt; New -&amp;gt; Project&amp;rdquo; 打开新建项目对话框,在对话框中,可以看到 Apache Dubbo 插件已经出现在左侧模版列表中,点击选中即可。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/10/plugin/img_3.png" alt="image.png">&lt;/p>
&lt;p>根据应用需要,录入项目名称、保存路径、坐标、JDK版本等信息了,录入完毕之后,点击 &amp;ldquo;Next&amp;rdquo; 进入下一步。&lt;/p>
&lt;h3 id="选择组件">选择组件&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/10/plugin/img_4.png" alt="image.png">&lt;/p>
&lt;p>插件将使用 &lt;code>dubbo-spring-boot-starter&lt;/code> 创建 Spring Boot 项目,因此我们&lt;/p>
&lt;ul>
&lt;li>首先,需要选择 Dubbo 与 Spring Boot 的版本。&lt;/li>
&lt;li>其次,根据项目需要,选择相应的 Dubbo 与业务组件&lt;/li>
&lt;/ul>
&lt;p>最后,点击 “Create”,完成项目创建。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/10/plugin/img_5.png" alt="image.png">&lt;/p>
&lt;h2 id="总结">总结&lt;/h2>
&lt;p>IntelliJ IDEA 官方插件的发布,极大的简化了 Dubbo 项目初始化的成本,接下来,Apache Dubbo 社区会继续与 IntelliJ 官方合作,将更多的 Dubbo 特性抽象为插件组件,以简化 Dubbo 使用中的依赖、配置管理等难题。
除了插件形式外,您也可以直接打开 &lt;a href="https://start.dubbo.apache.org">start.dubbo.apache.org&lt;/a> 在线服务,通过浏览器快速创建 Dubbo 项目。&lt;/p></description></item><item><title>Blog: Apache Dubbo 云原生可观测性的探索与实践</title><link>https://dubbo.apache.org/zh-cn/blog/2023/10/07/apache-dubbo-%E4%BA%91%E5%8E%9F%E7%94%9F%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E7%9A%84%E6%8E%A2%E7%B4%A2%E4%B8%8E%E5%AE%9E%E8%B7%B5/</link><pubDate>Sat, 07 Oct 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/10/07/apache-dubbo-%E4%BA%91%E5%8E%9F%E7%94%9F%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E7%9A%84%E6%8E%A2%E7%B4%A2%E4%B8%8E%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;p>摘要:本文整理自平安壹钱包中间件资深工程师、Apache Dubbo committer宋小生在 Community Over Code 2023 大会上的分享。本篇内容主要分为五个部分:&lt;/p>
&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;h2 id="一可观测性建设">一、可观测性建设&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>首先介绍一下云原生升级的挑战。目前大部分公司里基本上都有CICD、OPS来帮助开发、测试、运维提升开发的效率与质量,也会有容器化来帮助提升产线运维的效率与质量。但在云原生时代,大规模容器的频繁变更会带来很多稳定性的问题。这些稳定性问题,包含了很多我们可以提前规避掉的已知的异常,也包含了很多我们无法避免的异常,比如网络故障、机器宕机等系统无法提前测出来的问题。&lt;/p>
&lt;p>如果我们能提前发现这些问题,其实是可以规避掉很多风险的。所以我们通过可观测系统及时的感知到了这些问题,高效的分析异常,快速的恢复系统。因此可以判定,在云原生时代,可观测系统的建设是非常重要的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_1.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>Dubbo作为微服务RPG的框架,直接建设一个大而全的可观测性系统或者平台是不现实的,而且它的定位也不是很符合。可观测性系统更强调关联性,通过单维度或者多维度进行系统的观测与问题的诊断。&lt;/p>
&lt;p>首先看一下可度量系统的健康状态的指标。Dubbo通过采集系统内部的Dubbo指标的同时,把指标内部的数据暴露给外部的监控系统。这些监控指标中间包含了很多的应用信息、主机信息、Dubbo服务标签信息等等。当我们发现问题的时候,可以通过这些标签信息关联到全链路系统。之后全链路系统可以做到请求级或者应用级的系统性能分析或者系统异常诊断。&lt;/p>
&lt;p>Dubbo侧通过适配各大厂商门面的形式,只需进行非常简易的依赖就引入或者配置就可以直接把数据导出到各大全链路平台。无论企业使用哪个流行平台,在后期升级Dubbo后都可以直接把链路导出去。&lt;/p>
&lt;p>另外,链路系统还包含全链路的Traceid或者局部的磁盘ID。通过全链路的ID,我们可以在链路系统直接跳转到日志平台。在日志平台里包含非常详细的日志上下文,这些日志上下文可以提供非常精确的异常问题诊断。&lt;/p>
&lt;p>Dubbo也提供了非常详细的错误码机制和专家建议的形式,在官网上通过日志的形式可以直接通过错误码的形式直接导航到官网上的帮助文档。&lt;/p>
&lt;h2 id="二多维指标体系">二、多维指标体系&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_2.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>Dubbo在多维度指标体系实践的时候,我们主要从两个维度来看它。&lt;/p>
&lt;p>第一个是纵向的维度。Dubbo指标在采集的时候有一个接入导出的流程。Dubbo为用户和开发者提供了简单易用的接入门面。接入后服务在运行过程中通过指标器进行指标的采集。Dubbo中提供了非常多的指标采集器,包括聚合和非聚合的指标采集等等。&lt;/p>
&lt;p>然后采集的指标会通过变量值临时存储在内存里,之后会有部分指标(QPS等带有滑动窗口的最小值、最大值的聚合指标)进行聚合计算,最后这些指标会导出到外部系统。我们支持在Dubbo QPS服务质量中进行指标导出,或者把指标导出到Prometheus,或者http直接访问也可以进行指标的查询。&lt;/p>
&lt;p>第二个是横向的维度。Dubbo指标采集覆盖了非常容易出现异常的地方。比如Dubbo 3提供了三大中心,包括注册中心、元数据中心、配置中心,存在外部网络交互的地方是非常容易出现问题的。&lt;/p>
&lt;p>另外一个比较关键的是RPC电路上的采集,比如请求相应的时间、异常、nity网络、IO的指标等等。此外还有一些关于Dubbo线程池的指标采集。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_3.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>前面说的是比较大面上的指标采集,具体Dubbo的采集需要哪些指标我们也调研了很多比较流行的方法论。&lt;/p>
&lt;ul>
&lt;li>图中第一张图是谷歌SRE书的四大黄金指标。它是谷歌总结大规模的分布式服务监控总结出来的,它可以进行请求级别的服务质量的衡量,主要包含延迟、流量、错误以及饱和度。&lt;/li>
&lt;li>图中第二张图是RED 方法。它更侧重于请求,从外部视角来查看服务的健康状态,主要包含速率、错误与持续时间。&lt;/li>
&lt;li>图中第三张图是USE 方法。它更侧重于系统内部的资源使用情况,包含利用率、饱和度与错误。&lt;/li>
&lt;/ul>
&lt;p>可以看到,以上三个指标的方法论中都包含的指标是错误,错误也是每个开发者比较关注的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_4.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>然后我们进行了指标的系统完善。在Dubbo 3.2版本中,多维度指标体系已经完成,而且也在快速持续的版本迭代中。在这个版本中我们只需要引入一个快速集成的Spring Boot中的Starter包就可以实现指标的自动采集。之后我们通过Dubbo的QPS服务质量端口可以直接访问到。如果是本机可以通过浏览器,如果是服务器可以通过科尔命令访问52端口,后面加一个Metric路径,这样就可以看到非常详细的默认指标的导出。&lt;/p>
&lt;p>可以看到这些指标有Dubbo前缀,类型是Dubbo的不同模块,比如消费者提供的请求级别,三大注册中心一起线程。&lt;/p>
&lt;p>下面是Dubbo当前指标的行为,比如响应时间最后会加一些单位,这个格式参考的是Prometheus的官方格式。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_5.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>多维度指标体系有些人可能会直接复用Spring Boot默认的manager管理端口,Dubbo也适配了一下Spring Boot Actuator的扩展。&lt;/p>
&lt;p>操作和刚刚一样,只是引入Spring Boot Starter包。后面也无需做任何其他的配置,就可以在Spring端口里看到详细的指标了。包括Spring Boot内置的jvm指标、Dubbo指标等等。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_6.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>指标体系接入之后,我们如果直接通过命令行访问只能看到一些瞬时的数据,但在监控指标体系我们其实更关注的是多维度的向量数据。如果我们把这些数据看作是一个点其实是比较难看出问题的,所以我们需要把这些数据存储起来,看作是一个实际化的向量数据。&lt;/p>
&lt;p>Dubbo默认提供对Prometheus采集的介入。Prometheus作为指标存储与监控一体的监控系统,提供了很多的服务发现模型。比如我们直接把服务部署在K8s上,可以直接基于K8s标签的服务发现机制进行指标采集。如果公司有自建的cmdb系统,可以自己扩展http接口进行指标采集。此外,文件或者静态的服务发现机制只要能发现Dubbo服务的IP和服务接口,也可以进行指标采集。采集到的指标会自动存储在Prometheus的实际数据库里。&lt;/p>
&lt;p>上图是我们通过Prometheus的查询框查询出来的响应时间的最新指标。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_7.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>Prometheus的指标更侧重于存储与报警,如果我们想更直观的体现还需要接入Grafana。Grafana的目标是为企业提供简易接入的监控面板,上图是一个简易的全局大盘。&lt;/p>
&lt;p>我们通过应用级别的筛选/机器IP维度的查询/服务接口的维度,查询服务的健康状态。可以看到,这些指标基本上都是基于前面总结的方法论实现的。比如QPS、请求数量、成功率、失败率、请求的时延等等。&lt;/p>
&lt;p>此外,还有一些应用信息的指标,比如升级Dubbo 3时,想看到哪些应用已经升级到新的版本,就可以看到新的应用的版本号,也会有应用信息的实例IP分布,还有一些现成资源。&lt;/p>
&lt;h2 id="三链路追踪门面">三、链路追踪门面&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_8.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>刚才说的指标比较抽象,它更利于帮助我们发现问题,接下来进行一些简单问题的诊断。微服务系统往往是多个系统之间有关联关系,所以服务之间的诊断更依赖于全链路系统。&lt;/p>
&lt;p>全链路系统Dubbo,当时考虑使用Agent的方式,这种方式对于用户接入是非常方便的,在代理层直接注入一些指标采集的方式即可。如果用这种方式在企业里做全链路的覆盖是非常方便的,但如果Dubbo只做Dubbo的指标采集,风险会比较大。因为Agent接入后会进行字节码修改等不兼容的问题,有些时候很难在前期发现。&lt;/p>
&lt;p>另外,Dubbo也调研了一些开源的链路追踪门面。Dubbo选择通过原生内置门面的形式,让专业的事情交给专业人做。Dubbo通过适配各大厂商的全链路追踪系统,快速适配接入的用户,只需增加少量的配置就可以实现链路数据的导出。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_9.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>在链路追踪门面的选型方面,我们参考了业界比较流行的几个链路,从中挑选了两个进行选型,分别是OpenTelemetry和Micrometer。&lt;/p>
&lt;p>OpenTelemetry,大家应该非常熟悉,它支持多语言,规范标准统一的API,支持大部分流行的第三方厂商的全链路追踪系统,是CNCF孵化的项目之一,很多中间件应用都已经接入了这种规范。&lt;/p>
&lt;p>Micrometer,大家可能对的印象是指标采集的接入。它的缺点是只能支持Java,但它在语言方面,它是Spring Boot 3默认的指标采集,链路采集默认支持micrometer-tracing的功能。此外,Micrometer它还可以通过桥接包直接转化为open的协议,间接也支持各种第三方的采集。并且Micrometer自身也通过调节机制调节了很多的全链路厂商。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_10.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>我们为了和前面使用到的指标采集进行统一,使用Micrometer后无需额外引入第三方的依赖,只需使用Micrometer Tracing的桥接包,就可以快速的接入。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_11.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>上图是链路追踪系统的简单结构。Dubbo的边路采集主要采集rpc请求的链路。在消费者发起请求的时候,如果存在链路ID就直接复用,没有的话会产生链路ID,然后把她们上报给采集器。同样消费者也会通过rpc的上下文把链路数据透传给提供端。提供端拿到这个链路数据后,会对它进行父子关系的关联。最后把这些链路数据上报采集器。&lt;/p>
&lt;p>采集器在前面的时候主要是内存级别的操作,对系统的损耗比较小。后面将进行异步的导出,和前面指标体系是一样的。内存级的同步采集,异步的把数据导出到第三方的链路系统。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_12.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>链路系统接入也比较简单,主要是引入Spring Boot Starter的依赖包,进行一些比较简单的配置,包括不同厂商的导出地址等等。&lt;/p>
&lt;p>链路系统可以帮助大家分析性能与异常,但一些系统问题原因的排查可能需要更详细的日志上下文来进行关联。这个时候这个链路系统会把数据放到mdc日志系统的上下文里面,然后在日志上下文里把链路系统编入的内容取出来,展示到日志的文件里。&lt;/p>
&lt;p>日志文件可能也会接触到第三方的日志平台,如果你有二次开发能力,可以在这种系统平台里加上链接,让这些Traceid自动跳转,即全链路系统自动跳转到日志平台,日志平台也可以自动跳转到全链路系统,查询问题会非常高效。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_13.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>上图是接入Zipkin的展示页面。可以看到它可以进行应用级的性能分析和接口级的性能分析。还可以看到一些Dubbo元数据,它的标签可以和指标大盘指标体系进行关联关系。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_14.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>这是Skywalking的格式,包括列表形式、表格形式等等。它通过Traceid搜到全链路的请求链路,也可以进行性能和异常的诊断。&lt;/p>
&lt;h2 id="四日志管理分析">四、日志管理分析&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_15.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>Dubbo通过日志里面的形式适配了各大日志组件。因为我们的日志组件在后期发展的体系是非常多的,可能是历史原因,Dubbo已经通过门面的形式适配了各大日志组件。&lt;/p>
&lt;p>系统运行过程中,非常容易出现问题的地方包括,服务的注册与发现,注册服务发现模型,服务提供端的注册,服务消费端的订阅与通知,服务rpc请求链路。&lt;/p>
&lt;p>当出现这些问题的时候,系统会出现异常。如果我们直接查看异常/网上检索/通过源码形式分析的话,不仅比较困难而且非常耗时。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_16.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>基于此,Dubbo做了一个专家建议帮助的文档手册。升级到Dubbo 3版本后,可以看到日志里有一个帮助文档的sq链接的形式。这个帮助手册套里提供了一些问题可能出现的原因和排查问题的解决思路。&lt;/p>
&lt;p>对排查问题比较感兴趣的同学,可以直接打开官网看一下。里面包含了非常多资深专家提供的问题诊断的思路,希望社区里的用户和开发者和我们一起共同建设。&lt;/p>
&lt;h2 id="五稳定性的实践">五、稳定性的实践&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_17.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>最后我们结合指标、链路、日志进行稳定性实践的介绍。主要分为两个部分:观测系统的异常和快速的恢复。&lt;/p>
&lt;p>观测系统的异常,在整体全链路系统建设之后,我们有运营人员主动的盯监控大盘发现告警,也有通过邮件、短信、钉钉的形式被动的收到告警。无论通过哪种形式,收到告警之后可以尝试使用可观测的思维,通过一些常见的、和异常相关的指标进行排查。&lt;/p>
&lt;p>通过这个方法,你可能会发现一些问题,但不一定是病因。这个时候你可以通过指标发生问题的地方找到全链路系统,之后分析哪个系统的哪一段有问题。如果排查不到问题,再通过链路系统的全链路ID关联到日志,通过日志里排查详细原因。如果日志也排查不到问题,可能就需要你在系统流量摘掉之后,通过工具进行详细的根因分析。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/observability/img_18.png" alt="dubbo-可观测性-metrics-and-tracing">&lt;/p>
&lt;p>快速的恢复,有了前面的原因定位后,基本上就可以知道哪里有问题了。这个时候可以根据你的原因进行流量的治理。比如切换机房流量,对流量进行限流,或者你的系统有异常的时候进行系统的回滚。&lt;/p></description></item><item><title>Blog: OpenSergo &amp; Dubbo 微服务治理最佳实践</title><link>https://dubbo.apache.org/zh-cn/blog/2023/10/07/opensergo-dubbo-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/</link><pubDate>Sat, 07 Oct 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/10/07/opensergo-dubbo-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;p>摘要:本文整理自阿里云 MSE 研发工程师何家欢的分享。本篇内容主要分为四个部分:&lt;/p>
&lt;ul>
&lt;li>一、Why 微服务治理?&lt;/li>
&lt;li>二、OpenSergo:服务治理控制面与标准规范&lt;/li>
&lt;li>三、OpenSergo &amp;amp; Dubbo 最佳实践&lt;/li>
&lt;li>四、OpenSergo 的未来之路&lt;/li>
&lt;/ul>
&lt;h2 id="一why-微服务治理">一、Why 微服务治理?&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>现代的微服务架构里,我们通过将系统分解成一系列的服务并通过远程过程调用联接在一起,在带来一些优势的同时也为我们带来了一些挑战。&lt;/p>
&lt;p>如上图所示,可以看到一个词云,这些都是目前微服务架构在生产上所遇到的挑战。比如,最常见的流量激增的场景,近一年内AIGC突然爆火,相关网站/服务都存在过因为激增流量导致服务不可用的情况,可能会让我们错过一个最佳的增长窗口。&lt;/p>
&lt;p>再比如缺乏容错机制,某视频网站的某个服务异常,随调用链扩散,导致全站入口不可用,影响千万用户,产生实质性的经济损失。这些生产故障频频发生,也是在提醒我们稳定性是用好微服务的重大挑战之一。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_1.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>为了保障微服务的稳定性,我们就需要做一些架构的演进。&lt;/p>
&lt;p>我们先看一下左侧的微服务3大件,这个大家已经很熟悉了,通过这三者的配合,我们的应用就能够正常使用了,但是距离生产可用其实还有很大一段距离,各个企业和社区为了消除这其中的gap都有一些探索和实践,比如Dubbo社区在Dubbo3中引入一系列诸如流量管理、高可用性的能力来保障微服务的稳定性,这些措施可以统称为微服务治理。&lt;/p>
&lt;p>所以其实大家已经意识到,从把微服务跑起来到真的生产可用,微服务治理是必不可少的一环。但微服务治理要做些什么,如何去做其实都还比较模糊。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_2.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>从软件生命周期的角度,我们可以把微服务治理分成三个域,开发态与测试态、变更态、运行态。&lt;/p>
&lt;p>在这三个域中都面临着很多挑战,对于这些挑战大家也有着一些探索和实践,比如对于发布有损的问题,我们可以通过无损上下线来解决,变更的影响面通过灰度来控制,对于不确定流量使用流控、热点防护,不稳定调用使用熔断与隔离。&lt;/p>
&lt;p>可以看到在各个域中都有一些成熟的方案和效果很好的实践。但是不管是阿里还是其他公司,在体系化落地微服务治理时都会遇到很多问题。&lt;/p>
&lt;h2 id="二opensergo服务治理控制面与标准规范">二、OpenSergo:服务治理控制面与标准规范&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_3.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>首先我们涉及的组件有很多,在微服务架构中,往往会涉及很多组件,它们需要有Dubbo这样的调用框架,nacos这样注册中心,snetinel、hystrix这样的稳定性中间件等等,因此也没办法进行统一治理,管控成本就非常高。&lt;/p>
&lt;p>其次时概念不统一,比如在envoy中的隔离与 sentinel中的隔离完全不是一个意思,envoy的隔离是摘除不健康实例,sentinel的隔离是并发控制,这就会使开发者理解成本很高。&lt;/p>
&lt;p>同时各个企业社区都有自己的最佳实践,这也就导致大家能力上是不对齐的,没有统一的标准。&lt;/p>
&lt;p>还有配置不统一的问题相信大家都很有体感,比如sentinel、hystrix、istio都有熔断的能力,但是配置却各有差别,需要开发者分别学习,还要注意不混淆,不利于理解,也不利于统一管控。&lt;/p>
&lt;p>可以发现由于这些问题,我们在落地体系化微服务治理时会有很大的阻力,我们需要的是一个统一的治理界面来让我们更好地做微服务治理,因此我们提出了OpenSergo这个项目。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_4.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>而OpenSergo期望提出一套开放通用的、面向云原生架构的微服务治理解决方案及标准规范,来助力保障微服务高可用,上图的四个部分就是OpenSergo社区的愿景。&lt;/p>
&lt;p>OpenSergo社区会基于业界微服务治理场景与实践抽象成规范,通过这种方式去解决前面提到的概念、配置、能力不统一的问题,并用统一的管控面去承载,降低使用和维护成本。&lt;/p>
&lt;p>同时在纵向上,我们针对链路上的每一环进行抽象,覆盖完整的场景,在横向上,无论是Java生态,Go生态或是其他语言,无论是传统微服务还是Mesh架构,都会纳入到这套统一的体系中。&lt;/p>
&lt;p>但是OpenSergo作为一个开放标准,仅凭借阿里是不够的,所以我们联合了多家公司以及社区比如bilibili、中国移动、字节跳动的cloudwego社区等,共同建设这套开放标准,希望能够真正解决微服务稳定性的风险。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_5.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>接下来简单介绍一下OpenSergo的架构体系,前面也介绍了OpenSergo社区会基于场景抽象出OpenSergo的Spec,但这只是第一步,为了承载这些标准规范我们就需要一个控制面,社区在一开始的演进中选择从0开始开发一个控制面来做治理规则的管控、监听与下发。&lt;/p>
&lt;p>但是随着社区的演进,我们发现基于Istion去扩展,成本更低,也能够复用更多的能力,因此在后续的演进中我们会选择结合Istio扩展控制面与决策中心实现治理规则统一管控、治理策略预计算。&lt;/p>
&lt;p>在有了控制面后我们还需要数据面来进行具体治理能力的实现,它可以是像sentinel这样的中间件,也可以是框架本身。控制面与数据面之间的通讯在初始的架构中是基于grpc构建的链路,但在确定了后续演进方向会基于istio扩展后,社区选择拥抱xds,尽可能服用它的链路,对于一些无法承载的我们再使用自身的grpc链路。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_6.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>前面也提到社区控制面的后续演进是基于Istio扩展的,Istio本身也有一些流量治能力,并有着一定的普及度。但是Istio主要关注流量管理,让流量到达该去的地方而不是微服务治理治理,所以在微服务稳定性的场景下,Istio所提供的这些能力是不足以满足我们的需求的。&lt;/p>
&lt;p>因此我们在Istio的基础上,基于微服务稳定性的一些场景,比如前面提到的变更态稳定性、运行时稳定性去抽象、制定了满足需求的规范标准,希望能够更加贴合微服务场景。所以整体上我们在微服务治理领域会是Istio的超集,而不是互斥关系。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_7.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>接下来我们一起看一下OpenSergo的标准规范是如何解决前面所提到的这些场景。&lt;/p>
&lt;p>首先我们聊一下流量路由,它的主要作用是将符合一定特征的流量路由到指定的workload上,一般大家会用这种能力来实现灰度、同AZ路由等方案。&lt;/p>
&lt;p>基于 Istio VirtualService/DestinationRule 的格式社区定义了流量路由spec,但我们在调研以及实践的过程中发现,它并不能很好的满足微服务场景下的需求。所以为了更贴近微服务的场景去扩展去做了扩展。比如我们增加了路由失败后的处理逻辑,这在微服务架构中是很常见的需求。&lt;/p>
&lt;p>又由于Istio主要关注的是HTTP请求,它的CRD不能够很好地承载像Dubbo这样的RPC调用,所以我们为此增加了更多RPC模型的支持。后续我们也会探索与社区标准结合的方案,使我们的Spec更加通用与标准。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_8.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>前面所提到的灰度,在阿里集团内部数年的安全生产实践中,与可监控、可回滚一起被定义为安全变更的三板斧,其中灰度是控制变更影响面,保障变更稳定性的必不可少的能力。&lt;/p>
&lt;p>为了实现灰度,我们通常有几种方案,第一种是物理隔离,我们通过部署两套一样的环境来实现灰度,但是这种方案的部署和维护成本都很高。&lt;/p>
&lt;p>为了提高资源利用率,便产生了第二种方案,流量灰度。我们不部署独立的环境,而是在流量的每一跳进行流量的特征匹配,并且由此决定去往灰度实例还是base实例,这种方案相较与前者更加灵活高效,可以通过前面提到的流量路由能力来实现。但是需要我们在每一跳都配置路由规则,相对比较繁琐。&lt;/p>
&lt;p>并且由于有些信息在后续链路是获取不到的,比如uid,导致这个方案的实施有一定的困难。于是便产生了第三种方案,全链路灰度,我们通过在流量入口处进行流量匹配并打上标签,标签会自动沿着调用链路透传,后续链路根据标签来进行路由。通过这种方式,我们就能够更简洁地去定义灰度。Opensergo针对这种场景抽象了对应的CRD。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_9.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>我们将这个CRD称之为TrafficLane也就是泳道,我觉得还是比较形象的,大家看一下上边的图片,橙色的是正常的流量走向,灰色的是灰度流量的走向,就像是将一个池子分成了多个泳道。&lt;/p>
&lt;p>泳道的CRD有三个部分组成,也比较好理解,首先我们需要去匹配灰度流量,所以就要去定义匹配的条件,然后定义为这些流量打上什么标签,最后再定义这个标签以什么方式去透传。&lt;/p>
&lt;p>通过这样的CRD我们就定义了一条灰度泳道。但是如果只是定义是不足以实现全路灰度的,我们还需要借助OpenSergo体系全链路全方位框架的一个支持,才能让标签在这些框架中自动的透传,这些框架也能通过标签进行路由。其中流量染色和标签透传会借助标准的trcae体系去实现,比如OT。&lt;/p>
&lt;p>上图右侧是一个CRD的例子,大家可以简单看一下。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_10.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>接下来我们一起看一下运行态稳定性的场景。&lt;/p>
&lt;p>我们主要提两个场景,第一个是流量激增的场景,比如双十一的秒杀活动,一开始流量是稳定的情况下,系统也处于稳态。但是当流量激增的时候,系统就会开始往不稳定的方向发展,异常调用也会激增,最后就会变成不可用的状态。对于这类场景,我们可以用流量控制的能力拒绝超出容量的请求,或是通过流量平滑的能力削峰填谷,让流量处于比较平稳的状态,避免服务的不可用。&lt;/p>
&lt;p>第二个是不稳定调用导致服务不可用的场景,比如我们调用一些第三方服务经常会出现不稳定的情况,这里的不稳定主要指异常或是慢调用。以dubbo为例,当服务提供方出现慢调用的时候,会导致服务消费方的线程堆积,影响到其他的正常调用甚至是整个服务的稳定性,并且这种风险会沿着调用链反向传递、扩散最终影响整个系统的稳定性。这时我们可以通过并发控制或是熔断保护来限制慢调用对资源的占用,保障系统的整体稳定性。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_11.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>针对前面提到的这些场景,OpenSergo也制定了相关的CRD。在业界的实践中sentinel是一个成熟的流量防护方案,在阿里内部积累了大量的流量防护相关的场景和实践,2018年开源依赖在业界进一步丰富了这些积累,我们从这些积累中抽象出了一套流量防护的规范标准。&lt;/p>
&lt;p>那么一条流量防护的规则应该包含哪些内容,大家可以简单想一下。&lt;/p>
&lt;p>首先我们要确定的是要针对怎样的流量,我们可以按接口去划,也可以按请求中的特征去划。确定了目标之后,我们就需要定义要采取怎样的治理策略。这里的策略包括了刚才提到的这些策略,以及更高阶的比如自身过载保护等策略。&lt;/p>
&lt;p>最后由于限流本身是有损的,但是我们不希望这种有损传递到用户侧,因此我们需要为不同的规则配置不同行为,从而使得在用户侧的表现是比较友好的,比如最基本的对于抢购场景的限流,我们可以返回一个排队中,请稍后的提示。&lt;/p>
&lt;p>上图右侧是一个CRD的示例,流量目标为接口名为/foo的请求,策略为阈值为10的全局限流,fallback为特定的返回体。&lt;/p>
&lt;p>通过这样的CRD配置,不管是Dubbo框架还是其他框架,我们都能很方便的使用流量防护的能力。&lt;/p>
&lt;h2 id="三opensergo--dubbo-最佳实践">三、OpenSergo &amp;amp; Dubbo 最佳实践&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_12.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>对于框架开发者来说想要接入到OpenSergo的体系中其实有两种方式&lt;/p>
&lt;p>一种是通过对接OpenSergo体系的数据面来接入,框架开发者只需要实现对接Sentinel的适配模块就可以完成对接工作。而对于有特殊要求或是更贴近特定场景的框架,也可以自行对接OpenSergo的标准,来接入OpenSergo体系。&lt;/p>
&lt;p>对于用户来说,不管是哪一种方式,都只需要简单地引入一些依赖,就可以无感地获取OpenSergo定义的微服务治理能力,并能在统一的控制面管控这些框架的微服务治理能力,大大提高使用微服务治理的体验与效率。讲完了接入的方式,我们再一起来看下实现的效果。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_13.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>第一个实践是全链路灰度控制消除变更态稳定性风险。这是一个简单的demo,我们只需要部署这样的一个CRD,定义/A/dubbo的请求,当它的参数里出现xiaoing的时候,我们就把它导向灰度的环境。可以看到现在的请求走向是符合我们预期的,有灰度环境的就是灰度环境了。对于不符合要求的流量,就还是走基线环境,我们只需要简单的CRD就可以实现。&lt;/p>
&lt;p>但我们的生产环境会比demo复杂的多,会涉及各种框架,比如RokcetMQ、spring cloud alibabab。但只要这些框架对接了Opensergo的体系,就可以用这一个CRD来做到全链路,全框架的灰度。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_14.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>第二个实践是流量防护与容错保障运行时稳定性——不稳定调用场景。这里使用一个简单的Demo,应用A通过Dubbo调用应用B。右侧是一个正常接口和慢调用接口的流量图,蓝色的是总流量,黄色的是拒绝流量,橙色的异常流量。在一开始慢调用还没有发生,系统处于稳态,没有异常流量。&lt;/p>
&lt;p>在第一个时间点,我手动调整了慢调用接口的RT,慢调用发生,异常流量出现,同时由于慢调用大量地占用了Dubbo的线程资源,导致正常调用的资源受到挤占,同样出现大量的异常流量,Dubbo侧也出现了线程池耗尽的异常。&lt;/p>
&lt;p>大家可以想一下,这种场景下我们应该配置什么规则来解决这个问题,其实这个时候很多人会想要流量控制来做限流希望能解决这个问题,我们一起看下它的一个效果。&lt;/p>
&lt;p>在第二个时间我配置了一条限流规则,可以看到情况虽然有所缓解,但是依旧有大量报错,这是因为在慢调用场景下,请求已经出现堆积,仅仅通过QPS限流还是会导致请求涌入进一步堆积。&lt;/p>
&lt;p>所以我们真正需要的并发控制,在第三个时间点我配置并发控制规则来限制慢调用接口的并发数,也就是正在处理的请求数。可以看到通过这种限制,即便慢调用仍然存在,但是它所能占用的线程资源被限制,正常接口得以正常调用,从而避免稳定性风险的扩展,保障应用的稳定性。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_15.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>第三个实践是流量防护与容错保障运行时稳定性——自适应过载保护。可以看到我们的demo在持续的高负载下,异常流量开始逐渐上升,系统的稳态被破坏,这时我们可以通过配置自适应过载保护规则,来自适应地调节限流行为,达到消除异常请求,帮助系统重新回到稳态的效果。&lt;/p>
&lt;p>目前的策略我们在开源已经支持了BBR,在内部的实践中我们也有用PID。这些策略我就不在这里详细介绍了,大家感兴趣可以去我们的开源社区一起参与讨论。&lt;/p>
&lt;p>从这三个例子可以看到Dubbo通过对接Sentinel接入OpenSergo体系后就无感地具备了OpenSergo所定义的通用的治理能力,并且能够通过统一的控制平面来管控。&lt;/p>
&lt;p>而对于其他框架也是一样,可以设想一下如果我们生产上所涉及的所有框架都对接了OpenSergo体系,那我们就可以在一个控制面上管控所有服务,所有框架的微服务治理能力,更好地保障系统的稳定性。&lt;/p>
&lt;h2 id="四opensergo-的未来之路">四、OpenSergo 的未来之路&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_16.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>这是多语言服务治理的生态大图。在生态上,我们希望OpenSergo是全链路多语言异构化的,我们会主要关注Java/Go + Gateway + Mesh 生态,在生态上不断去覆盖更多的框架。&lt;/p>
&lt;p>在能力上我们会不断抽象并落地更多的通用的微服务治理能力。包括流量防护、自愈、服务容错、健全、发现等等。&lt;/p>
&lt;p>目前我们已经和很多社区建立了联系和合作,比如Dubbo、ShenYu、APISIX、Higress、RocketMQ、MOSN等等,其中也有不少已经有了一些实质性的进展。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_17.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>接下来分享一下我们近期的规划。&lt;/p>
&lt;ul>
&lt;li>控制面方面,我们会逐步推动控制面的生产可用,在明年3月份发布GA版本,让大家能够在生产上去验证微服务治理体系。&lt;/li>
&lt;li>Spec方面,我们会去支持微服务安全治理、离群实例摘除,并持续地与社区标准集成。&lt;/li>
&lt;li>治理能力的演进上,我们会重点完成Sentinel 2.0 流量治理的升级,并在安全和自适应方向上进行探索。&lt;/li>
&lt;li>在社区合作上,我们会继续推进与社区间的交流与合作,推进各个微服务治理领域的生态落地,统一控制面、Spec 共建。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/opensergo/img_18.png" alt="dubbo-opensergo-服务治理最佳实践">&lt;/p>
&lt;p>虽然阿里在集团以及云上积累了大量的经验和场景,但稳定性的问题是复杂的,场景是多样的,仅凭一方不足以覆盖所有稳定性的场景,也不足以成为标准,所以微服务治理技术、生态与标准化的演进还需要各个企业和社区的共同参与。&lt;/p>
&lt;p>大家可以从以下三个方面入手来参与社区。&lt;/p>
&lt;ul>
&lt;li>微服务治理的spec,各个社区和企业都是各自领域中引领者,大家能从各自的场景和最佳实践出发,一起制定与完善标准规范。&lt;/li>
&lt;li>微服务统一控制面的演进,这一块其实有很多的可能性,作为控制面其实它处在一个决策者的位置,一定程度上具备整个系统的上帝视角,在AI技术火爆的当下大有可为。&lt;/li>
&lt;li>治理能力与社区生态的贡献,大家可以参与到服务治理能力的演进中,也可以贡献各个社区和OpenSergo体系的对接。&lt;/li>
&lt;/ul>
&lt;p>最后我想说,微服务治理其实是一个很广阔的平台,参与其中,你可以接触到各个领域的技术与场景,而不是被限制在单点技术范围内摸爬滚打。欢迎企业与社区同学加入开源贡献小组,一起主导下一代微服务技术体系的演进!&lt;/p></description></item><item><title>Blog: Seata 微服务架构下的一站式分布式事务解决方案</title><link>https://dubbo.apache.org/zh-cn/blog/2023/10/07/seata-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E4%B8%8B%E7%9A%84%E4%B8%80%E7%AB%99%E5%BC%8F%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</link><pubDate>Sat, 07 Oct 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/10/07/seata-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E4%B8%8B%E7%9A%84%E4%B8%80%E7%AB%99%E5%BC%8F%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</guid><description>
&lt;p>摘要:本文整理自阿里云分布式事务产品负责人、Seata 开源项目创始人、微服务开源治理负责人季敏的分享。本篇内容主要分为三个部分:&lt;/p>
&lt;ul>
&lt;li>一、微服务架构下数据一致性的挑战&lt;/li>
&lt;li>二、分布式事务Seata的架构演进&lt;/li>
&lt;li>三、如何基于Seata扩展RPC和数据库&lt;/li>
&lt;/ul>
&lt;h2 id="一微服务架构下数据一致性的挑战">一、微服务架构下数据一致性的挑战&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>在2019年,我们基于Dubbo Ecosystem Meetup,收集了2000多份关于&amp;quot;在微服务架构,哪些核心问题是开发者最关注的?&amp;ldquo;的调研问卷。最终分布式事务占比最大,有54%。&lt;/p>
&lt;p>但在Seata出现之前,大家都说分布式事务能避就避,因为消息最终一致性去解释了问题。但Seata开源之后,这些问题都迎刃而解。比如无损上下限,到底是说服务的可用性还是其他的。对于我来说,我觉得它最终关注的是数据的问题。因为无论前端的业务怎么去交互,最终都会沉淀到数据。如果业务的数据不一致,前面是什么架构,都意义不太大,所以我认为数据是企业的核心资产。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_1.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>那么到底哪些场景会遇到分布式事务的问题呢?&lt;/p>
&lt;p>第一个场景,在拆分成微服务架构之后,不同的服务可能由不同的团队负责上下游的协调联动。比如C服务发布的时候,并不会通知A服务和B服务,这个时候就会遇到上下线带来的数据一致性的问题。&lt;/p>
&lt;p>第二个场景,不可靠、不稳定的基础设施,会导致网络或者个别主机的宕机。&lt;/p>
&lt;p>第三个场景,timeup是分布式架构里比较难解的状态,因为一旦出现服务调用的timeup,这个服务的业务逻辑到底是执行了,还是没有执行timeup的服务怎么实现数据的密度,都是比较尖锐的问题。&lt;/p>
&lt;p>第四个场景,业务里除了会涉及到数据库,还会涉及第三方的组件。比如缓存、Redis,我们的库存会先经过Redis这样的组件,那么如何实现它的一致性也是个问题。&lt;/p>
&lt;p>第五个场景,我们在上下游做业务的时候,你传给我一些参数,但这些参数本身可能是非法的。那么我就需要把你的下服务也回关掉,而不是只有我这一个服务去做拒绝。&lt;/p>
&lt;p>所以分布式事务的场景主要包括了跨库、跨服务、资源的多样性。异常上主要包括业务异常、系统异常。&lt;/p>
&lt;p>那么分布式事务是不是微服务架构独有的问题呢?其实不是,它在单体应用里也有类似的问题,只不过在微服务架构里它的问题更凸显。&lt;/p>
&lt;p>在单体架构下存在哪些分布事务的场景呢?比如一个单体应用要去修改多个数据库或者多模块的,整体而言,单体数据库它完成的是ServerSission下边的一个本地事务。只要跨了这个本地事务,其他的都是分布式事务,即使微服务都去修改同一个数据库。这样其实你的数据库的本身也不是能反序列化传递到另外一个服务的,这些问题都会涉及到分布式事物的问题。&lt;/p>
&lt;p>整体看起来,分布式事物涉及到了分布式架构和单体架构中非常广泛的应用。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_2.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>市面上的分布式事务方案有以下六类:&lt;/p>
&lt;ul>
&lt;li>XA模式,它的问题是吞吐量和性能要差一点,在一致性上是最高水准。&lt;/li>
&lt;li>TCC模式和SAGA模式,可以归结为是一个业务层面的分布式事务,因为他不会拦截数据。比如TCC模式可能有cc接口,至于这个接口怎么回滚,怎么正向的,在框架层面完全不用管。这可能是你里边逻辑本身不是对等的,也不是框架已经参与的,所以更多的是把接口暴露给了业务实现。&lt;/li>
&lt;li>消息最终一致性,它最大的优点是实现异步化的解耦,结合消息的削峰填补的特点。但它本身存在着一些问题,对消息来说,他更多的是做一个单项的通知。这个通知可能对于一些消息消费来说,即使业务失败了,它也没法去回滚。&lt;/li>
&lt;/ul>
&lt;p>比如现金红包的业务,我首先要将红包转到我的账户,然后再从我的账户转到我的银行卡。可能消息消费的时候我这个账户已经注销掉了,那么你的消息消费就会一直处在失败的状态。对于这类问题,不可能再把上游消息的发送给关掉,所以它更多的是单项通知的场景。&lt;/p>
&lt;ul>
&lt;li>定时任务补偿,它的学习成本低,但实践成本高。尤其是微服务的链路有多翘的节点,需要业务逻辑写的非常周全。&lt;/li>
&lt;li>AT模式,它综合了一致性性能,主要的特点是简单无侵入,强一致,学习成本低。缺点是需要遵守一定的开发规约,并且它不是对所有的SQL类型都支持,它有一定限制。从业务场景上来说适应的是一个通用的场景,但它并不适应于热点数据类型的高并发场景,比如SKU的库存的部件。因为在这个模式它有一个应用层的分支锁,需要对相同的数据做一个排队的等待。&lt;/li>
&lt;/ul>
&lt;h2 id="二分布式事务seata的架构演进">二、分布式事务Seata的架构演进&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_3.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>Seata在阿里内部的代号叫TXC,在蚂蚁叫DTX。它起源于集团的五彩石项目,五彩石的项目是当初集团内在做去IOE,从单体架构引进到分布式架构。在分布式架构必然会涉及到很多的中间价,TXC承担的主要的角色做服务一致性的保证。&lt;/p>
&lt;p>我们和集团内的三大件都做了深度的集成,包括服务调用框架HSF,也就是对外开源的Dubbo;数据库有分库分表的TDDL组件;异步消息的MetaQ组件。在集团内也有广泛的使用,日均百亿级别调用,标准3节点集群吞吐达近10w TPS。&lt;/p>
&lt;p>我们的SLA会分为几个SLA,一个是可用性的SLA服务,另外一个是性能的SLA服务。因为对于分配事物来说,除了要保证一致性,也要保证性能的吞吐量。所以我们规定比如每一次的RT额外的开销不能超过XX。目前能达到毫秒级的事务处理,能保证在稳定性上全年无故障。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_4.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>最开始我们在做分布式事务实现的时候,我们也去考虑我们的分布式事务应该是在哪层面去实现?&lt;/p>
&lt;p>从应用架构的视角,分为这么几层,一个是最上层的应用开发框架,可能每一套公司都有自己的开发框架,比如像ddt的开发框架或者club的体系等等。再下一层是服务调用框架,类似于Apache Dubbo主要承担,也在国内使用的非常广泛。再下一层是数据中间件,这层主要包括ORM框架、事务、同步、对账。再下一层是跟数据库连接,这一层类似于JDBC、Java去连数据库。&lt;/p>
&lt;p>我们去做了一个简单的对比,到底是在哪层实现分布式事务,是在DB层、数据中间件层还是应用框架层?&lt;/p>
&lt;p>在应用框架层,它去实现一致性相对来说比较弱,因为你会掺杂很多复杂的、不可控的因素,会把服务调用的因素给牵扯进去。比如服务调用的超时,这就是为什么我们现在有的像TCC模式它会有一些密等、放悬挂那些问题。都是因为融入了RPC的因素,持续的不确性导致的一些问题。&lt;/p>
&lt;p>在数据中间件层,它的一致性比应用框架要好一些,它主要的问题是他不是在DB层实现的,所以我是有办法绕过中间件直接去修改DB的,这时候就会存在事物并发时序的问题。最好的一致性是在DB层去实现数据一致性,但这一层数据一致性主要是数据库的厂商,但是也是参差不齐。比如Msever,他在5.7.7版本才把差异完善起来,在之前的版本它对差异回滚一直是有问题的。&lt;/p>
&lt;p>但它只能局限在数据库的scope,如果我要去更大的scope,从应用架构层可能要跨服务,跨服务这一层它就管不了,只能管我自己数据库。所以他最终还是需要有一个第三方的去协调跨服务的数据一致性。最终我们把这一层AT差异模式是把它做到了数据库中间件这层,JDBC server这层我们做到了应用开发框架这层。&lt;/p>
&lt;p>所以它不仅实现了一整套的集团生产体系,还包括了我们对分布式事务编程模型的定义,运维安全。因为要涉及到数据,会有数据的敏感以及性能和观测高可用等等。&lt;/p>
&lt;p>在理论模型上我们当时还是比较匮乏的,我们做了一些对差异以及Spring事物模型的延展。我们延展了已有的模型,而不是新造一条。这于开发者来说,学习成本会更低。&lt;/p>
&lt;p>此外,我们还做了一些定义,包括怎么定义一致性,是定义多节点的一致性,还是业务应用架构数据的一致性,以及这套架构里的角色模型设计的事物动作和隔离。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_5.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>什么是分布式事务的模型定义?举个例子,我去做银行转账的时候,我给你转100块钱,恰好这个时候出现了网络超时,那么这100块钱到底有没有扣。如果不确定就可能出现资损的问题,甚至可能影响企业的商誉。&lt;/p>
&lt;p>我们都在谈分布式架构,但从整个应用的视角,并不是所有东西都是分布式的。比如我们从一个应用的架构的层面去看数据库,包括今天称之为分布数据库。从整个应用层面,它我们看它是一个集成式的数据的存储。它的内部实现可能是分布式的,包括分布式的链路数据。&lt;/p>
&lt;p>因为在分布式的应用架构里,每个业务的节点都只掌握了部分的信息。如果做一些问题的排查,必然需要一个集成式的东西。对于分布式事务它的核心工作是做分布式协调,所以他要掌握全局的信息。&lt;/p>
&lt;p>这就是为什么我们有了Transaction Coordinator。对他来说,他要有一个上帝视角,充当第三方的协调器。而真正做事的是Resource Manager,你可以认为它是数据库的灵魂,我们需要把它作为Pro。&lt;/p>
&lt;p>真正随着业务应用去做事务的动作是Transaction Manager,它会随着业务的执行链路进行,到底直接事务的边界是怎么样的,以及分布式事务的动作是怎么样的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_6.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>2019年1月Seata开始开源了,我们主打的特点特色是AT 模式,因为是组装,我们从0.1版本就把AT模式给开源出去了。0.4版本我们纳入了TCC的模式,因为AT模式它需要适配不同的数据库。而在现有阶段我们不能满足对所有数据库的支持以及缓存资源,这就需要应用TCC模式去做补充。你可以用TCC模式做一些我们没实现的数据库以及缓存的结构。&lt;/p>
&lt;p>在0.9版本,我们纳入Saga的事务模式,它主要解决长事务方解决方案。比如一个事务非常长,且还有微服务的编排工作。在1.1版本,我们纳入了XA的事务模式,因为有的客户已经应用了Seata的AT模式,但他还有一些老的特别事务。他希望应用Seata统一的一套解决方案,解决不同业务常用的分支事务,所以我们把XA的事务模式也纳入进来了。&lt;/p>
&lt;p>最终从整个架构上来说,我们是打造了一站式的分布式事务的解决方案。针对不同的业务场景,Seata都能做事务。如上图所示,目前市面上没有一只分布事务的模式,能解决不同业务场景的问题。主要强调几个问题,分布式事务可能有同步的分布式事物,有异步的分布式事务,以及对分布式事务的一致性的要求也不高。有强一致性,最终一致性,弱一致性。&lt;/p>
&lt;p>另外,对于事物执行时间的长短也有要求。比如有长事务、短事务以及性能吞吐量等等。所以我们纳入了现在的四种事务模式,它们从改造成本、性能隔离性上各有所长,这里就不展开介绍了。&lt;/p>
&lt;h2 id="三如何基于seata扩展rpc和数据库">三、如何基于Seata扩展RPC和数据库&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_7.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>首先看一下Seata开源社区这几年的发展。目前Seata已经具备了AT、TCC、Saga、XA四种事务模式,而且对于市面上主流的关系数据库,RPC框架做了广泛的支持,同时被许多第三方社区做了主动和被动集成。已经和三十多个社区做了集成,这些集成都放在我们的扩展机制里边。&lt;/p>
&lt;p>目前多语言体系也做起来了,除了最开始的Java,Go语言支持的也非常成熟,欢迎大家去使用我们的Go版本,给我们提更多宝贵的建议。另外,我们还建建设了多语言版本,包括PHP、Python等等。&lt;/p>
&lt;p>目前 Seata 开源产品已被上千家企业在业务系统中应用,金融企业纷纷试点。我们都知道金融类的业务对分布式事务是强需求,而且它的业务场景非常严苛。像中信银行、光大银行、农行我们也做了一些社区上的合作,改造一些他们的核心账务系统,用Seata保证他们账务体系的数据一致性。&lt;/p>
&lt;p>目前Seata社区的Star数已经到达了24k,contributor有300+。并且Seata社区是非常开放的,现在整个Seata的框架代码有70%来自创始团队之外的外部贡献者,所以欢迎大家积极的参与到我们Seata社区里。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_8.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>接下来介绍一些Seata比较典型的企业案例。&lt;/p>
&lt;p>第一个案例,中航信航旅纵横项目。中航信是Seata 最早的天使用户,用的是Seata 0.2版本。如果大家出差比较频繁,应该会用到它们的APP,航旅纵横。它解决机票和优惠券业务的数据一致性问题。虽然在早期的版本中陪我们踩了不少坑,但最终还是应用起来。&lt;/p>
&lt;p>第二个案例,滴滴出行二轮车事业部。它在Seata 0.6.1版本就将 Seata 引入到了二轮车事业部的各个业务中,包括市面上大家看到青桔单车,还有他们内部的资产管理。&lt;/p>
&lt;p>第三个案例,美团基础架构。美团基础架构团队基于开源 Seata 项目封装了内部分布式事务 Swan 项目,作为美团内部各业务解决分布式事务问题的组件。&lt;/p>
&lt;p>第四个案例,盒马小镇。盒马小镇游戏互动中通过 Seata 控制偷花的流程,开发周期从20天下降至5天,大幅度减少了开发的成本。&lt;/p>
&lt;p>综上可以发现分布式事务的两个价值。&lt;/p>
&lt;ul>
&lt;li>业务的正确性,因为只有数据一致了谈架构才有意义。&lt;/li>
&lt;li>Seata大幅度提高了开发迭代的效率。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_9.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>上图是Seata生态的扩展点。最上层我们定义了API这一层,中间这一层包括注册、配置中心等等,下边是群的模式,包括基于关系数据库DB的,Redis的以及现在2.x里正在推广的rough模式,负载均衡也有各种模式,以及对于分布式锁扩展也是基于各种各样的模式。目前我们对于关系型数据库也支持的挺多的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_10.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>我们在做Seata机制的时候参考了Dubbo的机制,对我们的学习成长以及社区的成长还是非常有帮助意义的。我们把扩展点充分发挥到了极致,分为server侧的扩展点以及客户端的扩展点。客户端扩展点大概有30+个,server侧的扩展点包括锁的扩展、存储的扩展以及事务模式的处理。&lt;/p>
&lt;p>从今天来看如果你去支持数据库、国产达梦、人大金仓,成本都比较低。只要按照我们的文档,按照API的扩展点去做简单的实践,就能把整个流程跑起来。另外,我们server不同的锁的存储,事务筛选的存储都是可以扩展的。这里我们也是借鉴了Dubbo去做了一些对开发者非常友好的扩展,让开发者更容易的扩展市面上的RPC框架以及数据库。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_11.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>目前我们支持了11中RPC框架,Dubbo是我们核心要支持的。我们类似于Dubbo,基于一般RPC都有fell或者ins。我们核心要做的是把Seata事物上下文通过服务调用链路给传递下去。并且把事物链路还原到服务里边去做事物的绑定、解除、清除等等,这个核心我们扩展起来还是比较容易的。&lt;/p>
&lt;p>核心的话右边我们实现了一些接口,目前我们对Dubbo生态,包括老的阿里巴巴Dubbo以及Apache我们都做了充分的支持。欢迎大家在Dubbo的生态去适应一下Seata分布式事物去体验一下。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/seata/img_12.png" alt="dubbo-seata-分布式事务最佳实践">&lt;/p>
&lt;p>目前Seata数据库支持MySQL、OceanBase、Oracle等等数据库,其中有一些PR还没有合并,比如达梦、IBMDB2。就像我刚才说的,我们只要基于当前的扩展点,我们就能做充分的扩展。&lt;/p>
&lt;p>最近我们也是做仓库的编程之下,也是让我们眼前的同学感觉一下,它也做了一些PolarDB的支持,后边我们会对数据库的生态top 20完整的支持起来。&lt;/p></description></item><item><title>Blog: 基于 Triple 实现 Web 移动端后端全面打通</title><link>https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E5%9F%BA%E4%BA%8E-triple-%E5%AE%9E%E7%8E%B0-web-%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%90%8E%E7%AB%AF%E5%85%A8%E9%9D%A2%E6%89%93%E9%80%9A/</link><pubDate>Sat, 07 Oct 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E5%9F%BA%E4%BA%8E-triple-%E5%AE%9E%E7%8E%B0-web-%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%90%8E%E7%AB%AF%E5%85%A8%E9%9D%A2%E6%89%93%E9%80%9A/</guid><description>
&lt;p>摘要:本文整理自陌陌研发工程师、Apache Dubbo PMC陈有为在 Community Over Code 2023 大会上的分享,本篇内容主要分为四个部分:&lt;/p>
&lt;ul>
&lt;li>一、RPC 协议开发微服务&lt;/li>
&lt;li>二、全新升级的 Triple 协议&lt;/li>
&lt;li>三、Triple 协议开发微服务&lt;/li>
&lt;li>四、Dubbo 为 Triple 协议带来治理能力&lt;/li>
&lt;/ul>
&lt;h2 id="一rpc-协议开发微服务">一、RPC 协议开发微服务&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>在我们正常开发微服务的时候,传统RPC服务可能在最底层。上层可能是浏览器、移动端、外界的服务器、自己的测试、curl等等。我们可能会通过Tomcat这种外部服务器去组装我们的RPC层,也就是BFF。或者我们没有BFF,我们的RPC就是对外提供服务。但因为浏览器要访问,所以我们需要有一个网关,比如说Apisix或者ShenYu等HTTP网关。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_1.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>上图展示的是我们的流程,但是存在一些问题。&lt;/p>
&lt;p>如果我们的服务是非常轻的,我们只需要一个转发层,我们是不是很麻烦。无论是配网关还是起一个webserver去转发,肯定都很麻烦。&lt;/p>
&lt;p>此外,RPC服务大部分都是基于二进制的,而二进制正常在本地是没法测试的。因此我们的公司内都可能就会开发一种后台或者中间的Process让我们去测试。但这个的前提是你至少得把它部署到测试环境,所以还是没法在本地测试。&lt;/p>
&lt;p>总体来说,这两个问题的易用性比较低,且开发成本相对较高,因为要做一些重复劳动。&lt;/p>
&lt;h2 id="二全新升级的-triple-协议">二、全新升级的 Triple 协议&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_2.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>基于上边的两个问题,我们来介绍一下Triple协议。&lt;/p>
&lt;p>先来说一下上一代协议,它产出的原因是什么。我们应该都知道Dubbo原来是Dubbo协议,它是基于tcp的,它有一个包。因为它的包的设计,导致了网关无法做一些特殊规则判断、过滤等操作。但也不是绝对的,如果你愿意牺牲性能把包完全解出来,组装回去再透传还是可以做到的,但一般大家都不太能接受。&lt;/p>
&lt;p>所以我们就在想能不能把原数据和真正的包分开。现在我们有现成的HTTP,又有一个业界主流的gRPC,所以我们的目标就是兼容gRPC。因为gRPC目前都是用IDL,而IDL有一个问题,尤其在Java侧。因为大家都是写一些接口,定义一些包去实现,这样就会非常麻烦。Go侧就还好,因为大家已经习惯了这种开发模式。&lt;/p>
&lt;p>所以我们开发了Triple协议,首先它兼容了gRPC,所以我们能实现和gRPC的完全互通。其次,我们兼容了自己定义接口的方法。虽然会损失一定的性能,但提升了一些易用性。而且RPC一般不是业务的瓶颈,大多数瓶颈还是在DB。&lt;/p>
&lt;p>但还有个问题,虽然我们兼容了gRPC,但gRPC是基于TPC的,所以如果前端或者其他第三方系统只有HTTP,它还是接受不了我们的系统。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_3.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>基于此,我们想推出一个全新的Triple协议。为了解决上述的所有问题,我们参考了gRPC、gRPC Web、通用HTTP等多种协议,做到浏览器访问,支持Streaming,还支持同时运行在 HTTP/1、HTTP/2 协议上。因为目前HTTP/3还没有大规模推广,未来也会支持HTTP/3。&lt;/p>
&lt;p>最终的设计实现是完全基于HTTP的,且对人类、开发调试友好。我们可以通过简单的浏览器访问或者curl访问,尤其是对unary RPC。此外,我们和gRPC是完全互通的,用HTTP的业务不用担心兼容性的问题,也不用担心签协议的问题。为了稳定性,我们只会采用业界流行的网络库,比如Java的netty、Go的基础的net包。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_4.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>虽然Triple协议和gRPC协议都基于HTTP,但gRPC是基于HTTP/2的,而Triple是基于HTTP/1和HTTP/2的。&lt;/p>
&lt;p>我们在进入gRPC的同时,我们为了易用性扩展了一些功能。比如请求里我们支持application Json,curl访问,此外上一版的协议,为了支持传统定义接口的方式,我们有一个二次序列化的过程。我们想在这里通过一个特殊的tag来决定我们的body的结构,解决二次序列化的问题。同时这个东西是可以扩展的,理论上HTTP的所有future我们在Triple协议上都可以实现,也可以拓展。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_5.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>用了Triple协议之后,我们的开发流程也发生了改变。如果你不需要进行组装,或者没有外层的代理,可能你的接入流程就是从外部的请求浏览器、对方的服务器、curl、自己测试等直接到了server。&lt;/p>
&lt;p>和其他的gRPC的通信也是没有问题的,流程就相当于少了一层。对于大多数用户,如果你不需要这个场景,其实是有很大的好处。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_6.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>Triple协议因为最开始兼容gRPC,那个时候只基于HTTP/2,HTTP/2有Streaming的能力,所以它天然支持Streaming。但这里比较特殊的是,我们新版的协议在HTTP/1也支持了Stream,但仅支持了Server Stream。也就是客户端发一个,服务端发好几个回去,这个HTTP/1的Server Push实现的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_7.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>Client Stream和Bi Stream就没什么可说的了。但有一个特别的是,在Java侧没有Bi Stream,从编码上就没有,但从实现上是有的。&lt;/p>
&lt;h2 id="三triple-协议开发微服务">三、Triple 协议开发微服务&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_8.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>目前Triple协议比较灵活的支持两种定义方式,分别是IDL定义和直接定义。直接定义支持同步、异步、手写。还有比较极端一点的,比如在自己定义接口的时候用IDL生成probuff的类,我们不定义它的service,只用它的接口也是没问题的,它会自动识别接口使用pb还是不使用pb。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_9.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>Server就是把它的务实现一下。上图是一个例子,我就直接拿了API的组装方式,真正的业务上可能是注解或者XML的方式。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_10.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>因为我们支持了HTTP这个标准的协议,理论上我们的测试就会变得很简单。&lt;/p>
&lt;p>因为我们支持gRPC,所以我们可以用gRPC curl去调用我们的服务。但前提是你得有反射服务,然后手动开启一下,它不是默认开启的。然后它就可以通过反射拿到接口的源数据,通过Json转成pb格式发过去。或者我们直接用Application Json的方式直接调过去。这里有一点比较特别的是在HTTP/1下我们也可以用Sream。&lt;/p>
&lt;p>另外,因为我们支持HTTP,理论上所有第三方的HTTP客户端都是可以调用的。然后我们的admin也可以进行测试,前提是你得把它注册上。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_11.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>调用端不管是POJO还是IDL,它们都没有本质的区别。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_12.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>现在我们有了Triple协议,但如果这个协议没有承载方也是行不通的。因此我们还得有一个框架,有一些服务治理才是我们的微服务。所以服务治理也是微服务中不可或缺的一部分。&lt;/p>
&lt;h2 id="四dubbo-为-triple-协议带来治理能力">四、Dubbo 为 Triple 协议带来治理能力&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_13.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>Triple的定位只是Dubbo里的其中一个协议,当然你也可以为了兼容性,用原来的Dubbo协议或者其他的协议。而且我们支持在同一个端口上开多个协议,可以按需选择。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_14.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>同时Dubbo 为 Triple 提供了多语言的实现。目前会在Rust、Go、Java、JS、node、Python这几部分实现官方的实现。这样用户就不用自己根据实验协议的spec去实现了。如果你有一些定制需求,比如内部的一些框架,你根据spec实现也是可以的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_15.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>Dubbo和服务框架集成的很好,理论上在开发流程中,尤其是在Java侧服务定义、服务治理、服务注册发现等都不用客户来操心,是开箱即用的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_16.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>Dubbo 提供了丰富的生态,第三方的生态包括Nacos、Zookeeper等等,我们不用创新,直接引入相应的包即可。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_17.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>这是我们使用Triple协议服务注册的例子。上面你可以选Nacos、Zookeeper、K8s,左边是一个Client和一个Server,这么调用。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_18.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>我们在admin上看一下实现。这里提一句,我们的admin也在新版重构,是用Go实现的,大家可以期待一下。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/triple/img_19.png" alt="dubbo-triple-协议">&lt;/p>
&lt;p>我们经常会遇到灰度发布或者流量染色的需求。我们可以从admin上发一个tag下去,把一些实例打上tag,然后这个流量从入口就会挨个下去。&lt;/p></description></item><item><title>Blog: 启动速度提升10倍:Apache Dubbo 静态化 GraalVM Native Image 深度解析</title><link>https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E5%90%AF%E5%8A%A8%E9%80%9F%E5%BA%A6%E6%8F%90%E5%8D%8710%E5%80%8Dapache-dubbo-%E9%9D%99%E6%80%81%E5%8C%96-graalvm-native-image-%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/</link><pubDate>Sat, 07 Oct 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E5%90%AF%E5%8A%A8%E9%80%9F%E5%BA%A6%E6%8F%90%E5%8D%8710%E5%80%8Dapache-dubbo-%E9%9D%99%E6%80%81%E5%8C%96-graalvm-native-image-%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/</guid><description>
&lt;p>摘要:本文整理自杭州有赞科技有限公司中间件技术专家、Apache Dubbo PMC华钟明在 Community Over Code 2023 大会上的分享。本篇内容主要分为五个部分:&lt;/p>
&lt;ul>
&lt;li>一、GraalVM 直面Java应用在云时代的挑战&lt;/li>
&lt;li>二、Dubbo 享受 AOT 带来的技术红利&lt;/li>
&lt;li>三、Dubbo Native Image 的实践和示例&lt;/li>
&lt;li>四、Dubbo 集成 Native Image 的原理和思考&lt;/li>
&lt;li>五、Dubbo 在 Native Image 技术的未来规划&lt;/li>
&lt;/ul>
&lt;h2 id="一graalvm-直面java应用在云时代的挑战">一、GraalVM 直面Java应用在云时代的挑战&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>云计算时代比较显著的特点包括:&lt;/p>
&lt;ul>
&lt;li>基于云计算的基础设施,Java应用能够在云计算的基础设施上快速、轻松、高效的做到弹性。&lt;/li>
&lt;li>基于容器化技术,系统资源切分的更加细,资源的利用率也更高了。&lt;/li>
&lt;li>基于云计算的开发平台,让应用部署的更加容易,更加敏捷。&lt;/li>
&lt;/ul>
&lt;p>那么在云计算时代,Java应用存在哪些问题呢?&lt;/p>
&lt;ul>
&lt;li>冷启动速度较慢。&lt;/li>
&lt;li>应用预热时间过长,无法立即达到性能峰值。&lt;/li>
&lt;li>内存、CPU等系统资源占用高。&lt;/li>
&lt;li>Java构建的应用程序繁重,执行还需要具备JDK环境。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_1.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>在Serverless场景上,Java的问题会尤为突出,因为Serverless不仅能简化开发场景和开发体验,还能做到极致的弹性,甚至是秒级的弹性。&lt;/p>
&lt;p>上图是Datalog统计的Fast和AWS两个产品。Java语言虽然更流行,但相较于Python和Node.JS,它的占比还是比较低的。Java本身在Serverless层面,比如在做容器的调度、镜像的下载的时候,启动时间、冷启动的时间、预热时间等等,都会影响Serverless场景下它弹性扩容的时间。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_2.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>下面介绍一下GraalVM,它是可以把Java应用提前编译到独立的二进制包内,这些二进制包相对于跑在JVM上它可以更小,更快的启动,不需要预热就能够达到极限的峰值,还可以减少内存和CPU的占比。&lt;/p>
&lt;p>可以看到它的介绍和Java语言的应用所涉及到的问题都一一对应。GraalVM应该算是JDK的&amp;quot;超集&amp;quot;,除了包含完整的JDK发行版本外,还有GraalVM Compiler、Native image、Truffle等,甚至还涉及到多语言汇编的能力。&lt;/p>
&lt;p>总结一下,GraalVM本身涉及两部分,JIT和AOT。&lt;/p>
&lt;ul>
&lt;li>JIT,是在编译后的class文件、字节码文件,它会在运行时把它翻译成机器码。&lt;/li>
&lt;li>AOT, 它和JIT的区别是,它在编译期就能把字节码直接转化为机器码,无需在运行时再去处理。所以它的CPU和内存会相对更低。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_3.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>上图左侧是一张Java生命周期的全景图。可以看到,它从JVM的启动,再到Java的main函数的启动,再到Java的应用预热,再到它的稳定期,最后到达效果,这是Java完整的生命周期的呈现。&lt;/p>
&lt;p>而AOT的区别在于,它没有红色的VM。另外,JIT相对于AOT而言是没有的,也没有浅绿色的解释器。所以AOT对于JIT来说,只有内加载,GC以及它能够瞬间达到应用的稳定期。&lt;/p>
&lt;p>根据右侧的图可以看出:&lt;/p>
&lt;ul>
&lt;li>AOT的启动耗时相对较低,内存损耗和它打出来的二进制包相对较小。&lt;/li>
&lt;li>JIT因为有及时编译的效果,所以现在极限的分值比AOT要好,比如它的极限吞吐量比AOT好。&lt;/li>
&lt;/ul>
&lt;h2 id="二dubbo-享受-aot-带来的技术红利">二、Dubbo 享受 AOT 带来的技术红利&lt;/h2>
&lt;ol>
&lt;li>多产物形态&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_4.png" alt="dubbo-graalvm-native-image.png">&lt;/p>
&lt;p>我们在编码之后,Soft Code的产物形态新增了。&lt;/p>
&lt;p>第一种是我们传统认知上的Jar包形态,比如mvn、clean、package。第二种是Docker Image,它能轻松的帮我们直接打到镜像里面去,不用写dockerfile等文件。第三种是我们集成GraalVM后新产生的一种Native可执行文件的形态。这种形态无需JDK的环境就能启动,它能像GO一样把二进制文件直接启动。&lt;/p>
&lt;ol start="2">
&lt;li>启动耗时大幅降低&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_5.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>上图的跑分都是基于4c16g的micro24的系统上跑出来的。左边和右边的区别是,左边的Provider端提供了一个Dubbo服务跑出来的,右边是提供了一个调用者的身份跑分出来的。从左边这张图可以看到,Native的可视性文件比Jar包方式的启动耗时降低了12倍+,在客户端应用,它的启动耗时降低了11倍+。所以在刚刚提到的Serverless场景上,它能提供一个非常好的启动速度。在扩容的时候能够达到秒级,甚至达到毫秒级。&lt;/p>
&lt;ol start="3">
&lt;li>启动后立即达到性能峰值&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_6.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>上图也是跑分跑出来的数据,可以看到Consumer和Provider端通过静态化执行文件执行后,比都为Jar包的情况,第一次调用的耗时降低6倍。这第一次调用代表的是预热的时长,以及第一次需要解析的类,包括资源的情况等等。这让我们在Serverless场景下能够瞬间达到性能峰值。&lt;/p>
&lt;ol start="4">
&lt;li>内存损耗大幅降低&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_7.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>上面有左右两张图,在Dubbo应用的基础上,它的内存损耗也降低大概3.5倍。Native静态化执行文件可以做到60M的内存占比,在客户端它的内存损耗也大概降低了4倍。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_8.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>这是Dubbo在Native Image技术场景中做的努力:&lt;/p>
&lt;ul>
&lt;li>易用性增强:在注解和XML方式中自动识别服务接口,生成Reachability Metadata。&lt;/li>
&lt;li>可维护性增强:自动生成Source code,减轻了Dubbo开发者维护Adaptive的维护成本。自动扫描生成Dubbo core 所需的Reachability Metadata。&lt;/li>
&lt;li>多平台的支持:Linux、MacOS、Windows。&lt;/li>
&lt;li>多功能的覆盖:Dubbo、Triple协议。&lt;/li>
&lt;/ul>
&lt;h2 id="三dubbo-native-image-的实践和示例">三、Dubbo Native Image 的实践和示例&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_9.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>首先需要安装Dubbo Native Image,这里就不过多介绍了,大家可以根据官方的文档进行下载。&lt;/p>
&lt;p>然后安装插件,可以看到上图中有三个插件需要安装,但和Dubbo相关的只有一个,是Dubbo Maven Plugin。除此之外,还有Spring Boot 的Maven Plugin,它提供的是Spring的AOT的能力。如果是API的接入方式我们无需加这个插件,如果是XML和注解就还需要加这个插件。第三个是GraalVM提供的插件,可以看到这里加了一个reachabilitu-metadata的执行,这个后面会介绍到。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_10.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>然后配置依赖,现在Dubbo关于可达性元数据的扫描、执行,以及配置文件和Source code的生成都在Dubbo Native的依赖下面,我们需要引入这个依赖。&lt;/p>
&lt;p>另外,注解和XML的还是需要接入一个Spring6的兼容的包。因为Dubbo现在还兼容JDK 8的版本,而Spring6发布后支持的最低版本是JDK 17,所以我们还是需要有这么一个模块做一下兼容。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_11.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>最后还需要加一个插件和依赖,然后就能轻松的把应用转化成Native Image的形式。&lt;/p>
&lt;p>最下面是完整的代码示例,大家感兴趣的话,可以尝试一下编译打包,看一下执行的效果。&lt;/p>
&lt;h2 id="四dubbo-集成-native-image-的原理和思考">四、Dubbo 集成 Native Image 的原理和思考&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_12.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>首先看一下Dubbo集成GraalVM Native Image技术的发展历程。2021年6月我们发布了Dubbo 3.0版本,初步探索了Native Image技术,提供了一个实验性的版本和Demo,涉及到的问题包括以下三个。&lt;/p>
&lt;ul>
&lt;li>维护繁重的Adaptive源码、维护Dubbo所需的全量Reachability Metadata。可能涉及到的问题是,比如要新增一个功能,我们需要考虑coding以及code review的时候是否要添加可达性的元数据,这也会造成维护成本非常高。&lt;/li>
&lt;li>仅支持API方式,不支持注解和XML方式。&lt;/li>
&lt;li>dubbo-native-plugin的插件,在后面3.1版本的时候,Native Image的发展并不多。&lt;/li>
&lt;/ul>
&lt;p>2022年11月Spring6+Spring Boot3正式发布了,它把Native Image技术作为发布的亮点展现给大家。但Dubbo社区认为我们应该对Native Image技术有一个新的跨越,所以在2023年4月发布了Dubbo 3.2版本,将Native Image技术进行了思考和重构。支持以下四个方面:&lt;/p>
&lt;ul>
&lt;li>编译阶段自动生成Adaptive源码,已经不需要开发者维护了。&lt;/li>
&lt;li>支持编译阶段自动生成Dubbo所需的Reachability Metadata。减小了打在业务启动的可执行文件里包的大小。因为在之前的版本里,它是把Dubbo所涉及的全量的可达性的元数据都打在二进制包里。比如业务用jka作为注册中心,我们把nacos也打在那里面,这就会导致它的二进制包非常大。现在这个版本如果用到jka,我们在box上解析不到nacos相关的依赖。所以我们就不会再把相关的内容打进去了,而且现在都是自动识别的。&lt;/li>
&lt;li>新增dubbo-maven-plugin,用于替代dubbo-native-plugin。因为dubbo-native-plugin的能力和内容是比较聚焦的,我们把它重新归名为dubbo-maven-plugin后,涉及到的是我们能够降低业务接入的薪资负担。后面Dubbo相关的maven插件,都通过它来做就行了。&lt;/li>
&lt;li>兼容了Spring6+Spring Boot3,这就是我们在下个版本把XML和注解支持上去的技术的基础。&lt;/li>
&lt;/ul>
&lt;p>2023年12月将会发布Dubbo 3.3x版本。它基于Spring6,完成对XML和注解方式的支持,还移除了dubbo-native-plugin。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_13.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>刚刚提到了非常多次Reachability Metadata可达性的元数据,到底是什么呢?&lt;/p>
&lt;p>我们先来聊一聊AOT的局限性,它本身就有局限,它遵循封闭世界的一个假设。比如它只关注能看到的所有字节码的信息,这就会带来一个问题,Java动态语言的功能就不再支持了。也及时说JNI、Java反射、动态代理、ClassPath资源的获取等都不再支持。&lt;/p>
&lt;p>我们知道,在组件/业务开发/使用产品上涉及到的这些功能是非常多的,既然GraalVM出了这个功能,当然也考虑到了这个问题,所以它利用Reachability Metadata的能力解决了这些问题。&lt;/p>
&lt;p>右边的这张图分为了五类,它涉及到了JNI、反射、序列化、resource、proxy相关的元数据的配置信息。它可以让开发者在编译前就提供好这些元数据信息,提前打包到可执行的二进制文件中。还有第六种分类,是预定义的类型,他需要提供完整的字节码Hash值,所以就没列出来,它可能需要和Tracing的agent联合起来使用。&lt;/p>
&lt;p>下面我们主要介绍一下这五类。&lt;/p>
&lt;p>第一,GraalVM 提供了Tracing Agent来辅助应用采集Reachability Metadata,也就是说在运行期间它会去采集你的行为,比如你要用到反射,他会把反射的元素自动生成出来,然后生成出一个配置文件提供给你。但是并无法确保把所有都采集完整。&lt;/p>
&lt;p>第二,GraalVM提供了Reachability Metadata Repository,用于管理三方组件的Reachability Metadata。我们在Java反射、动态代理这种纯业务的场景,用的相对较少,在运用到组件中相对多一点。举个例子,比如Native里用到反射,我们可以在仓库中直接找到Native反射的metadata。然后通过刚刚提到三个插件中的Native自身提供的插件,它会把仓库里的元数据直接打在二进制包里,我们也就不需要关心这些公共组件的元数据信息了。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_14.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>和Dubbo相关的元数据信息包括以下五类:&lt;/p>
&lt;p>第一,反射的元数据。&lt;/p>
&lt;ul>
&lt;li>内外部的service。我们知道Dubbo是rpc框架,所以定义服务接口是最通用的一种能力。内部提供的服务包括metric service、metadata service,用户服务就是业务定义的服务接口。&lt;/li>
&lt;li>SPI扩展。Dubbo的扩展能力得益于自己建的一套SPI机制。&lt;/li>
&lt;li>多实例。&lt;/li>
&lt;li>配置相关的内容。&lt;/li>
&lt;li>业务上自己用到的反射的行为。&lt;/li>
&lt;/ul>
&lt;p>第二,resource的元数据。如果业务上要做扩展,配置文件,resource的元数据主要涉及的就是META-INF下的三个路径。此外,还有一个是在Dubbo 3里支持对安全性的增强,序列化的黑白名单的resources的配置。&lt;/p>
&lt;p>第三,序列化的元数据。作为rpc调用的框架,它的接口定义、方法定义、内外部分的服务、parameter、请求参数、返回类型等都需要用到序列化的接口。&lt;/p>
&lt;p>第四,动态代理的元数据。在传统的rpc框架里动态代理是用的比较多的产品。内外部分服务的引用就是代理的元数据。&lt;/p>
&lt;p>第五,JNI的元数据,暂时没有用到。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_15.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>这是Dubbo 相关的 Reachability Metadata 总结和处理策略,我们把它分为了四类。&lt;/p>
&lt;ul>
&lt;li>规律性的内容,是刚刚提到的Adaptive Source Code的生成。&lt;/li>
&lt;li>确定性资源和行为,是Dubbo内部的扩展以及资源的配置。&lt;/li>
&lt;li>不确定性的资源和行为,是业务自定义的扩展实现以及定义的服务。&lt;/li>
&lt;li>集成和依赖的组件,比如刚刚提到jka是其他社区的生态,它涉及到注解的元数据信息,我们会提供官方的支持,还会提供内部的适配逻辑。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_16.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>这是AOT的执行流程。可以看到它的源码在编译之后,它的区别是它会从main函数开始启动Java应用进程,然后去找所有的source code和Bean的元数据信息。&lt;/p>
&lt;p>下面是Spring Server自动生成的一个source code,它会把它生成一个Bean定义的获取的类。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_17.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>而Dubbo并不是从main函数启动的,它启动了一个扫描的进程,把确定性的、不确定性的元素以及规律性的内容扫描进来,自动帮大家生成元数据信息。&lt;/p>
&lt;p>下面是用Dubbo service生成后的一些信息。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_18.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>上图是Spring本身提供的一个产物的内容以及Dubbo的AOT产物的内容。可以看到Dubbo下面是Adaptive的一些source code。最后Native在执行的时候会读取到这里所有的配置。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_19.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>这是Dubbo和AOT之间的边界,可以看到API的接入方式和注解、XML的接入方式是有所区别的。注解和XML借用了Spring AOT的能力,包括ServiceBean、ReferenceBean等等,而Dubbo AOT的能力主要是自身的元数据的生产。&lt;/p>
&lt;h2 id="五dubbo-在-native-image-技术的未来规划">五、Dubbo 在 Native Image 技术的未来规划&lt;/h2>
&lt;ol>
&lt;li>提升开发者体验&amp;amp;开发效率&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_20.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>Dubbo在3.0之后提供了CTL、脚手架、IDEA插件,Dubbo Native Image目前还在建设中,之后也会加进去。此外,还有一些文档的建设。&lt;/p>
&lt;ol start="2">
&lt;li>性能优化与提升&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_21.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>刚刚已经分享了很多内容,但还是有很多可以做的事情。在GraalVM提供的能力上,我们还可以把一些类相关的可达性的配置加上去,产生作用之后能让最后打出来的二进制包更小,编译时间更短。&lt;/p>
&lt;ol start="3">
&lt;li>覆盖更多的组件&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/native/img_22.png" alt="dubbo-graalvm-native-image">&lt;/p>
&lt;p>因为目前很多组件都还不支持,所以我们现在的主要思路是把Dubbo主仓库的扩展性支持完成,然后再往wpi的扩展上做相应的支持。&lt;/p>
&lt;p>另外,内核所需要的可达性的元数据,我们会把它推到program的可达性的元数据的仓库上面去,让业务开发能够正常使用大陆内核里的元数据信息。&lt;/p>
&lt;p>最后我们的思路还是优先考虑GraalVM官方的支持。&lt;/p></description></item><item><title>Blog: 手把手教你部署Dubbo应用到Kubernetes – Apache Dubbo Kubernetes 最佳实践</title><link>https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E6%89%8B%E6%8A%8A%E6%89%8B%E6%95%99%E4%BD%A0%E9%83%A8%E7%BD%B2dubbo%E5%BA%94%E7%94%A8%E5%88%B0kubernetes-apache-dubbo-kubernetes-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/</link><pubDate>Sat, 07 Oct 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E6%89%8B%E6%8A%8A%E6%89%8B%E6%95%99%E4%BD%A0%E9%83%A8%E7%BD%B2dubbo%E5%BA%94%E7%94%A8%E5%88%B0kubernetes-apache-dubbo-kubernetes-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;p>精进云原生 – Dubbo Kubernetes 最佳实践&lt;/p>
&lt;p>摘要:本文整理自阿里云研发工程师、Apache Dubbo PMC江河清的分享。本篇内容主要分为六个部分:&lt;/p>
&lt;ul>
&lt;li>一、使用 Dubbo Starter 初始化项目&lt;/li>
&lt;li>二、开发微服务之协议选型&lt;/li>
&lt;li>三、基于 Kubernetes 快速初始化环境&lt;/li>
&lt;li>四、快速部署应用到 Kubernetes 集群中&lt;/li>
&lt;li>五、云原生微服务可观测最佳实践&lt;/li>
&lt;li>六、在 Kubernetes 中管理微服务应用&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>上图是从 Istio 借鉴的一个demo,它包含了四个组件,分别是Product Page、Reviews、Details、Ratings,它就是一个全链路的串联,实现了整体的微服务架构,它的功能可以实现我们简单的调用。&lt;/p>
&lt;h2 id="一使用-dubbo-starter-初始化项目">一、使用 Dubbo Starter 初始化项目&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_1.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>首先介绍一下Starter的功能。对于很多开发来说,在Java体系下创建出新的应用,无外乎就是用IDE创建一个新的项目,或者用maven的artifact,或者基于Spring的Initializer。&lt;/p>
&lt;p>上图使我们基于Spring的Initializer建立了我们自己的初始化项目的工程。我们点击最上面的网址就能直接看到这个页面了,你需要输入对应的group和artifact。然后选择你希望用到的组件,比如Nacos、Prometheus的组件等等。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_2.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>除此之外,我们在IDE里提供了一个Dubbo的插件。这个插件可以通过上图的方式进行安装,或者如果你的仓库里已经用到了Dubbo的配置,它会提示你可以直接安装。安装完成后在右边就会有一个对应的初始化的项目了。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_3.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>上图是一个示例,它在这里建立了一个Dubbo的项目,然后你需要在这里选中所需要的组件信息,最后点击创建,之后它就会帮你在本地直接创建出一个全新的项目,然后你就可以在这个模版上开发了。&lt;/p>
&lt;h2 id="二开发微服务之协议选型">二、开发微服务之协议选型&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_4.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>我们会用到最新的Triple协议,它整体支持兼容gRPC、HTTP/1、HTTP/2。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_5.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>这里主要想和大家分享的点是,我们基于curl访问的能力,比如POSTMAN、HttpClient都是支持的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_6.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>下面来看一下我们的项目,这是刚才建立的一个项目,我现在把应用启动起来,配置一些注册中心的地址,这就是一个标准的Spring的启动的流程。这里定义了一个接口,这个接口返回了一个&amp;quot;hello&amp;quot;的内容信息。然后我用一个简单的命令,就可以直接返回我的hello world的结果了。这样对我们本身的测试来说有很大的帮助,也就是本地启动之后,就可以直接测试接口。&lt;/p>
&lt;h2 id="三基于-kubernetes-快速初始化环境">三、基于 Kubernetes 快速初始化环境&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_7.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>假设我们已经把前面四个应用的代码全部开发完成了,接下来我要把它部署到K8s环境上。部署之前有一个非常重要的步骤,需要先初始化环境。比如Nacos、ZK、Skywalking、Zipkin、Prometheus等组件,我们都需要将它们安装上去,因为它们是应用前置依赖的各种组件。这些组件的安装流程都很复杂,那么我们如何简化这个流程呢?&lt;/p>
&lt;p>Dubbo提供了一个命令,这个命令可以一键帮你在K8s体系下拉起上图左边的所有组件。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_8.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>这里有一个简单的例子,拉起来之后,它会把所有的组件都会帮你拉起来。这里埋一个点,这里的Prometheus我们后面还会继续使用。整个Nacos的地址,Zookeeper的地址都会直接提供给你。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_9.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>这也是一个的例子。执行一个简单的命令,然后本地会把kubectl的配置都准备好,它就会自动的帮你把组件都创建起来。也就是我们一键就可以获取到所有service的部署。&lt;/p>
&lt;h2 id="四快速部署应用到-kubernetes-集群中">四、快速部署应用到 Kubernetes 集群中&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_10.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>部署应用有三个重要的点,分别是应用容器化、无状态部署、生命周期对齐。&lt;/p>
&lt;p>首先介绍一下应用容器化。想要将应用容器化,首先需要建一个dockerfile,引入一个jdk的包,把启动命令和启动脚本拉进去。然后还要写一个Java的编译的脚本,把Java编译的jar包结果拉进去。这个过程非常复杂,所以我们可以用一下Jib的插件。这个插件是maven的一个plugin,我只需要把这些配进去,指定成我的Image就足够了。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_11.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>可以看到,我只需要把我的pom里添加一个对应的配置项依赖,通过一键maven的编译模式,它就可以在maven打包的过程中帮你构建完镜像,然后直接推送到远端仓库。这一切都只需要这一个命令就可以完成,而且一次性配置之后,未来你所有的镜像更新都可以自动化的去做,不需要再去写繁琐的dockerfile。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_12.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>其次介绍一下无状态部署。刚才我们把镜像打出来了,这只是第一步,紧接着我们要让镜像run起来。我们可以基于K8s的deployment的模式,它是从K8s的官网上直接拉下来的。拉下来之后我们可以指定对应的应用名、镜像信息等等,这是K8s无法绕过去的,相对于说它需要配置这样的一个demo,当然也会有云厂商平台提供一个可视化的界面给你,它的底层配置的就是这样的一个yarml。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_13.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>这是一个简单的例子,把deployment配置完之后,指定了刚才的镜像。同时我声明了一个service,这个service非常重要,它后面会作为from_end应用入口的配置,但它是一个Ingress网关。可以看到apply镜像之后,我们就可以在K8s体系上把这个环境run起来了。&lt;/p>
&lt;p>这里做一个简单的测试,我引入一个curl的容器,同样我们可以用刚才curl的命令访问我新部署好的容器节点,可以看到它返回了hello world的数据信息。&lt;/p>
&lt;p>综上,我们通过deployment的部署,可以在K8s上把容器run起来,同时它还可以对外提供服务,对外提供的服务我可以通过下面curl的命令进行调用。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_14.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>最后介绍一下生命周期对齐。整体部署上了之后,大家都会进行多Pod部署,所以就会涉及到分批的行为。如果现在分了两批,且我希望我的业务中间是不中断的,这个时候就需要让K8s帮我们进行分批处理。因为K8s只知道进程起来了,所以我们需要让K8s感知到这个应用当前的状态是否startup了。然后还需要让K8s知道是否ready,以及是否存活。这是K8s提供的流程,那么怎么和Dubbo的流程相匹配呢?&lt;/p>
&lt;p>上图右侧有一些Dubbo原生提供的ports信息,我们会对外发布这样的Dubbo的状态信息,可以让你和K8s的生命周期完整的对齐。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_15.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>上图是一个例子。在整个应用启动的时候,这里sleep了20秒,然后配置了对应的Pro信息。&lt;/p>
&lt;p>我们简单推测一下,我在前面设置了等待20秒,那么我的应用肯定要超过20秒才能起来。因为修改了代码,所以这里需要重新编译一下,用一键maven的编译模式直接推上去。接下来要把deployment apply进去,进去之后Pod的状态全都是not ready的,都是零的状态。&lt;/p>
&lt;p>因为前面sleep了20秒的时候,Dubbo还没启动完,所以都是not ready的状态。我们等sleep的阶段过了,它就会变成ready的状态,然后再进行分批这就是生命周期对齐的过程。&lt;/p>
&lt;p>所以K8s知道应用什么时候启动成功了,什么时候启动失败了,才能进行更好的调度。&lt;/p>
&lt;h2 id="五云原生微服务可观测最佳实践">五、云原生微服务可观测最佳实践&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_16.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>部署上去之后,我们还会涉及到整个应用的可观测。因为我们的应用可能部署了非常多节点,我需要感知应用的状态。&lt;/p>
&lt;p>可观测体系包括Metrics体系和Tracing体系。Metrics体系包括几个指标,比如谷歌的四个环境指标,延迟、流量等等。对应到Dubbo,会提供QPS、RT等等指标,它都是在这样体系下的Metrics的最佳实践。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_17.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>前面在部署初始化环境的时候,提了Prometheus的服务,现在就有用了。当我把Prometheus环境部署完之后,我们只需配置几行简单的Metrics采集信息。然后Prometheus就会帮你在你的节点上面采集很多的Metrics信息,然后得到右边的panel信息,这个panel也是Dubbo官方提供的,可以直接看到Dubbo的状态信息。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_18.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>上面是一个演示的例子。我们在前面的deployment的例子上加上Metrics的采集信息,然后把它apply进去之后,我们就可以用整个Grafana导出过来。跑了一段时间之后,就会有对应的流量信息,比如QPS信息、RT信息、成功率等等。&lt;/p>
&lt;p>得到这些指标后,我们还可以做一个告警。比如QPS从100突然跌到了0,或者成功率突然跌了很多,这种情况我们需要做一个警示,让大家知道当前发生的问题。我们可以基于Prometheus采集,做一个主动的推送,这就是告警的过程。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_19.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>Tracing包括内置的Tracing、agent注入的方案。目前主流的Go语言和其他语言大多都会用sdk依赖一个open去做一个Tracing。因为Go构体系下的agent注入也不太完善,Dubbo本身也提供了默认Tracing的能力支持。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_20.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>大家可以看到,在这里你只需要依赖dependency里面加上Dubbo的starter,配置项里把Tracing能力打开,开启一个指标的上报,9411是我们Zipkin的一个后端。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_21.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>这也是一个例子,我只需要配置这些配置,它的数据就会报到Zipkin上去,这里的dependency直接加上。&lt;/p>
&lt;p>同样的,用刚才的命令进行打包,把镜像推送上去,然后我们等待一下。推送的过程中可以看一下Zipkin这个组件,它也是在最前面我们在K8s初始化环境的时候一起拉起的,所以这一切你只需要在前面一次性部署的时候就可以拥有了。&lt;/p>
&lt;p>然后我们简单的执行一个curl命令,因为我需要让我的环境有流量。部署完之后,用curl命令还是执行一下我们的获取,这个其实已经把后端开发完了,它返回了真实的结果。&lt;/p>
&lt;p>接下来我们去Zipkin上看看能不能找到这条Tracing。首先把9411映射过来,我们可以看到curry一下,这里就会有对应的指标信息。整个全链路的调用信息这里都可以看到,这就是全链路的接入的流程。相当于你只需要把前面的dependency加上,把上报的配置加上,之后的一切我都会帮你在后面完成以及上报。你看到对应的结果,就可以知道全链路上发生了什么事情。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_22.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>除此之外,还可以基于agent的方式。如果我们基于K8s部署,我们接入一个agent也是非常方便的。你可以基于一个initContainer把整个Java的配置项信息直接注入进去,这样在skywalking上就可以看到一个对应的全链路的信息。因为和前面是类似的,这里就不再赘述它的demo的工程了。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_23.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>对于整个可观测来说,我们可以通过Metrics看到QPS、RT等信息,通过Tracing看到全链路的访问信息。这里提供给我们一个很好的方案,就是我们要先去做服务的观测,基于服务的观测更好的排查整体的问题,第一时间知道应用挂没挂。比如半夜两点,它的可用率跌到零了。这个时候可以通过一系列的自动化机制告诉你应用出了问题,快速的进行恢复。这里的快速恢复可以使用回滚,将流量隔离的方案他都可以快速的执行。&lt;/p>
&lt;p>基于这样快速的从观测到排查,再到快速恢复的链条,可以构建整个生产环境下的安全稳定的体系。所以我们观测完之后的目标就是保证整个应用的稳定。&lt;/p>
&lt;h2 id="六在-kubernetes-中管理微服务应用">六、在 Kubernetes 中管理微服务应用&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_24.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>K8s给我们带来的收益包括快速扩缩容,即我可以很快的基于K8s从一个Pod变成多个Pod。因为K8s是基于整个Image的部署的流程,当镜像打包出来后,你的环境就是固定的,只需要去横向的扩容即可。&lt;/p>
&lt;p>横向的快速扩容也会涉及到几个瓶颈的点,如果我需要让我的应用能够快速扩容,比如我的应用提起来就要几十分钟,这种情况即使快速扩容了,等扩容完之后你的业务峰值也过去了,这里就会引入到Native Image。&lt;/p>
&lt;p>基于Native Image,我们可以很好的实现整个Serverless的横向的扩容。如果可以实现毫秒级的启动,我可以在流量来的波峰,直接让我的Pod横向扩容好几倍,当它的流量下去的时候就直接下掉,这样就实现了成本的压缩。&lt;/p>
&lt;p>另外还有一个问题是怎么知道什么时候要扩容?这就需要基于Metrics的观测,基于一些历史数据的分析,知道在某个时间点会有多少的流量,然后提前扩容,或者做一个自动化的扩容。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_25.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>这里我举一个简单的例子,比如我的rating上出了一些问题,我需要把它的故障摘除掉,返回一个磨合的结果。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_26.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>这个时候你只需要在上面去配置一个上图的规则,它就会返回。这就是Admin的使用流程,这里就不再展开了,还有刚刚提到的我们在做Go版本的重构能力,后面也都会有更好的建设。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_27.png" alt="dubbo-kubernetes-最佳实践">&lt;/p>
&lt;p>除此之外,基于 istio的Service Mesh治理,我们前面协议选型的时候选了Triple协议,它完全是based on HTTP标准的。因此我们使用istio的整个体系之后,你只需要挂上subcard它就会帮你去做流量治理。这一切的前提是你的协议一定是istio可见的。&lt;/p>
&lt;p>比如你原来用是Dubbo 2的Dubbo的协议,它是一个私有的tcp协议,对于istio来说它很难分辨你的协议内容。如果你用了Triple协议,我们可以基于HTTP标准,你就可以知道你的header里有什么东西,可以去做一个流量的转发。所以它完全拥抱Mesh的体系,可以支持我们所有istio的治理能力。&lt;/p></description></item><item><title>Blog: 政采云基于Dubbo的混合云数据跨网实践</title><link>https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E6%94%BF%E9%87%87%E4%BA%91%E5%9F%BA%E4%BA%8Edubbo%E7%9A%84%E6%B7%B7%E5%90%88%E4%BA%91%E6%95%B0%E6%8D%AE%E8%B7%A8%E7%BD%91%E5%AE%9E%E8%B7%B5/</link><pubDate>Sat, 07 Oct 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E6%94%BF%E9%87%87%E4%BA%91%E5%9F%BA%E4%BA%8Edubbo%E7%9A%84%E6%B7%B7%E5%90%88%E4%BA%91%E6%95%B0%E6%8D%AE%E8%B7%A8%E7%BD%91%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;p>摘要:本文整理自政采云资深开发工程师王晓彬的分享。本篇内容主要分为四个部分:&lt;/p>
&lt;ul>
&lt;li>一、项目背景&lt;/li>
&lt;li>二、为什么叫高速公路&lt;/li>
&lt;li>三、修路实践&lt;/li>
&lt;li>四、未来规划&lt;/li>
&lt;/ul>
&lt;h2 id="一项目背景">一、项目背景&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>我们有一个云岛业务叫政采云,它是政府的购物网站,类似于淘宝。政府采购会在政采云上做企业采购、政府采购的业务。&lt;/p>
&lt;p>云岛中的&amp;quot;云&amp;quot;是指我们的云平台,云平台是我们公司自己部署的一套购物网站,它对应的是一套微服务框架。而&amp;quot;岛&amp;quot;是指,比如安徽或者山西它们都有自己的局域网,如果我们在它们那里也部署一套这个框架,就叫&amp;quot;岛&amp;quot;。我们的云主要是给浙江省和相关的区划用的。&lt;/p>
&lt;p>我们的云和岛之间存在数据传输的问题,举个例子,比如我现在收到一个政府的公告,而这个公告肯定是全国性的。所以我可能会在云平台的管理平台上去录公告,再把它推送出去,这个时候云和岛之间就存在了一些数据的跨网。&lt;/p>
&lt;ol>
&lt;li>云岛网络&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_1.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>对我们云平台来说,这个局域网是我们公司内部完全可控的。比如你要开个端口,很快就能开起来。导端它可能是局域网或者是私有网络,比如我们之前做了一个浙商银行的项目,它是完全隔离的一个岛。他们的安全策略和开端口的东西都是他们自己定义的,这就是我们云岛的业务结构。&lt;/p>
&lt;ol start="2">
&lt;li>混合云岛网络&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_2.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>上图是大概的数据链路图。云平台下面有分支机构、分公司,它们会对应一套业务的系统。政务云是我刚才说的省级(安徽省)或者市级(无锡市)对应的区块,隔离的政务云。私有部署是银行、国企、军队、政企等典型的混合云的网络架构。&lt;/p>
&lt;ol start="3">
&lt;li>混合云岛网络的特点&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_3.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>我们混合云网络架构的特点包括:&lt;/p>
&lt;ul>
&lt;li>平台的一致性。我们部署在公有云、云平台、政务云、私有云上的那一套的代码是一样的。我们把一套代码部署在不同的地方就变成了多个平台。&lt;/li>
&lt;li>网络连接与能力复用。我们会依赖一些第三方的能力,比如短信,但私有云上它的网络管控比较严,所以和第三方互通端口或者网络的流程就会比较复杂。这个时候我们希望去复用我们云平台的能力,这个时候他们之间又有一些数据的交互。&lt;/li>
&lt;li>跨域访问迁移。&lt;/li>
&lt;li>统一的平台管理。像我刚才举的例子,如果要发公告,我们希望可以在一个平台上就可以管理起来。而不是浙江发一条,安徽发一条,那样维护的成本也会比较高。&lt;/li>
&lt;/ul>
&lt;ol start="4">
&lt;li>政企网络痛点&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_4.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>很多公司都会和政府打交道,政企网络有以下几个特点:&lt;/p>
&lt;p>网络复杂。比如银行的网络,它们的安全性和内部的东西很复杂,流程的开通也比较多,需要你要经常去跑,跑完了之后发现有新的问题,又要去跑。&lt;/p>
&lt;p>安全要求高。比如在开通端口的时候,我们需要去传数据,如果里面的那些序列化的协议不符合它们的规范,它们就会拿掉。这个时候给我们的业务其实是超时的,或者是那种通用的异常。而我们并不知道发生了什么,这就会带来未知的风险。&lt;/p>
&lt;p>业务驱动运维。我们有了业务才会去部署,才会去做事情。我们就会多次、重复的投入,这就会导致人力、时间成本会比较高,私有部署的时候会更多。&lt;/p>
&lt;ol start="5">
&lt;li>现有方案&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_5.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>基于以上的痛点,我们做了两个方案。&lt;/p>
&lt;p>第一个方案,基于Dubbo Filter的单向方案。这个方案的历史比较久一些,它有两个特点。&lt;/p>
&lt;p>第一个特点,单向传输。它是从&amp;quot;岛&amp;quot;到&amp;quot;云&amp;quot;只有一个方向,它基于Dubbo Filter的原因是,我们公司内部的微服务都是通过Dubbo来调用的,所以我们是强依赖的来Dubbo的。所以做数据跨网的方案肯定会基于Dubbo的特性来做。&lt;/p>
&lt;p>第二个特点,在本地部署业务的provider过滤器是运维上的负担。当导端需要把数据同步给云端的时候,也就是从岛端的业务Web传输到云端的业务provider。这个时候我必须在导端也部署一套业务的provider才可以。部署它的原因是它要拦截这个请求,然后把这个请求转发给部署在云平台的Dubbo网关。&lt;/p>
&lt;p>但这个时候就会给我们带来负担。如果导端本来就有数据的入库就还好,因为provider本来就存在,但一些业务只是做跨网用的,没有本地的入库,那么这个时候业务的provider就是多余的了。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_6.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>第二个方案,网状点对点方案。因为岛和岛之间需要网络互通,所以就会单独开通这个点和你需要传输的点之间的端口。开通之后我们就可以调用了,调用的形式可以用Dubbo。&lt;/p>
&lt;p>这个方案有一个很明显的缺陷,线特别多,所以点和点之间开通的复杂度也很高,对后面的扩展可能也非常不利。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_7.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>以上方案存在的问题包括单向传输、白名单开通成本高、平台维护成本高、公共功能的缺失。&lt;/p>
&lt;p>基于以上的问题,我们做了一个新的方案,叫高速公路。&lt;/p>
&lt;h2 id="二为什么叫高速公路">二、为什么叫高速公路&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_8.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>为什么叫告诉公路呢?主要因为我们想要达到的效果是:&lt;/p>
&lt;p>只建一次,可复用。比如北京到上海的高速公路,它只要够宽,一条就够了。如果你是从上海到北京或者从杭州到北京,是可以复用的,不用单独再修建一条。&lt;/p>
&lt;p>隧道机制。因为高速公路修建的地方不一定都在平原,可能会在河、海、山等等附近。如果我们在高速公路下面搭建一条隧道,这个时候对于司机来说就是无感的。我们的目的是一样的,如果你觉得政企网络很复杂,那么我们就帮你把它屏蔽掉,这样你也是无感的了。&lt;/p>
&lt;p>考虑传输性能。如果每个业务部门都自己搭建一套传输链路,那么传输性能只要能承载自己的业务就够了,因为不一定要给别人用,或者给别人用了也是小范围的。但如果搭建的是一条可复用的链路,就必须考虑传输的性能了。&lt;/p>
&lt;h2 id="三修路实践">三、修路实践&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_9.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>接下来介绍一下我们在修建高速公路的时候遇到的一些问题以及具体的做法。我们在客户端接入上遇到了以下问题:&lt;/p>
&lt;p>第一个问题,强依赖Dubbo。&lt;/p>
&lt;p>第二个问题,透明传输,不改变使用Dubbo的方式。也就是我不需要自己写一些注解代替Dubbo,或者写一些API调用Dubbo。因为写了之后,一些新人可能并不能理解或者不能习惯,也不知道里面有什么坑。所以我们用原始的Dubbo来做可能会对用户更加无感。&lt;/p>
&lt;p>第三个问题,接入灵活,支持多种形态。虽然我们强依赖Dubbo必须支持Dubbo,但我们也需要支持其他的形式,比如HTTP。但在接入之前,我们需要考虑接入灵活性的问题。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_10.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>下面我们先介绍一下Dubbo的方式。Dubbo的客观接入主要有以下三种方式:&lt;/p>
&lt;p>第一种,注解方式。使用@DubboReference提供的通用parameters参数,设置路由目标,可以达到方法粒度的路由。路由信息写在中间parameters那里,parameters是Dubbo给我们提供的通用参数的传递。&lt;/p>
&lt;p>如果是正常的,我写了这个信息,Dubbo是不做任何处理的,因为这个东西对它来说没有含义。但因为你引入了高速公路的SDK,所以在你写了这个东西之后,我们就会去解析,拦截Dubbo的请求,把parameters里的参数抓起来做一些路由处理,这种形式其实没有改变Dubbo的使用方式。&lt;/p>
&lt;p>第二种,配置中心指定。比如我们用的是阿波罗的配置中心,它完全可以把接入方式替换掉,parameters的信息在配置中心配置也可以,只要SDK可以支持就好。这种方式其实代码是完全侵入的,就是跟跨网之前和跨网之后没有任何区别。但最后发现我们的业务并不喜欢这种方式,首先因为阿波罗大家不喜欢用,其次不好理解。如果是一个新人看这个代码,他就会认为是在调本地的接口。&lt;/p>
&lt;p>第三种,线程指定。当你在线程里指定了路由信息,下面再去调用的时候,这次调用就会走你的路由。如果再调用一次,它就会调回本地。因为基于线程的形式,在Dubbo的扩展里,它会在调用完成之后把线程信息清理掉。所以需要注意一下,如果你想多次调用,就需要写多次。如果不想写多次,你可以用上面这种方式,你只要在当前的been里,都是路由到上海。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_11.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>接下来介绍一下高速公路的架构,刚才介绍点对点的方式,它的缺点是开通白名单比较复杂。现在我们的高速公路架构是一个新型的架构,所以它开通白名单的复杂度会低一点。&lt;/p>
&lt;p>如上图所示,比如最左边的节点是上海,最上边的节点是安徽,我想从安徽到上海,这个时候中心网关就需要开通一个白名单。开完之后,这条链路就可以直接过去了。可以看到一共就六条线,所以它的复杂度也就下来了。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_12.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>18:30上图是高速公路里最核心的架构图。&lt;/p>
&lt;p>比如山西集群的APP1调APP2的时候,我想去调上海APP2,如果你什么都不做,它默认调的就是山西集群的APP2。如果你在APP调用的时候加了一些路由信息,放在山西集群APP1里的SDK就会把它的流量切走,切到山西集群的Dubbo网关。&lt;/p>
&lt;p>之后Dubbo网关会通过HTTP的协议走统一网关,再通过HTTP的协议到上海集群的Dubbo网关。在这里会把路由信息拿到,包括调用的Service、方法、版本号、参数等等。然后通过泛化的形式调上海集群的APP1,最后返回,完成这次跨网的调用。&lt;/p>
&lt;p>那么为什么要有Dubbo Proxy这个角色呢?为什么不直接从APP1切到统一网关?少一个步骤不好么?涉及到的原因有以下三点:&lt;/p>
&lt;p>虽然这个图上只画了一个APP1,但实际上山西鸡群里的调用非常多。如果几百个应用都直接到统一网关,网关就需要建立很多的长链接,而统一网关的资源是有限的。&lt;/p>
&lt;p>因为安全性的问题,可能每次调用都要走一下白名单来保证安全。这个时候如果加了一个Dubbo Proxy,就可以去收敛IP。岛内不用和Dubbo Proxy交互,因为它们是同一个环境,不用考虑安全的问题。当Dubbo Proxy请求到网关之后,因为网关和统一网关之间只有一条链接,所以IP是收敛的。&lt;/p>
&lt;p>还有一个是功能的收敛,当后面要做升级的时候,如果更新SDK,就需要每个应用都升级,这就需要推动业务做升级,做起来会比较痛苦。所以我们希望把升级功能全放在一个应用里,对业务功能无感,连升级SDK都不需要。当然因为SDK就做了一件事情,就是切换路由,基本不需要更新。&lt;/p>
&lt;p>所以对于业务来说,它也解放了。我把它理解成是一个功能上的收益。这个模式叫分布式运行时,在现在也比较流行。我们可以把它理解成Dapper,把一些比较麻烦的操作放到公共的服务里,留给业务的SDK是很纯粹的。&lt;/p>
&lt;p>另外,为什么要用HTTP协议呢?它也并不是很高效的协议。而Dubbo协议中的Dubbo2其实也是比较惊艳的,除了一些模糊全部都是数据。这样的话其实我们后面是可以考虑把HTTP升级掉,让它的性能更快一点。&lt;/p>
&lt;p>现在用HTTP协议的原因是,它是一个标准的协议,中间可能会通过很多设备,虽然我们这里只画了一个。HTTP协议是没有任何障碍的,如果用Dubbo协议,还需要一个个打通。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_13.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>为了实现这个架构,Dubbo本身并不能直接用。因为Dubbo没有提供跨网的特性,所以我们需要从Dubbo层面解决我们碰到的问题。&lt;/p>
&lt;p>在动态IP切换方面,其实Dubbo是支持的,但因为这个特性比较新,所以也会出现一些问题。它的支持程度是部分支持,比如在最开始的时候Dubbo2不支持,Dubbo3支持。此外,还会有一些bug。&lt;/p>
&lt;p>在404扩展方面,对于HTTP来说,你要调一个接口,但这个接口不存在,就会返回给前端一个404的报错。比如当我们把流量从APP1切到Dubbo Proxy的时候,Dubbo Proxy其实是Dubbo的一个应用,它引入了一个Dubbo的jar包,它是Dubbo的一个空应用。这个流量到Dubbo的网关后,它不能识别,它的功能是要把它转发出去。这个时候我们就需要加入这个扩展。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_14.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>下面介绍一下隧道的机制。隧道机制的作用是屏蔽网络的复杂性,屏蔽中间的协议转换,给用户一个统一、透明的调用方式。&lt;/p>
&lt;p>中间的HTTP协议里面的body带了一个原始的bodv。倒装之后再把它拆包拆出来,再通过泛化去调。这个时候隧道是可以匹配掉这些差异的。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_15.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>另外,隧道机制对Dubbo协议的支持力度更高。比如APP1和本地的APP 3,最终调到APP2的时候,它看到了二进制流是一样的。因为我并没有去做什么,我只是把它分装起来,最后拆包。中间除了一点路由信息之外其他都一模一样。&lt;/p>
&lt;p>这个机制的好处是,基本上Dubbo的所有特性都能支持。但也有一些个例,比如token和网络相关的机制。&lt;/p>
&lt;h2 id="四未来规划">四、未来规划&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_16.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>借用网络分层的架构对高速公路做了一些规划:&lt;/p>
&lt;p>第一层,物理网络层打通。它其实跟我们关系不大,因为我理解的是开通端口,你开通了那么多事,可以总结一些经验或者方法论去加快这个事情。&lt;/p>
&lt;p>第二层,通讯协议层加速。中间的HTTP协议转发,我们是可以加速的。比如Tripple协议也是基于HTTP2对网络设备进行了识别,然后把问题解决了。所以我们也可以考虑去调研,在通讯协议层去做优化。&lt;/p>
&lt;p>第三层,语言层编译加速。GraalVM之前我们也调研过,而且也真正的去试过。虽然没有落地,但编译加速是可以的。特别是网关层,它的特点是流量大,但是每个流量又特别小,对语言本身的性能要求比较高。如果把它用Go来实现,其实也是一个比较好的加速。&lt;/p>
&lt;p>第四层,框架层功能升级。中间件层我们也做了很多事情。&lt;/p>
&lt;p>第五层,通用任务调度与编排。调用其实会经过很多节点,比如a到b到c到d到e,随着业务越来越复杂,我们可能会有更多的路由。比如a到c,c和d汇合起来再到d,未来也将会规划进去。&lt;/p>
&lt;p>第六层: 定制任务调度与编排。&lt;/p>
&lt;p>第七层: 监控 &amp;amp; 告警 &amp;amp; 可观测性。&lt;/p>
&lt;p>第八层: 规范 &amp;amp; 流程&amp;amp; 安全。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_17.png" alt="dubbo企业实践-政采云">&lt;/p>
&lt;p>最后做一个总结。&lt;/p>
&lt;p>为什么要做这个项目?之前的方案比较多,成本也比较高。所以我们需要有一个统一的方案考虑更多公共的测试把这个东西给推广起来。目前我们已经接入了非常多的应用,它已经成为了政法人员数据跨网的统一的标准方案。&lt;/p>
&lt;p>我们要达到的效果,项目架构,未来规划刚才都介绍过了,就不再重复了。&lt;/p>
&lt;p>重点说一下我们的开源与社区的合作。刚才的方案其实是我们公司内部使用的,也对Dubbo做了深度的定制。一般我们会选择私有版本进行开发,但因为想要开源,所以在最开始的时候,我们就和Dubbo社区沟通,看能不能在开源层实施掉。一方面社区可以帮我们review这些特性,做一些安全上的把控。另一方面我们也能把自己做的一些事情,特别是把公共的东西抽出来反馈给社区。&lt;/p></description></item><item><title>Blog: CoC Asia 2023 大会精彩回顾</title><link>https://dubbo.apache.org/zh-cn/blog/2023/08/25/coc-asia-2023-%E5%A4%A7%E4%BC%9A%E7%B2%BE%E5%BD%A9%E5%9B%9E%E9%A1%BE/</link><pubDate>Fri, 25 Aug 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/08/25/coc-asia-2023-%E5%A4%A7%E4%BC%9A%E7%B2%BE%E5%BD%A9%E5%9B%9E%E9%A1%BE/</guid><description>
&lt;p>以下包含本期演讲的完成文字稿内容与现场精彩瞬间,更多 ppt、视频录像可关注 &amp;ldquo;apachedubbo&amp;rdquo; 微信公众号获取。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E5%9F%BA%E4%BA%8E-triple-%E5%AE%9E%E7%8E%B0-web-%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%90%8E%E7%AB%AF%E5%85%A8%E9%9D%A2%E6%89%93%E9%80%9A/">基于 Triple 协议实现 Web、移动端、后端微服务全面打通&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E6%89%8B%E6%8A%8A%E6%89%8B%E6%95%99%E4%BD%A0%E9%83%A8%E7%BD%B2dubbo%E5%BA%94%E7%94%A8%E5%88%B0kubernetes-apache-dubbo-kubernetes-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/">手把手教你部署 Dubbo 应用到 Kubernetes - Apache Dubbo &amp;amp; Kubernetes最佳实践&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dubbo.apache.org/zh-cn/blog/2023/10/07/apache-dubbo-%E4%BA%91%E5%8E%9F%E7%94%9F%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E7%9A%84%E6%8E%A2%E7%B4%A2%E4%B8%8E%E5%AE%9E%E8%B7%B5/">Apache Dubbo 云原生可观测性的探索与实践&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dubbo.apache.org/zh-cn/blog/2023/10/07/opensergo-dubbo-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/">Opensergo &amp;amp; Dubbo 微服务治理最佳实践&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dubbo.apache.org/zh-cn/blog/2023/10/07/seata-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E4%B8%8B%E7%9A%84%E4%B8%80%E7%AB%99%E5%BC%8F%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/">Seata 微服务架构下的一站式分布式事务解决方案&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E5%90%AF%E5%8A%A8%E9%80%9F%E5%BA%A6%E6%8F%90%E5%8D%8710%E5%80%8Dapache-dubbo-%E9%9D%99%E6%80%81%E5%8C%96-graalvm-native-image-%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/">启动速度提升 10 倍:Apache Dubbo-静态化 GraalVM Native Image 深度解析&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dubbo.apache.org/zh-cn/blog/2023/10/07/%E6%94%BF%E9%87%87%E4%BA%91%E5%9F%BA%E4%BA%8Edubbo%E7%9A%84%E6%B7%B7%E5%90%88%E4%BA%91%E6%95%B0%E6%8D%AE%E8%B7%A8%E7%BD%91%E5%AE%9E%E8%B7%B5/">政采云基于 Dubbo 的混合云数据跨网实践&lt;/a>&lt;/li>
&lt;li>工商银行分布式建设及转型实践&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/dubbo-members-justin.jpg" alt="dubbo-members-justin">&lt;/p>
&lt;p>Apache Dubbo 社区骨干成员及 Apache Board Member, Justin Mclean 合影&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/dubbo-members-apache-members.jpg" alt="dubbo-members-apache-members">&lt;/p>
&lt;p>Apache Dubbo 社区骨干与 Apache Member 交流合影&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/huazhongming.jpg" alt="huazhongming">&lt;/p>
&lt;p>华钟明,Apache Dubbo PMC Member,杭州有赞科技有限公司中间件技术专家,《Apache Dubbo 静态化 GraalVM Native Image 解决方案与实践》&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/songxiaosheng.jpg" alt="songxiaosheng">&lt;/p>
&lt;p>宋小生,Apache Dubbo Committer,平安壹钱包中间件资深工程师,《Apache Dubbo 云原生可观测性探索与实践》&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/chenyouwei.jpg" alt="chenyouwei">&lt;/p>
&lt;p>陈有为,Apache Dubbo PMC Member,陌陌研发工程师,《基于 Triple 协议实现WEB、移动端、后端服务全面打通》&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/jiangheqing.jpg" alt="jiangheqing">&lt;/p>
&lt;p>江河清,Apache Dubbo PMC Member,阿里云研发工程师,《精进云原生 - Dubbo Kubernetes 最佳实践》&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/wangxiaobin.jpg" alt="wangxiaobin">&lt;/p>
&lt;p>王晓彬,Apache Dubbo Committer,政采云资深开发工程师,《政采云基于 Dubbo 的混合云跨网方案实践》&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/hejiahuan.jpg" alt="hejiahuan">&lt;/p>
&lt;p>何家欢,Sentinel Maintainer,阿里云研发工程师,《OPENSERGO &amp;amp; DUBBO 微服务治理最佳实践》&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/dingxingzhong.jpg" alt="dingxingzhong">&lt;/p>
&lt;p>丁兴中,中国工商银行软件研发中心云计算实验室架构师,《工商银行分布式建设及转型实践》&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon-summary/jimin.jpg" alt="jimin">&lt;/p>
&lt;p>季敏,Seata 开源项目创始人,阿里云分布式事务产品负责人,《SEATA:微服务架构下的一站式分布式事务解决方案》&lt;/p></description></item><item><title>Blog: Dubbo 微服务专题论坛 - 8月19日北京ApacheCon大会不见不散</title><link>https://dubbo.apache.org/zh-cn/blog/2023/08/07/dubbo-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%B8%93%E9%A2%98%E8%AE%BA%E5%9D%9B-8%E6%9C%8819%E6%97%A5%E5%8C%97%E4%BA%ACapachecon%E5%A4%A7%E4%BC%9A%E4%B8%8D%E8%A7%81%E4%B8%8D%E6%95%A3/</link><pubDate>Mon, 07 Aug 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/08/07/dubbo-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%B8%93%E9%A2%98%E8%AE%BA%E5%9D%9B-8%E6%9C%8819%E6%97%A5%E5%8C%97%E4%BA%ACapachecon%E5%A4%A7%E4%BC%9A%E4%B8%8D%E8%A7%81%E4%B8%8D%E6%95%A3/</guid><description>
&lt;p>Dubbo 微服务专题论坛将于8月19日下午在北京丽亭华苑酒店举行,作为本次 CommunityOverCode Asia 2023(原 ApacheCon Asia)大会上的重磅议题,我们将以 Apache Dubbo 为中心展开,给大家带来开源微服务技术方向发展、云原生微服务选型、企业实践分享等精彩内容!&lt;/p>
&lt;p>打开 &lt;a href="https://www.bagevent.com/event/cocasia-2023">官网购票链接&lt;/a>,输入 cocasia 优惠码可八折购票!&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/8/apachecon/apachecon-rpc-schedule.png" alt="apachecon-rpc-schedule">&lt;/p>
&lt;p>作为 Apache 软件基金会(ASF)的官方全球系列大会,每年的 CommunityOverCode Asia 都吸引着来自全球各个层次的参与者、社区共同探索 &amp;ldquo;明天的技术&amp;rdquo;。8 月 18 日至 20 日,即将强势来袭的 CommunityOverCode Asia 2023 上,大家可以近距离感受来自 Apache 项目的最新发展和新兴创新。&lt;/p></description></item><item><title>Blog: GLCC x Apache Dubbo编程夏令营报名启动</title><link>https://dubbo.apache.org/zh-cn/blog/2023/07/05/glcc-x-apache-dubbo%E7%BC%96%E7%A8%8B%E5%A4%8F%E4%BB%A4%E8%90%A5%E6%8A%A5%E5%90%8D%E5%90%AF%E5%8A%A8/</link><pubDate>Wed, 05 Jul 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/07/05/glcc-x-apache-dubbo%E7%BC%96%E7%A8%8B%E5%A4%8F%E4%BB%A4%E8%90%A5%E6%8A%A5%E5%90%8D%E5%90%AF%E5%8A%A8/</guid><description>
&lt;h2 id="背景介绍">背景介绍&lt;/h2>
&lt;p>GitLink编程夏令营(GLCC),是在CCF中国计算机学会指导下,由CCF开源发展委员会(CCF ODC)举办的面向全国高校学生的暑期编程活动。活动将覆盖近千所高校,并联合各大开源基金会、开源企业、开源社区、开源专家,旨在鼓励青年学生通过参加真实的开源软件开发,提升自身技术能力,为开源社区输送优秀人才。为青年学生提供开放友好的交流平台,希望进一步推动国内开源社区的繁荣发展。&lt;/p>
&lt;h2 id="报名方式">报名方式&lt;/h2>
&lt;p>此次报名仅限 GLCC “无奖金项目”。具体请在此查看 &lt;strong>&lt;a href="https://www.gitlink.org.cn/glcc/freeproject" target="_blank">项目详情与报名方式&lt;/a>&lt;/strong>。&lt;/p>
&lt;p>&lt;strong>Apache Dubbo 项目报名截止日期:2023-07-30&lt;/strong>&lt;/p>
&lt;p>如有更多问题,请扫描官方公众号咨询:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/contacts/wechat-account.jpg" alt="wechat-account">&lt;/p></description></item><item><title>Blog: Apache Dubbo 开源之夏 2023,贡献社区赢取 12000 奖金</title><link>https://dubbo.apache.org/zh-cn/blog/2023/05/15/apache-dubbo-%E5%BC%80%E6%BA%90%E4%B9%8B%E5%A4%8F-2023%E8%B4%A1%E7%8C%AE%E7%A4%BE%E5%8C%BA%E8%B5%A2%E5%8F%96-12000-%E5%A5%96%E9%87%91/</link><pubDate>Mon, 15 May 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/05/15/apache-dubbo-%E5%BC%80%E6%BA%90%E4%B9%8B%E5%A4%8F-2023%E8%B4%A1%E7%8C%AE%E7%A4%BE%E5%8C%BA%E8%B5%A2%E5%8F%96-12000-%E5%A5%96%E9%87%91/</guid><description>
&lt;p>欢迎在校同学们参与Apache Dubbo开源之夏,社区导师手把手让&lt;strong>你的代码被社会广泛复用,来赚取最高12000奖金,可&lt;/strong>推荐入职/实习你心意公司,&lt;strong>又拿钱又成长又有价值&lt;/strong>,你还等什么呢?报名马上截止,快来参与Apache Dubbo开源之夏。&lt;/p>
&lt;h2 id="ospp-开源之夏是什么">OSPP 开源之夏是什么?&lt;/h2>
&lt;p>开源之夏是由“开源软件供应链点亮计划”发起并长期支持的一项暑期开源活动,旨在鼓励&lt;strong>在校学生&lt;/strong>积极参与开源软件的开发维护,促进优秀开源软件社区的蓬勃发展,培养和发掘更多优秀的开发者。
活动联合国内外各大开源社区,针对重要开源软件的开发与维护提供项目任务,并面向全球高校学生开放报名。
学生可在本活动中自主选择感兴趣的项目任务进行申请,并在中选后获得该开源项目资深维护者(社区导师)亲自指导的机会,完成项目并贡献给社区后,参与学生还将获得开源之夏&lt;strong>活动奖金&lt;/strong>和&lt;strong>结项证书&lt;/strong>。&lt;/p>
&lt;h1 id="apache-dubbo-项目简介">Apache Dubbo 项目简介&lt;/h1>
&lt;p>Apache Dubbo 是国内最具影响力的开源软件项目之一,由阿里巴巴贡献开源,是支撑阿里双十一百万集群、万亿次服务调用的核心框架,目前 Dubbo 已捐献给享誉世界的 Apache 软件基金会 (ASF)。&lt;/p>
&lt;h2 id="参与apache-dubbo开源之夏条件">参与Apache Dubbo开源之夏条件&lt;/h2>
&lt;ul>
&lt;li>本活动面向年满 18 周岁在校学生。&lt;/li>
&lt;li>暑期即将毕业的学生,只要在申请时学生证处在有效期内,就可以提交申请。&lt;/li>
&lt;li>海外学生可提供录取通知书、学生卡、在读证明等文件用于证明学生身份。&lt;/li>
&lt;/ul>
&lt;h2 id="参与apache-dubbo开源之夏你能获得什么">参与Apache Dubbo开源之夏,你能获得什么?&lt;/h2>
&lt;ol>
&lt;li>**【你的代码被社会广泛复用】**你的代码可能会运行在上万家企业核心业务逻辑中,帮助企业解决问题。&lt;/li>
&lt;li>**【赢得最高12000奖金】**奖金总额根据项目难度分为进阶 12000 元、基础 8000 元(注:奖金数额为税前人民币金额)&lt;/li>
&lt;li>**【社区核心人员辅导快速成长】**只要你报名被选中,每个题目的导师会精心手把手教你融入社区,帮助你完成题目的设计以及最终的落地。&lt;/li>
&lt;li>**【推荐入职/实习】**在本次编程之夏项目中表现优秀同学,可推荐入职/实习 你心意的公司工作。&lt;/li>
&lt;li>**【额外获得社区礼包】**所有参与本次编程之夏项目的同学,均可获得Apache Dubbo社区大礼包。&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>百分百有奖品拿哦&lt;/strong>,现在唯一的问题是时间不多了,赶紧上车报名,截止报名时间是6月4日,6个核心题目,快点来报名参与Apache Dubbo编程之夏吧。&lt;/p>
&lt;h2 id="课题报名方式">课题&amp;amp;报名方式&lt;/h2>
&lt;p>点开Apache Dubbo开源之夏的&lt;a href="https://summer-ospp.ac.cn/org/orgdetail/ab188e59-fab8-468f-bc89-bdc2bd8b5e64?lang=zh">链接&lt;/a> 选择你喜欢的题目:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0282?list=org&amp;amp;navpage=org">IDL 管理平台&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0286?list=org&amp;amp;navpage=org">API 管理平台&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0284?list=org&amp;amp;navpage=org">基于 Kubernetes 的集成测试体系建设&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0287?list=org&amp;amp;navpage=org">服务 JSON 序列化兼容性校验&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0289?list=org&amp;amp;navpage=org">将 Dubbo 工程结构重构为 Gradle 项目&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0292?list=org&amp;amp;navpage=org">自动化性能测试方案&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0294?list=org&amp;amp;navpage=org">移除对 jprotoc 的依赖&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0520?list=org&amp;amp;navpage=org">Node.js HTTP/2 协议实现&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/prodetail/23a7f0553?list=org&amp;amp;navpage=org">实现 Dubbo Rust 的路由模块&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>具体流程请参考 &lt;a href="https://summer-ospp.ac.cn/help/student/">学生指南&lt;/a>。&lt;/p>
&lt;p>请注意找导师沟通截止流程时间,优先更导师沟通,能帮助你更好的了解题目。&lt;/p>
&lt;p>为了方便大家报名,我们有以下咨询通道开放,如果对报名、题目、如何撰写 Proposal 有任何疑问,都可以前往咨询:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>扫码关注回复 &amp;ldquo;Apache Dubbo&amp;rdquo; 官网微信公众号,回复 “编程之夏” 加入微信沟通群&lt;/p>
&lt;p>&lt;img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/jpeg/54037/1684119089728-eae2eb7d-4098-430e-a69e-a3939265e22b.jpeg#clientId=ub09992a8-5524-4&amp;amp;from=paste&amp;amp;height=129&amp;amp;id=u938740a9&amp;amp;originHeight=258&amp;amp;originWidth=258&amp;amp;originalType=binary&amp;amp;ratio=2&amp;amp;rotation=0&amp;amp;showTitle=false&amp;amp;size=27895&amp;amp;status=done&amp;amp;style=none&amp;amp;taskId=ud0f6af1b-fed8-4a07-aa5a-4e3f3bce229&amp;amp;title=&amp;amp;width=129" alt="qrcode_for_gh_a84d4cf4c871_258 (1).jpg">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>钉钉群:22895027434(Dubbo 2023 编程之夏群),搜索并加入咨询问题&lt;/p>
&lt;/li>
&lt;li>
&lt;p>发送邮件到 Apache Dubbo 邮件组:dev@dubbo.apache.org&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h1 id="参考资料">参考资料&lt;/h1>
&lt;ul>
&lt;li>Apache Dubbo Github 仓库:
&lt;ul>
&lt;li>&lt;a href="http://github.com/apache/dubbo">Java&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://github.com/apache/dubbo-go">Go&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://github.com/apache/dubbo-js">Node.js&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://github.com/apache/dubbo-rust">Rust&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://github.com/apache/dubbo-admin">Admin&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://github.com/dubbo/">更多生态&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://dubbo.apache.org/">Apache Dubbo 官网&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://summer-ospp.ac.cn/org/orgdetail/a7f6e2ad-4acc-47f8-9471-4e54b9a166a6?lang=zh">开源之夏官网&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>为了让同学们更好地了解Apache Dubbo,我们还在观望提供了电子书供大家阅读学习。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://cn.dubbo.apache.org/zh-cn/contact/books/">Apache Dubbo 微服务开发从入门到精通&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://cn.dubbo.apache.org/zh-cn/contact/books/">Apache Dubbo3 源码深度解析&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>同时如果同学们对其他领域项目感兴趣,也可以尝试申请,例如:&lt;/p>
&lt;ul>
&lt;li>对于&lt;strong>微服务注册发现和配置管理&lt;/strong>有兴趣的同学,可以尝试填报 &lt;a href="https://summer-ospp.ac.cn/org/orgdetail/ab188e59-fab8-468f-bc89-bdc2bd8b5e64?lang=zh">Nacos 开源之夏&lt;/a>;&lt;/li>
&lt;li>对于&lt;strong>微服务分布式事务&lt;/strong>有兴趣的同学,可以尝试填报&lt;a href="https://summer-ospp.ac.cn/org/orgdetail/064c15df-705c-483a-8fc8-02831370db14?lang=zh">Seata&lt;/a>开源之夏;&lt;/li>
&lt;li>对于&lt;strong>微服务框架和RPC框架&lt;/strong>有兴趣的同学,可以尝试填报&lt;a href="https://summer-ospp.ac.cn/org/orgdetail/41d68399-ed48-4d6d-9d4d-3ff4128dc132?lang=zh">Spring Cloud Alibaba&lt;/a> 和 &lt;a href="https://summer-ospp.ac.cn/org/orgdetail/a7f6e2ad-4acc-47f8-9471-4e54b9a166a6?lang=zh">Dubbo&lt;/a> 开源之夏;&lt;/li>
&lt;li>对于&lt;strong>云原生网关&lt;/strong>有兴趣的同学,可以尝试填报&lt;a href="https://higress.io/zh-cn/blog/ospp-2023">Higress&lt;/a> 开源之夏;&lt;/li>
&lt;li>对于&lt;strong>分布式高可用防护&lt;/strong>有兴趣的同学,可以尝试填报&lt;a href="https://summer-ospp.ac.cn/org/orgdetail/5e879522-bd90-4a8b-bf8b-b11aea48626b?lang=zh">Sentinel&lt;/a> 开源之夏;&lt;/li>
&lt;li>对于&lt;strong>微服务治理&lt;/strong>有兴趣的同学,可以尝试填报&lt;a href="https://summer-ospp.ac.cn/org/orgdetail/aaff4eec-11b1-4375-997d-5eea8f51762b?lang=zh">OpenSergo&lt;/a> 开源之夏。&lt;/li>
&lt;/ul></description></item><item><title>Blog: 精进云原生 - Dubbo 3.2 正式发布</title><link>https://dubbo.apache.org/zh-cn/blog/2023/04/15/%E7%B2%BE%E8%BF%9B%E4%BA%91%E5%8E%9F%E7%94%9F-dubbo-3.2-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</link><pubDate>Sat, 15 Apr 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/04/15/%E7%B2%BE%E8%BF%9B%E4%BA%91%E5%8E%9F%E7%94%9F-dubbo-3.2-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</guid><description>
&lt;h2 id="背景介绍">背景介绍&lt;/h2>
&lt;p>Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。&lt;/p>
&lt;h2 id="rest-协议支持">Rest 协议支持&lt;/h2>
&lt;h3 id="1-why-rest">1. Why Rest?&lt;/h3>
&lt;p>随着移动互联网的普及,越来越多的应用程序需要与不同的系统进行集成。而这些系统可能使用不同的通信协议,这就需要应用程序能够灵活地适应各种协议。Rest 协议正是一种非常灵活的协议,它使用 HTTP 进行通信,可以与几乎任何系统进行集成。&lt;/p>
&lt;p>在过去,RPC框架通常使用二进制协议进行通信,这种协议非常高效,但不够灵活。相比之下,Rest协议使用HTTP进行通信,更方便与其他系统集成,也更容易与现代化的Web和移动应用程序集成。&lt;/p>
&lt;p>除了灵活性,Rest协议还具有易读性和易用性。使用Rest协议,开发人员可以使用通用的HTTP工具(例如cURL或Postman)测试和调试服务,而不需要特定的工具。此外,由于Rest协议使用标准的HTTP方法(例如GET、POST、PUT和DELETE),因此开发人员可以更容易地理解和使用服务。&lt;/p>
&lt;h3 id="2-how-to">2. How To?&lt;/h3>
&lt;p>在之前的 Dubbo 版本中,也提供了 Rest 协议的支持,但存在以下问题:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>仅支持 JAX-RS 注解域,相较于采用度更高的 Spring Web 注解,复杂度更高&lt;/p>
&lt;/li>
&lt;li>
&lt;p>需要依赖众多外部组件,如 Resteasy、tomcat、jetty 等,才能正常工作,极大地增加了使用成本。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>因此,在 Dubbo 3.2 版本中,我们引入了 Spring Web 注解域的支持以及 Rest 协议的原生支持,无需依赖任何外部组件。&lt;/p>
&lt;p>最直观的区别是,如果你升级到了 Dubbo 3.2,通过 Spring Web 发布的服务也可以直接通过 Dubbo 来发布。这一切只需要将 @Controller 注解改成 @DubboService 注解即可。&lt;/p>
&lt;p>此外,对于原来使用 Spring Boot 或者 Spring Cloud 作为服务拆分的用户,也可以基于本功能平滑地迁移到 Dubbo 上来,以极低的成本获得 Dubbo 强大的能力。&lt;/p>
&lt;h3 id="3-whats-next">3. What&amp;rsquo;s next?&lt;/h3>
&lt;p>接下来 Dubbo 还将继续完善。除了现有的特性,我们还将加入以下新的特性,以更好地满足需求:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>HTTP/2、HTTP/3 协议的原生支持。这意味着,你可以更加方便地使用 Dubbo 与其他系统进行通信,无需担心协议的兼容性问题。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>参考 Spring Web 注解,Dubbo 原生提供 Web 注解的支持,使得用户无需依赖 Spring Web 也可以获得与使用 Spring Web 相同的体验。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>支持现有服务零改造以 Rest 协议发布。这个特性可以让你更加灵活地管理你的服务,而无需对现有的服务进行任何改动。你可以通过 Rest 协议来发布你的服务,这样你的服务就可以更加方便地被其他系统所使用了。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="可观测体系">可观测体系&lt;/h2>
&lt;p>在微服务架构下,业务系统由越来越多的服务组成,服务之间互相调用,随之而来的问题是如何快速地定位故障,并及时解决。为了解决这一问题,我们需要更多的工具和技术来确保整个系统的可靠性。其中一个解决方案是使用日志记录和分析,以便可以更好地跟踪应用程序的运行情况,找到潜在的问题并及时解决。另外,使用可视化的监控工具可以帮助我们更好地理解整个系统的状态,从而更好地预测和解决问题。最后,我们还可以使用自动化测试来确保每个服务的质量,以及整个系统的稳定性和可靠性,从而更好地满足客户的需求。&lt;/p>
&lt;p>一套完整的可观测体系应该包括以下功能:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Metrics 指标监控,用于收集和分析各种指标数据,包括系统的性能、资源消耗情况等等。通过指标监控,用户可以及时了解系统的运行情况,发现异常并做出相应的处理。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Tracing 分布式追踪,用于跟踪系统中各个服务之间的调用链路,帮助用户发现和定位潜在的性能问题、瓶颈等等。通过分布式追踪,用户可以深入了解系统的运作过程,识别出可能存在的问题并进行有效的优化和调整。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Logging 日志管理,用于记录系统中发生的各种事件和操作,包括错误日志、访问日志、事务日志等等。通过日志管理,用户可以了解系统的运行情况、故障信息等等,帮助用户快速定位问题并进行相应的处理。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>综上所述,以上三个功能不仅可以帮助用户快速定位故障,提高系统的可靠性和稳定性,还可以帮助用户深入了解系统的运行情况和性能状况,为用户提供全方位的监控和保障。&lt;/p>
&lt;p>在 Dubbo 3.2 版本中,我们主要就 Metrics 和 Tracing 两个方面进行了增强。&lt;/p>
&lt;h3 id="1-metrics">1. Metrics&lt;/h3>
&lt;p>在 Metrics 方面,我们使用 Micrometer 大幅增加了指标的埋点,包括但不限于 QPS、RT、调用总数、成功数、失败数、失败原因统计等核心服务指标。为了更好地监测服务运行状态,Dubbo 还提供了对核心组件状态的监控,例如线程池数量、服务健康状态等。此外,Dubbo 还支持标准 Prometheus 的 Pull 和 Push 模式,并提供了若干个官方原生的 Grafana 面板,实现面向生产的 Metrics 全天候观测。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/32-release/Untitled.png" alt="img">&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/32-release/Untitled%201.png" alt="Untitled">&lt;/p>
&lt;p>对于所有的用户,只需要升级到 Dubbo 3.2 版本,并添加 dubbo-spring-boot-observability-starter 依赖即可获得 Metrics 能力。在应用启动后,将在 Dubbo QoS 的 metrics 命令下暴露相关的指标,本地可以通过 &lt;code>http://127.0.0.1:22222/metrics&lt;/code> 获取。此外对于使用了 Spring Actuator 的用户,Dubbo 也将默认将这些数据暴露出来。&lt;/p>
&lt;h3 id="tracing">Tracing&lt;/h3>
&lt;p>在 Tracing 方面,我们还基于 Micrometer 实现了请求运行时的埋点跟踪。我们通过 Filter 拦截器原生方式来实现这一功能。我们支持将跟踪数据导出到一些主流实现,例如 Zipkin、Skywalking、Jaeger 等。这样就可以实现全链路跟踪数据的分析和可视化展示。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/32-release/Untitled%202.png" alt="Untitled">&lt;/p>
&lt;h3 id="logging">Logging&lt;/h3>
&lt;p>此外,对于 Logging 方面,Dubbo 从 3.1 版本开始引入了错误码机制,实现了 WARN、ERROR 级别日志的全覆盖。在异常场景下,支持快速索引官网解决文档。&lt;/p>
&lt;h2 id="native-image-原生支持">Native Image 原生支持&lt;/h2>
&lt;p>在Native Image方面,Dubbo从3.2开始将正式基于GraalVM完成对Native Image 的支持,从Dubbo3.0开始,Dubbo已经有一些Native Image支持的探索,但是易用性和支持程度都不太理想,从3.2版本开始,Dubbo将会简化用户接入Native Image的使用方式。主要可以分为三个面:&lt;/p>
&lt;ol>
&lt;li>编译插件配置升级:从最初的 native-image-maven-plugin 改为 dubbo-maven-plugin +native-maven-plugin,区分了Graalvm官方提供的native image配置与Dubbo所需的native image配置,简化了用户所需要关心的native image配置&lt;/li>
&lt;/ol>
&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-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;plugin&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;groupId&amp;gt;&lt;/span>org.graalvm.nativeimage&lt;span style="color:#268bd2">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;artifactId&amp;gt;&lt;/span>native-image-maven-plugin&lt;span style="color:#268bd2">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;version&amp;gt;&lt;/span>21.0.0.2&lt;span style="color:#268bd2">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;executions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;execution&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;goals&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;goal&amp;gt;&lt;/span>native-image&lt;span style="color:#268bd2">&amp;lt;/goal&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/goals&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;phase&amp;gt;&lt;/span>package&lt;span style="color:#268bd2">&amp;lt;/phase&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/execution&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/executions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;configuration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;skip&amp;gt;&lt;/span>false&lt;span style="color:#268bd2">&amp;lt;/skip&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;imageName&amp;gt;&lt;/span>demo-native-provider&lt;span style="color:#268bd2">&amp;lt;/imageName&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;mainClass&amp;gt;&lt;/span>org.apache.dubbo.demo.graalvm.provider.Application&lt;span style="color:#268bd2">&amp;lt;/mainClass&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;buildArgs&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --no-fallback
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.slf4j.MDC
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.slf4j.LoggerFactory
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.apache.log4j.helpers.Loader
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.apache.log4j.Logger
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.apache.log4j.helpers.LogLog
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.apache.log4j.LogManager
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.apache.log4j.spi.LoggingEvent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.slf4j.impl.Log4jLoggerFactory
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.slf4j.impl.Log4jLoggerAdapter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-build-time=org.eclipse.collections.api.factory.Sets
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.epoll.Epoll
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.epoll.Native
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.DefaultFileRegion
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventLoop
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.kqueue.Native
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.unix.Errors
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.unix.IovArray
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.unix.Limits
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.util.internal.logging.Log4JLogger
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.unix.Socket
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --initialize-at-run-time=io.netty.channel.ChannelHandlerMask
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --report-unsupported-elements-at-runtime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --allow-incomplete-classpath
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --enable-url-protocols=http
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> -H:+ReportExceptionStackTraces
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/buildArgs&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/configuration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/plugin&amp;gt;&lt;/span>
&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-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;plugin&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;groupId&amp;gt;&lt;/span>org.graalvm.buildtools&lt;span style="color:#268bd2">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;artifactId&amp;gt;&lt;/span>native-maven-plugin&lt;span style="color:#268bd2">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;version&amp;gt;&lt;/span>0.9.20&lt;span style="color:#268bd2">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;configuration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;classesDirectory&amp;gt;&lt;/span>${project.build.outputDirectory}&lt;span style="color:#268bd2">&amp;lt;/classesDirectory&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;metadataRepository&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;enabled&amp;gt;&lt;/span>true&lt;span style="color:#268bd2">&amp;lt;/enabled&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/metadataRepository&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;requiredVersion&amp;gt;&lt;/span>22.3&lt;span style="color:#268bd2">&amp;lt;/requiredVersion&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;mainClass&amp;gt;&lt;/span>org.apache.dubbo.demo.graalvm.provider.Application&lt;span style="color:#268bd2">&amp;lt;/mainClass&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/configuration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/plugin&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;plugin&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;groupId&amp;gt;&lt;/span>org.apache.dubbo&lt;span style="color:#268bd2">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;artifactId&amp;gt;&lt;/span>dubbo-maven-plugin&lt;span style="color:#268bd2">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;version&amp;gt;&lt;/span>${project.version}&lt;span style="color:#268bd2">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;configuration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;mainClass&amp;gt;&lt;/span>org.apache.dubbo.demo.graalvm.provider.Application&lt;span style="color:#268bd2">&amp;lt;/mainClass&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/configuration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;executions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;execution&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;phase&amp;gt;&lt;/span>process-sources&lt;span style="color:#268bd2">&amp;lt;/phase&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;goals&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;goal&amp;gt;&lt;/span>dubbo-process-aot&lt;span style="color:#268bd2">&amp;lt;/goal&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/goals&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/execution&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/executions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/plugin&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol>
&lt;li>旧版本中需要用户手动生成和补全Dubbo内独有的Adaptive代码,新版本用户将不需要关心这些细节。&lt;/li>
&lt;li>旧版本中Dubbo框架生成的META-INF.native-image下的配置文件会直接生成在用户的工程目录中,3.2新版本将会被编译到target下,不影响用户的工程结构。除此之外,Dubbo框架也将不再采用手动补全native image的方式,而且采用自动探测和生成所需的配置文件的方式,简化了Dubbo开发者的体验。这也能够降低最后编译后的二进制包的大小和提高编译速度。&lt;/li>
&lt;/ol>
&lt;p>除了易用性提升以外,Dubbo将在3.2版本将在native image场景下支持API、注解以及XML配置方式,并支持与SpringBoot3中的native兼容。&lt;/p>
&lt;h2 id="其他">其他&lt;/h2>
&lt;h3 id="jdk-17--spring-boot-3-原生支持">JDK 17 &amp;amp; Spring Boot 3 原生支持&lt;/h3>
&lt;p>JDK 17 是继 JDK 11 之后目前 Java 的最新 LTS 版本,包括许多新功能和改进,例如 Sealed 类、垃圾收集器的改进等等。&lt;/p>
&lt;p>自从 JDK 16 开始限制 Java 内部类反射以后,Dubbo 的序列化以及动态代理都受到了一定的影响。在 Dubbo 3.2 中,我们通过 Fastjson2 以及 Javassist 的优化从底层解决了兼容性问题。目前 Dubbo 已经可以完美运行在 JDK17 之上,所有单元测试以及大多数集成测试也都在 JDK 17 平台上测试通过。&lt;/p>
&lt;p>针对即将发布的 JDK 21 LTS,Dubbo 正在紧锣密鼓地进行适配。我们将在 3.3 版本中加入对 JDK 21 和 Dubbo 协程(Project Loom)的支持。&lt;/p>
&lt;h3 id="rpc-性能大幅提升">RPC 性能大幅提升&lt;/h3>
&lt;p>在3.2版本中,我们对RPC调用性能做了调优,其中优化内容如下。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>消除了同步锁竞争以及会出现阻塞的代码(&lt;code>triple&lt;/code>)&lt;/p>
&lt;ol>
&lt;li>在3.1版本中创建HTTP/2 Stream Channel时采用了同步阻塞用户线程的方式等待Stream Channel创建完成,创建完成后才开始发起远程调用。而在3.2中我们将创建HTTP/2 Stream Channel的行为&lt;code>异步化&lt;/code>并保证创建完毕后才发起请求,以此&lt;code>减少了用户线程不必要的等待&lt;/code>。&lt;/li>
&lt;li>在3.1版本中用户线程与Netty的I/O线程出现了同步锁竞争,IO线程每次写请求都会检查Socket可用性,而用户线程中也使用了Socket可用性检查的方法,但JDK中Socket可用性检查的实现使用了 &lt;code>synchronized&lt;/code> 来保证并发安全,为了减少这部分的耗时我们将用户线程的检查移除,消除了该部分的耗时。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>减少了用同步阻塞调用方式的请求响应延迟(&lt;code>dubbo&lt;/code>、&lt;code>triple&lt;/code>)&lt;/p>
&lt;p>在3.1版本中SYNC模式下的RPC调用我们使用了阻塞队列的方式等待远程服务写回的响应,当响应写回后会添加到队列中并唤醒被阻塞的用户线程。而在3.2中我们将阻塞队列更换为并发队列,利用其CAS的机制大幅度减少线程进入阻塞的次数,提高CPU利用率并降低了响应处理延迟&lt;/p>
&lt;/li>
&lt;li>
&lt;p>减少了线程切换的次数(&lt;code>triple&lt;/code>)&lt;/p>
&lt;p>在3.1版本中SYNC模式下的RPC调用在接收响应时使用了一个消费者线程池进行处理,处理完毕后才唤醒用户线程接收响应。但通过分析SYNC模式下的消费者线程池是不必要的,多了一层消费者线程池处理不仅浪费服务器资源还降低了性能,因此我们在3.2版本中将SYNC模式下消费者线程池移除,交互模型由 &lt;code>NettyEventLoop → ConsumerThread → UserThread&lt;/code>变成了&lt;code>NettyEventLoop → UserThread&lt;/code>,以此减少服务器资源的浪费同时提高了性能&lt;/p>
&lt;/li>
&lt;li>
&lt;p>优化了I/O性能(&lt;code>dubbo&lt;/code>、&lt;code>triple&lt;/code>)&lt;/p>
&lt;p>在3.1版本中我们利用了Netty框架实现了网络通讯,但每次往对端写消息时都直接刷写到对端导致系统调用次数极高,降低了通讯性能。为此我们在3.2版本中对该进行了优化,每次发消息时是先将消息提交到一个写队列中,并在合适的时机将多个消息一次性写出,以此提高了I/O利用率,大幅度提高RPC通讯性能。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>支持在用户线程上序列化报文(&lt;code>dubbo&lt;/code>、&lt;code>triple&lt;/code>)&lt;/p>
&lt;p>在3.1版本中RPC通讯中的报文反序列化均是在单一I/O线程中串行执行的,导致无法利用多核CPU的优势。为此我们在3.2版本中支持了在用户线程上执行反序列化这类较为耗时的任务,将I/O线程的压力均分到多个CPU核心上,以此提高了&lt;code>较大报文&lt;/code>场景下的RPC性能。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>3.2对比3.1的性能提升如下:&lt;/p>
&lt;p>Triple协议:较小报文场景createUser、existUser、getUser下,提升率约在&lt;code>40-45%&lt;/code>,提升后的性能与gRPC同场景的性能基本持平。较大报文场景listUser下提升了约&lt;code>17%&lt;/code>,相较于同场景下的gRPC还低&lt;code>11%&lt;/code>。&lt;/p>
&lt;p>Dubbo协议:较小报文场景createUser、getUser下,提升率约&lt;code>180%&lt;/code>。极小报文existUser(仅一个boolean值)下提升率约&lt;code>24%&lt;/code>,而较大报文listUser提升率最高,达到了&lt;code>1000%&lt;/code>!&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/32-release/Untitled%203.png" alt="Untitled">&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/32-release/Untitled%204.png" alt="Untitled">&lt;/p>
&lt;h2 id="如何升级到-dubbo-32">如何升级到 Dubbo 3.2&lt;/h2>
&lt;h3 id="pom-升级">Pom 升级&lt;/h3>
&lt;p>最新的 Dubbo Maven 坐标为:&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-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;groupId&amp;gt;&lt;/span>org.apache.dubbo&lt;span style="color:#268bd2">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;artifactId&amp;gt;&lt;/span>dubbo&lt;span style="color:#268bd2">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;version&amp;gt;&lt;/span>3.2.0&lt;span style="color:#268bd2">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="兼容性">兼容性&lt;/h3>
&lt;p>对于绝大多数的用户,升级到 Dubbo 3.2.0 是完全平滑的,仅需要修改依赖包版本即可。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>序列化校验逻辑的增强(&lt;strong>重要&lt;/strong>)&lt;/p>
&lt;p>如前文所述,在 Dubbo 3.2.0 版本中,Dubbo 将默认开启序列化白名单的强校验,以提升 Dubbo 的安全性,避免远程命令执行的问题。目前的机制通过包名递归机制自动信任了部分类,但对于一些使用了泛型等可能存在扫描不全的用户,我们建议您先升级到 Dubbo 3.1.9 版本或添加 &lt;code>-Ddubbo.application.serialize-check-status=WARN&lt;/code> 配置。观察一段时间后(通过日志、QoS 命令),如果没有触发安全告警,则可以配置强校验模式。&lt;/p>
&lt;p>关于自定义白名单的配置,可以参考官网的 &lt;code>文档 / SDK 手册 / Java SDK / 高级特性和用法 / 提升安全性 / 类检查机制&lt;/code> 一文进行配置。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>默认序列化的修改&lt;/p>
&lt;p>Dubbo 3.2.0 版本开始默认序列化方式从 &lt;code>hessian2&lt;/code> 切换为 &lt;code>fastjson2&lt;/code>,对于升级到 3.2.0 的应用,Dubbo 会自动尝试采用 &lt;code>fastjson2&lt;/code> 进行序列化。请注意,无论是客户端还是服务端,只要有一端还没有升级到 3.2.0,都将降级为 &lt;code>hessian2&lt;/code> 序列化,保证兼容性。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>默认关闭推空保护&lt;/p>
&lt;p>推空保护的目的是在注册中心出现故障并且主动推送空地址的时候,Dubbo 保留最后一批 provider 信息,以保证服务可用。但是,在大多数情况下,即使注册中心出现故障,也不会推送空地址,只有在一些特殊情况下才会出现。如果开启推空保护,则会对 Dubbo 的 Fallback 逻辑、心跳逻辑等造成较大的影响,给开发人员使用 Dubbo 带来困扰。&lt;/p>
&lt;p>如果在生产环境中需要开启推空保护以实现高可用性,可以将 &lt;code>dubbo.application.enable-empty-protection&lt;/code> 配置为 &lt;code>true&lt;/code>。但是请注意,已知开启推空保护会导致服务端应用从仅支持接口级服务发现的 &lt;code>2.6.x&lt;/code>、&lt;code>2.7.x&lt;/code> 版本升级到 &lt;code>3.x&lt;/code> 之后回滚到原来的版本时出现异常,极端情况下可能会导致服务调用失败。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="总结">总结&lt;/h2>
&lt;p>Dubbo 3.2 是一个非常重要的版本,它带来了众多新功能和改进,使得 Dubbo 更加强大和易用。我们非常感谢社区的支持和贡献,希望大家可以尽快体验 Dubbo 3.2,享受其中带来的便利和优势。&lt;/p></description></item><item><title>Blog: 2022 年度总结与 2023 新年规划</title><link>https://dubbo.apache.org/zh-cn/blog/2023/02/23/2022-%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93%E4%B8%8E-2023-%E6%96%B0%E5%B9%B4%E8%A7%84%E5%88%92/</link><pubDate>Thu, 23 Feb 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/02/23/2022-%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93%E4%B8%8E-2023-%E6%96%B0%E5%B9%B4%E8%A7%84%E5%88%92/</guid><description>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/roadmap/2023-roadmap.jpg" alt="dubbo-introduction">&lt;/p>
&lt;h2 id="2022-年度总结">2022 年度总结&lt;/h2>
&lt;h3 id="1-dubbo-开源-12-周年">1 Dubbo 开源 12 周年&lt;/h3>
&lt;p>50k+ star,30k fork,1000+ Contributor&lt;/p>
&lt;h3 id="2-dubbo3-里程碑">2 Dubbo3 里程碑&lt;/h3>
&lt;h3 id="实现规模化生产检验">实现规模化生产检验&lt;/h3>
&lt;p>阿里巴巴核心微服务集群实现从 HSF 到 Dubbo3 的全面升级,顺利支撑双十一、双十二万亿级服务调用&lt;/p>
&lt;h3 id="发力多语言生态">发力多语言生态&lt;/h3>
&lt;h4 id="具备生产可用条件">具备生产可用条件&lt;/h4>
&lt;p>Java、Go&lt;/p>
&lt;h4 id="从孵化走向成熟">从孵化走向成熟&lt;/h4>
&lt;p>Rust、Node.js、Python&lt;/p>
&lt;h3 id="3-核心技术">3 核心技术&lt;/h3>
&lt;p>应用级服务发现
HTTP/2 协议
流量管控升级
可观测性
自适应负载均衡
Proxyless Mesh
Spring Boot3 &amp;amp; Spring6&lt;/p>
&lt;h3 id="4-新晋-committerspmc">4 新晋 Committers&amp;amp;PMC&lt;/h3>
&lt;p>本年度社区共发展 Committer 13 位,PMC 4 位&lt;/p>
&lt;h2 id="2023-新年规划">2023 新年规划&lt;/h2>
&lt;ul>
&lt;li>官网与文档体验全面提升&lt;/li>
&lt;li>Go、Node.js、Rust 等多语言体系建设&lt;/li>
&lt;li>全面提升整体可观测性&lt;/li>
&lt;li>Dubbo Admin 一站式服务运维管控平台&lt;/li>
&lt;li>Dubbo Mesh 走向成熟&lt;/li>
&lt;li>提升 HTTP 开发体验,补全 Web 互通&lt;/li>
&lt;li>打造 gRPC over Dubbo 最佳实践&lt;/li>
&lt;li>完善的认证鉴权体系&lt;/li>
&lt;/ul></description></item><item><title>Blog: 一文帮你快速了解 Dubbo 核心能力</title><link>https://dubbo.apache.org/zh-cn/blog/2023/02/23/%E4%B8%80%E6%96%87%E5%B8%AE%E4%BD%A0%E5%BF%AB%E9%80%9F%E4%BA%86%E8%A7%A3-dubbo-%E6%A0%B8%E5%BF%83%E8%83%BD%E5%8A%9B/</link><pubDate>Thu, 23 Feb 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/02/23/%E4%B8%80%E6%96%87%E5%B8%AE%E4%BD%A0%E5%BF%AB%E9%80%9F%E4%BA%86%E8%A7%A3-dubbo-%E6%A0%B8%E5%BF%83%E8%83%BD%E5%8A%9B/</guid><description>
&lt;h2 id="dubbo-简介">Dubbo 简介&lt;/h2>
&lt;h3 id="一句话定义">一句话定义&lt;/h3>
&lt;p>Apache Dubbo 是一款微服务开发框架,它帮助解决微服务开发中的通信问题,同时为构建企业级微服务的提供服务治理能力,Dubbo 不绑定编程语言,我们的目标是为所有主流语言提供对等的微服务开发体验。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/1-overview.jpg" alt="overview">&lt;/p>
&lt;h3 id="基本架构">基本架构&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/2-arc.jpg" alt="overview">&lt;/p>
&lt;p>Dubbo 从架构图上分为数据面和控制面。在数据面,使用 Dubbo 开发的微服务进程间基于 RPC 协议通信。DubboAdmin 控制面作为服务治理的抽象入口,由一系列可选的服务治理组件构成,负责 Dubbo集群的服务发现、流量管控策略、可视化监测。&lt;/p>
&lt;h3 id="行业应用">行业应用&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/3-usecase.jpg" alt="overview">&lt;/p>
&lt;p>Dubbo 设计用于解决阿里巴巴内部大规模 微服务集群实践难题,当前已被广泛应用于几乎所有行业的微服务实践中。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/4-usecase-alibaba.jpg" alt="overview">&lt;/p>
&lt;p>以阿里巴巴为例,在 2021 年,阿里巴巴基于内部多年 HSF 框架实践积累,面向云原生架构设计了下一代微服务框架 Dubbo3,用于解决性能、治理升级、服务网格等一系列问题;截止目前,阿里巴巴已全面完成从 HSF到 Dubbo3 的迁移,核心业务都跑在开源 Dubbo3 之上。&lt;/p>
&lt;h2 id="dubbo-到底提供了哪些核心能力">Dubbo 到底提供了哪些核心能力?&lt;/h2>
&lt;h3 id="提供微服务抽象与框架">提供微服务抽象与框架&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/5-framework.jpg" alt="overview">&lt;/p>
&lt;p>首先,Dubbo 作为服务开发框架解决了业务应用中微服务定义、暴露、通信与治理的问题,为业务应用开发定义了一套微服务编程范式。
具体来说,Dubbo 为业务应用提供了微服务开发API、RPC 协议、服务治理三大核心能力,让开发者真正的专注业务逻辑开发。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/6-extensibility.jpg" alt="overview">&lt;/p>
&lt;p>Dubbo 不是应用框架的替代者,它可以很好的工作在每种语言的主流编程框架之上,以 Java 为例,Dubbo 可以很好的与 Spring 协作,并在此基础上提供服务定义、微服务编程、服务发现、负载均衡、流量管控等能力。&lt;/p>
&lt;h3 id="提供灵活的通信协议切换能力">提供灵活的通信协议切换能力&lt;/h3>
&lt;p>在通信方面,Dubbo 区别于其他 RPC 框架的是它不绑定特定协议,你可以在底层选用 HTTP./2、TCP、gRPC、REST、Hessian 等任意通信协议,同时享受统一的 API、以及对等的服务治理能力。&lt;/p>
&lt;h3 id="一切皆可扩展">一切皆可扩展&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/8-extensibility.jpg" alt="overview">&lt;/p>
&lt;p>Dubbo 的另一个优势在于其可扩展性设计,从流量管控、协议编码、诊断调优、再到服务治理,你都可以去扩展,满足企业级微服务开发与运维的所有诉求。&lt;/p>
&lt;h3 id="丰富的生态">丰富的生态&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/9-ecosystem.jpg" alt="overview">&lt;/p>
&lt;p>基于扩展能力 Dubbo 官方提供了丰富的生态适配,涵盖了所有主流的开源微服务组件。&lt;/p>
&lt;h3 id="服务网格">服务网格&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/10-mesh.jpg" alt="overview">&lt;/p>
&lt;p>对于服务网格架构,Dubbo也可以轻松接入原生 Istio 体系;
在数据面支持与 Envoy 部署的 Proxy 模式,也支持无 Envoy 的 Proxyless 模式,提供更灵活的数据面选择。&lt;/p>
&lt;h2 id="构建企业级dubbo-微服务有多简单你只需要-4-步">构建企业级Dubbo 微服务有多简单?你只需要 4 步&lt;/h2>
&lt;p>我们以 Java 微服务开发为例。&lt;/p>
&lt;h3 id="第一步">第一步&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/11-initializer.png" alt="overview">&lt;/p>
&lt;p>使用 &lt;a href="https://start.dubbo.apache.org/bootstrap.html">官方脚手架&lt;/a> 快速创建项目模板,只需要选择依赖的版本、组件,点击 “获取代码” 即可&lt;/p>
&lt;h3 id="第二步">第二步&lt;/h3>
&lt;p>将模板项目导入 IDE 开发环境。
定义 Java 接口作为 Dubbo 服务。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/12-interface.jpg" alt="overview">&lt;/p>
&lt;p>开发 Dubbo 服务端,实现接口并完成业务逻辑编码,通过一条简单的注解配置完成服务发布。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/13-impl.jpg" alt="overview">&lt;/p>
&lt;p>开发Dubbo 客户端,通过注解声明 Dubbo 服务,然后就可以发起远程方法调用了。至此,开发工作完成。
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/14-reference.jpg" alt="overview">&lt;/p>
&lt;h3 id="第三步">第三步&lt;/h3>
&lt;p>进入部署环节,我们选择 Kubernetes 作为部署环境。&lt;/p>
&lt;p>首先,通过一条命令安装 dubbo-admin 等服务治理组件,安装成功之后,我们查看部署状态。接下来,开始部署业务应用,随后查看确认直到应用已经正常启动
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/15-deploy.jpg" alt="overview">&lt;/p>
&lt;p>然后,我们就可以打开 Admin 控制台查看服务部署与调用情况了。这里是 Dubbo Admin 控制台的页面显示效果,可以看到刚才启动的 Dubbo 服务部署状态;除此之外,Admin 还提供了更详细的流量监控监测,点击服务统计,可进入监控页面&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/16-admin.jpg" alt="overview">&lt;/p>
&lt;p>你可以在此了解Dubbo 集群的详细运行状态,包括每个应用对外服务和调用服务的情况,QpS、成功率等,还可以查看每个实例的资源健康状况。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/17-grafana1.png" alt="overview">&lt;/p>
&lt;h3 id="第四步">第四步&lt;/h3>
&lt;p>进行流量管控。当应用已经平稳运行后,进一步控制流量的访问行为,包括实现金丝雀发布、全链路灰度、动态调整超时时间、调整权重、按比例流量分发、参数路由等。控制台提供了可视化的流量治理规则操作入口,在这里可以直接下发流量规则。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/19-gray.jpg" alt="overview">&lt;/p>
&lt;p>以一个线上环境的灰度隔离示例,通过 Dubbo 流量管控机制,我们可以给每个应用的一部分机器打上 gray 标签,接下来,对于入口为 gray 的流量,就可以控制确保它只在有 gray 标记的 Dubbo 实例内流转,实现了全链路的逻辑隔离效果,
对于隔离多套开发环境、线上灰度测试等场景都非常有用。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/20-region.jpg" alt="overview">&lt;/p>
&lt;p>对于同区域优先调用的场景,这里有两个应用做了多区域部署,紫色是杭州区域、蓝色是北京区域,部署在橙色区域的应用会优先访问同区域的应用,以此降低访问延迟,蓝色区域部署的服务亦是如此。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/introduction/21-region.jpg" alt="overview">&lt;/p>
&lt;p>当应用在同区域区域部署的实例不可用时,调用会自动跨区域切换到其他可用区,确保整体可用性。&lt;/p>
&lt;h2 id="总结">总结&lt;/h2>
&lt;p>接下来,请开始你的Dubbo 之旅吧。&lt;/p></description></item><item><title>Blog: Dubbo 在 Proxyless Mesh 模式下的探索与改进</title><link>https://dubbo.apache.org/zh-cn/blog/2023/02/02/dubbo-%E5%9C%A8-proxyless-mesh-%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E6%8E%A2%E7%B4%A2%E4%B8%8E%E6%94%B9%E8%BF%9B/</link><pubDate>Thu, 02 Feb 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/02/02/dubbo-%E5%9C%A8-proxyless-mesh-%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E6%8E%A2%E7%B4%A2%E4%B8%8E%E6%94%B9%E8%BF%9B/</guid><description>
&lt;h2 id="一背景">一、背景&lt;/h2>
&lt;p>随着 Docker 和 Kubernetes 的出现,一个庞大的单体应用可以被拆分成多个独立部署的微服务,并被打包运行于对应的容器中。不同应用之间相互通信,以共同完成某一功能模块。微服务架构与容器化部署带来的好处是显而易见的,它降低了服务间的耦合性,利于开发和维护,能更有效地利用计算资源。当然,微服务架构也存在相应的缺点:&lt;/p>
&lt;ul>
&lt;li>强依赖于 SDK,业务模块与治理模块耦合较为严重。 除了相关依赖,往往还需要在业务代码中嵌入SDK代码或配置。&lt;/li>
&lt;li>统一治理难。每次框架升级都需要修改 SDK 版本,并重新进行回归测试,确认功能正常后再对每一台机器重新部署上线。不同服务引用的 SDK 版本不统一、能力参差不齐,增大了统一治理的难度。&lt;/li>
&lt;li>缺少一套统一解决方案。目前市场不存在一整套功能完善、无死角的微服务治理与解决方案。在实际生产环境往往还需要引入多个治理组件来完成像灰度发布、故障注入等功能。&lt;/li>
&lt;/ul>
&lt;p>为解决这些痛点,Service Mesh诞生了。以经典的 Sidecar 模式为例,它通过在业务 Pod 中注入 Sidecar 容器,对代理流量实施治理和管控,将框架的治理能力下层到 Sidecar 容器中,与业务系统解耦,从而轻松实现多语言、多协议的统一流量管控、监控等需求。通过剥离SDK能力并拆解为独立进程,从而解决了强依赖于SDK的问题,从而使开发人员可以更加专注于业务本身,实现了基础框架能力的下沉,如下图所示(源自dubbo官网):
&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/2/1.png" alt="image.png">&lt;/p>
&lt;p>经典的 Sidecar Mesh 部署架构有很多优势,如减少SDK耦合、业务侵入小等,但增加了一层代理,也带来了一些额外的问题,比如:&lt;/p>
&lt;ul>
&lt;li>Sidecar 代理会损耗一部分性能,当网络结构层级比较复杂时尤其明显,对性能要求很高的业务造成了一定的困扰。&lt;/li>
&lt;li>架构更加复杂,对运维人员要求高。&lt;/li>
&lt;li>对部署环境有一定的要求,需要其能支持 Sidecar 代理的运行。&lt;/li>
&lt;/ul>
&lt;p>为解决这些痛点,Proxyless Service Mesh 模式诞生了。传统服务网格通过代理的方式拦截所有的业务网络流量,代理需要感知到控制平面下发的配置资源,从而按照要求控制网络流量的走向。以istio为例,Proxyless 模式是指应用直接与负责控制平面的 istiod 进程通信,istiod 进程通过监听并获取 Kubernetes 的资源,例如 Service、Endpoint 等,并将这些资源统一通过 xDS 协议下发到不同的 RPC 框架,由 RPC 框架进行请求转发,从而实现服务发现和服务治理等能力。
Dubbo 社区是国内最早开始对 Proxyless Service Mesh 模式进行探索的社区,这是由于相比于 Service Mesh,Proxyless 模式落地成本较低,对于中小企业来说是一个较好的选择。Dubbo 在 3.1 版本中通过对 xDS 协议进行解析,新增了对 Proxyless 的支持。xDS 是一类发现服务的总称,应用通过 xDS API 可以动态获取 Listener(监听器)、Route(路由)、Cluster(集群)、Endpoint(集群成员) 以及 Secret(证书)配置。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/2/2.jpeg" alt="image.png">&lt;/p>
&lt;p>通过 Proxyless 模式,Dubbo 与 Control Plane 直接建立通信,进而实现控制面对流量管控、服务治理、可观测性、安全等的统一管控,从而规避 Sidecar 模式带来的性能损耗与部署架构复杂性。&lt;/p>
&lt;h2 id="二dubbo-xds-推送机制详解">二、Dubbo xDS 推送机制详解&lt;/h2>
&lt;p>从整体上看,istio control plane 和 dubbo 的交互时序图如上。Dubbo 里 xDS 处理的主要逻辑在 PilotExchanger 和各个 DS (LDS、RDS、CDS、EDS) 的对应协议的具体实现里。PilotExchanger 统一负责串联逻辑,主要有三大逻辑:&lt;/p>
&lt;ul>
&lt;li>获取授信证书。&lt;/li>
&lt;li>调用不同 protocol 的 getResource 获取资源。&lt;/li>
&lt;li>调用不同 protocol 得 observeResource 方法监听资源变更。&lt;/li>
&lt;/ul>
&lt;p>例如对于 lds 和 rds,PilotExchanger 会调用 lds 的 getResource 方法与 istio 建立通信连接,发送数据并解析来自 istio 的响应,解析完成后的 resource 资源会作 为rds 调用 getResource 方法的入参,并由 rds 发送数据给 istio。当 lds 发生变更时,则由 lds 的 observeResource 方法去触发自身与 rds 的变更。上述关系对于 rds 和 eds 同样如此。现有交互如下,上述过程对应图里红线的流程:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/2/3.jpeg" alt="image.png">&lt;/p>
&lt;p>在第一次成功获取资源之后,各个DS会通过定时任务去不断发送请求给 istio,并解析响应结果和保持与 istio 之间的交互,进而实现控制面对流量管控、服务治理、可观测性方面的管控,其流程对应上图蓝线部分。&lt;/p>
&lt;h2 id="三当前dubbo-proxyless实现存在的不足">三、当前Dubbo Proxyless实现存在的不足&lt;/h2>
&lt;p>Dubbo Proxyless 模式经过验证之后,已经证明了其可靠性。现有 Dubbo proxyless 的实现方案存在以下问题:&lt;/p>
&lt;ul>
&lt;li>目前与 istio 交互的逻辑是推送模式。getResource 和 observeResource 是两条不同的 stream 流,每次发送新请求都需要重新建立连接。但我们建立的 stream 流是双向流动的,istio 在监听到资源变化后由主动推送即可,LDS、RDS、EDS 分别只需要维护一条 stream 流。&lt;/li>
&lt;li>Stream 流模式改为建立持久化连接之后,需要设计一个本地的缓存池,去存储已经存在的资源。当 istio 主动推送更新后,需要去刷新缓存池的数据。&lt;/li>
&lt;li>现有observeResource 逻辑是通过定时任务去轮询istio。现在 observeResource 不再需要定时去轮询,只需要将需要监听的资源加入到缓存池,等 istio 自动推送即可,且 istio 推送回来的数据需要按照 app 切分好,实现多点监听,后续 dubbo 支持其他 DS 模式,也可复用相应的逻辑。&lt;/li>
&lt;li>目前由 istio 托管的 dubbo 应用在 istio 掉线后会抛出异常,断线后无法重新连接,只能重新部署应用,增加了运维和管理的复杂度。我们需增加断线重连的功能,等 istio 恢复正常后无需重新部署即可重连。&lt;/li>
&lt;/ul>
&lt;p>改造完成后的交互逻辑:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/2/4.jpeg" alt="image.png">&lt;/p>
&lt;h2 id="四xds-监听模式实现方案">四、Xds 监听模式实现方案&lt;/h2>
&lt;h3 id="41-资源缓存池">4.1 资源缓存池&lt;/h3>
&lt;p>目前 Dubbo 的资源类型有LDS,RDS,EDS。对于同一个进程,三种资源监听的所有资源都与 istio 对该进程所缓存的资源监听列表一一对应。因此针对这三种资源,我们应该设计分别对应的本地的资源缓存池,dubbo 尝试资源的时候先去缓存池查询,若有结果则直接返回;否则将本地缓存池的资源列表与想要发送的资源聚合后,发送给 istio 让其更新自身的监听列表。缓存池如下,其中 key 代表单个资源,T 为不同 DS 的返回结果:&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">protected&lt;/span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, T&lt;span style="color:#719e07">&amp;gt;&lt;/span> resourcesMap &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ConcurrentHashMap&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>有了缓存池我们必须有一个监听缓存池的结构或者容器,在这里我们设计为 Map 的形式,如下:&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">protected&lt;/span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>Set&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span>, List&lt;span style="color:#719e07">&amp;lt;&lt;/span>Consumer&lt;span style="color:#719e07">&amp;lt;&lt;/span>Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, T&lt;span style="color:#719e07">&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span> consumerObserveMap &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ConcurrentHashMap&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>其中key为想要监听的资源,value 为一个 List, 之所以设计为 List 是为了可以支持重复订阅。 List 存储的 item 为 jdk8 中的 Consumer 类型,它可以用于传递一个函数或者行为,其入参为 Map&amp;lt;String, T&amp;gt;,其 key 对应所要监听的单个资源,便于从缓存池中获取。如上文所述,PilotExchanger 负责串联整个流程,不同 DS 之间的更新关系可以用 Consumer 进行传递。以监听 LDS observeResource 为例, 大致代码如下:&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:#586e75">// 监听&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">observeResource&lt;/span>(Set&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span> resourceNames, Consumer&lt;span style="color:#719e07">&amp;lt;&lt;/span>Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, T&lt;span style="color:#719e07">&amp;gt;&amp;gt;&lt;/span> consumer, &lt;span style="color:#dc322f">boolean&lt;/span> isReConnect);
&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">// Observe LDS updated&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ldsProtocol.observeResource(ldsResourcesName, (newListener) &lt;span style="color:#719e07">-&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// LDS数据不一致&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>newListener.equals(listenerResult)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//更新LDS数据&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">this&lt;/span>.listenerResult &lt;span style="color:#719e07">=&lt;/span> newListener;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 触发RDS监听&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (isRdsObserve.get()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> createRouteObserve();
&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>}, &lt;span style="color:#cb4b16">false&lt;/span>);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Stream流模式改为建立持久化连接之后,我们也需要把这个 Consumer 的行为存储在本地的缓存池中。Istio 收到来自 dubbo 的推送请求后,刷新自身缓存的资源列表并返回响应。此时 istio 返回的响应内容是聚合后的结果,Dubbo 收到响应后,将响应资源拆分为更小的资源粒度,再推送给对应的 Dubbo应用通知其进行变更。&lt;/p>
&lt;p>踩坑点:&lt;/p>
&lt;ul>
&lt;li>istio推送的数据可能为空字符串,此时缓存池子无需存储,直接跳过即可。否则dubbo会绕过缓冲池,不断向istio发送请求。&lt;/li>
&lt;li>考虑以下场景,dubbo应用同时订阅了两个接口,分别由app1和app2提供。为避免监听之间的相互覆盖,因此向istio发送数据时,需要聚合所有监听的资源名一次性发起。&lt;/li>
&lt;/ul>
&lt;h3 id="42-多点独立监听">4.2 多点独立监听&lt;/h3>
&lt;p>在第一次向istio发送请求时会调用getResource方法先去cache查询,缺失了再聚合数据去istio请求数据,istio再返回相应的结果给dubbo。我们处理istio的响应有两种实现方案:&lt;/p>
&lt;ol>
&lt;li>由用户在getResource方案中new 一个completeFuture,由cache分析是否是需要的数据,若确认是新数据则由该future回调传递结果。&lt;/li>
&lt;li>getResource建立资源的监听器consumerObserveMap,定义一个consumer并把取到的数据同步到原来的线程,cache 收到来自istio的推送后会做两件事:将数据推送所有监听器和将数据发送给该资源的监听器。
以上两种方案都能实现,但最大的区别就是用户调用onNext发送数据给istio的时候需不需要感知getResource 的存在。综上,最终选择方案2进行实现。具体实现逻辑是让dubbo与istio建立连接后,istio会推送自身监听到资源列表给dubbo,dubbo解析响应,并根据监听的不同app切分数据,并刷新本地缓存池的数据,并发送ACK响应给istio,大致流程如下:&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/2023/2/2/5.svg" alt="image.png">&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">class&lt;/span> &lt;span style="color:#268bd2">ResponseObserver&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> XXX {
&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:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">onNext&lt;/span>(DiscoveryResponse value) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//接受来自istio的数据并切分&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, T&lt;span style="color:#719e07">&amp;gt;&lt;/span> newResult &lt;span style="color:#719e07">=&lt;/span> decodeDiscoveryResponse(value);
&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>String, T&lt;span style="color:#719e07">&amp;gt;&lt;/span> oldResource &lt;span style="color:#719e07">=&lt;/span> resourcesMap;
&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> discoveryResponseListener(oldResource, newResult);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resourcesMap &lt;span style="color:#719e07">=&lt;/span> newResult;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// for ACK&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> requestObserver.onNext(buildDiscoveryRequest(Collections.emptySet(), value));
&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> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">discoveryResponseListener&lt;/span>(Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, T&lt;span style="color:#719e07">&amp;gt;&lt;/span> oldResult,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, T&lt;span style="color:#719e07">&amp;gt;&lt;/span> newResult) {
&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>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">//具体实现交由LDS、RDS、EDS自身&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">protected&lt;/span> &lt;span style="color:#268bd2">abstract&lt;/span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">decodeDiscoveryResponse&lt;/span>(DiscoveryResponse response){
&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>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (Map.Entry&lt;span style="color:#719e07">&amp;lt;&lt;/span>Set&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span>, List&lt;span style="color:#719e07">&amp;lt;&lt;/span>Consumer&lt;span style="color:#719e07">&amp;lt;&lt;/span>Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, T&lt;span style="color:#719e07">&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span> entry : consumerObserveMap.entrySet()) {
&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>&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>String, T&lt;span style="color:#719e07">&amp;gt;&lt;/span> dsResultMap &lt;span style="color:#719e07">=&lt;/span> entry.getKey()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .stream()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .collect(Collectors.toMap(k &lt;span style="color:#719e07">-&amp;gt;&lt;/span> k, v &lt;span style="color:#719e07">-&amp;gt;&lt;/span> newResult.get(v)));
&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> entry.getValue().forEach(o &lt;span style="color:#719e07">-&amp;gt;&lt;/span> o.accept(dsResultMap));
&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;/code>&lt;/pre>&lt;/div>&lt;p>踩坑点:&lt;/p>
&lt;ul>
&lt;li>原本多个stream流的情况下,会用递增的requestId来复用stream流,改成持久化连接之后,一种resource会有多个requestid,可能会相互覆盖,因此必须去掉这个机制。&lt;/li>
&lt;li>初始实现方案并没有对资源进行切分,而是一把梭,考虑到后续对其他DS的支持,对istio返回的数据进行切分,也导致consumerObserveMap有点奇形怪状。&lt;/li>
&lt;li>三种DS在发送数据时可以共享同一channel,但监听所用到的必须是同一channel,否则数据变更时istio不会进行推送。&lt;/li>
&lt;li>建立双向stream流之后,初始方案future为全局共享。但可能有这样的场景:相同的ds两次相邻时间的onNext事件,记为A事件和B事件,可能是A事件先发送,B随后;但可能是B事件的结果先返回,不确定istio推送的时间,因此future必须是局部变量而不是全局共享。&lt;/li>
&lt;/ul>
&lt;h3 id="43-采用读写锁避免并发冲突">4.3 采用读写锁避免并发冲突&lt;/h3>
&lt;p>监听器consumerObserveMap和缓存池resourcesMap均可能产生并发冲突。对于resourcemap,由于put操作都集中在getResource方法,因此可以采用悲观锁就能锁住相应的资源,避免资源的并发监听。对于consumerObserveMap,同时存在put、remove和遍历操作,从时序上,采用读写锁可规避冲突,对于遍历操作加读锁,对于put和remove操作加写锁,即可避免并发冲突。综上,resourcesMap加悲观锁即可,consumerObserveMap涉及的操作场景如下:&lt;/p>
&lt;ul>
&lt;li>远程请求istio时候会往consumerObserveMap 新增数据,加写锁。&lt;/li>
&lt;li>CompleteFuture跨线程返回数据后,去掉监听future,加写锁。&lt;/li>
&lt;li>监听缓存池时会往consumerObserveMap新增监听,加写锁。&lt;/li>
&lt;li>断线重连时会往consumerObserveMap新增监听,加写锁。&lt;/li>
&lt;li>解析istio返回的数据,遍历缓存池并刷新数据,加读锁。&lt;/li>
&lt;/ul>
&lt;p>踩坑点:&lt;/p>
&lt;ul>
&lt;li>由于dubbo和istio建立的是是双向stream流,相同的ds两次相邻时间的onNext事件,记为A事件和B事件,可能是A事件先发送,B随后;但可能是B事件的结果先返回,不确定istio推送的时间。因此需要加锁。&lt;/li>
&lt;/ul>
&lt;h3 id="44-断线重连">4.4 断线重连&lt;/h3>
&lt;p>断线重连只需要用定时任务去定时与istio交互,尝试获取授信证书,证书获取成功即可视为istio成功重新上线,dubbo会聚合本地的资源去istio请求数据,并解析响应和刷新本地缓存池数据,最后再关闭定时任务。
踩坑点:&lt;/p>
&lt;ul>
&lt;li>采用全局共享的定时任务池,不能进行关闭,否则会影响其他业务。&lt;/li>
&lt;li>&lt;/li>
&lt;/ul>
&lt;h2 id="五感想与总结">五、感想与总结&lt;/h2>
&lt;p>在这次功能的改造中,笔者着实掉了一波头发,怎么找bug也找不到的情形不在少数。除了上述提到的坑点之外,其他的坑点包括但不局限于:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>dubbo在某一次迭代里更改了获取k8s证书的方式,授权失败。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>原本的功能没问题,merge了下master代码,grpc版本与envoy版本不兼容,各种报错,最后靠降低版本成功解决。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>原本的功能没问题,merge了下master代码,最新分支代码里metadataservice发成了triple,然而在Proxyless模式下只支持dubbo协议,debug了三四天,最后发现需要增加配置。&lt;/p>
&lt;p>&amp;hellip;&amp;hellip;
但不得不承认,Proxyless Service Mesh确实有它自身的优势和广阔的市场前景。自dubbo3.1.0 release版本之后,dubbo已经实现了Proxyless Service Mesh能力,未来dubbo社区将深度联动业务,解决更多实际生产环境中的痛点,更好地完善service mesh能力。&lt;/p>
&lt;/li>
&lt;/ul></description></item><item><title>Blog: Dubbo 3.1.5、3.2.0-beta.4 正式发布</title><link>https://dubbo.apache.org/zh-cn/blog/2023/01/30/dubbo-3.1.53.2.0-beta.4-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</link><pubDate>Mon, 30 Jan 2023 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2023/01/30/dubbo-3.1.53.2.0-beta.4-%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</guid><description>
&lt;p>Dubbo 3.1.5 版本是目前 Dubbo 3 的最新稳定版本,我们建议所有的用户都升级到最新的稳定版本。Dubbo 3.2.0-beta.4 版本是目前 Dubbo 3 的最新特性版本,包括了如 Spring Boot 3、JDK 17、服务粒度的线程池隔离等新特性的支持,欢迎大家尝鲜使用。&lt;/p>
&lt;h1 id="dubbo-315">Dubbo 3.1.5&lt;/h1>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/3-1-5.png" alt="image.png">&lt;/p>
&lt;h3 id="新特性">新特性&lt;/h3>
&lt;ul>
&lt;li>Dubbo QoS 支持记录请求的记录,便于进行审计&lt;/li>
&lt;li>支持在服务映射失败以后定时进行重试,降低由于元数据中心抖动带来的影响&lt;/li>
&lt;li>支持在初始化 Nacos Client 的时候进行健康检查,如果失败则在一定次数限制下进行重试,降低由于 Nacos 性能问题带来的稳定性影响&lt;/li>
&lt;li>支持序列化类检查机制,默认开启日志告警模式&lt;/li>
&lt;/ul>
&lt;h3 id="bugfix">Bugfix&lt;/h3>
&lt;ul>
&lt;li>修复资源加载器的日志级别&lt;/li>
&lt;li>修复 Dubbo 配置类对 Scope Model 进行懒加载,避免触发非预期的默认模块初始化&lt;/li>
&lt;li>修复 ReferenceConfig 中获取 ClassLoader 的逻辑&lt;/li>
&lt;li>修复 Metadata Service 在获取订阅服务列表时出现 NPE 的问题&lt;/li>
&lt;li>修复对接 Spring Cloud Rest 模式的时候 Metadata 配置覆盖的问题&lt;/li>
&lt;li>修复 Spring 懒加载时可能出现死锁的问题&lt;/li>
&lt;li>修复端口重复的无效日志&lt;/li>
&lt;li>修复 Active Limit Filter 不生效的问题&lt;/li>
&lt;li>修复服务映射时 Nacos CAS 检查写入无效的问题&lt;/li>
&lt;li>修复 Zookeeper 注册中心对接的应用级服务发现在服务发布的时候出现单节点服务找不到的问题&lt;/li>
&lt;li>修复服务映射在冲突以后未等待导致的冲突率高的问题&lt;/li>
&lt;li>修复应用级服务发现下节点更新失败的问题&lt;/li>
&lt;li>修复应用级配置覆盖不生效的问题&lt;/li>
&lt;li>修复在应用级地址刷新之后原 Revision 的元数据无法获取的问题&lt;/li>
&lt;li>修复 Zookeeper 注册中心在应用级服务发现下退订阅后无法重订阅的问题&lt;/li>
&lt;li>兼容 Nacos 在频繁刷新时最终一致性错误的问题&lt;/li>
&lt;li>关闭 Nacos 本地缓存获取的开关&lt;/li>
&lt;li>修复 Triple 传递大写 Attachment 无效的问题&lt;/li>
&lt;li>修复 Triple 处理特定类反序列化错误的问题&lt;/li>
&lt;li>修复 Protobuf 依赖不存在时抛出非预期异常的问题&lt;/li>
&lt;li>修复 CountDown 功能无效的问题&lt;/li>
&lt;li>修复 Triple 在反序列化时类加载器未切换的问题&lt;/li>
&lt;/ul>
&lt;h3 id="faq">FAQ&lt;/h3>
&lt;p>本次发布中有 5 个提交涉及异常日志 FAQ 的完善。关于错误码机制请参考官网&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/faq/intro/">错误码机制介绍&lt;/a>一文。&lt;/p>
&lt;h3 id="代码优化">代码优化&lt;/h3>
&lt;p>本次发布中有 4 个提交涉及代码质量的优化。&lt;/p>
&lt;h3 id="依赖升级">依赖升级&lt;/h3>
&lt;ul>
&lt;li>升级 protobuf-java: 3.16.3 -&amp;gt; 3.18.3&lt;/li>
&lt;li>升级 fastjson2: 2.0.21 -&amp;gt; 2.0.23&lt;/li>
&lt;/ul>
&lt;h3 id="贡献者">贡献者&lt;/h3>
&lt;p>Dubbo 感谢以下贡献者对本次发布的贡献:@win120a, @wuwen5, @AlbumenJ, @CrazyHZM, @EarthChen, @xieshouyu, @wxbty&lt;/p>
&lt;h3 id="新贡献者">新贡献者&lt;/h3>
&lt;ul>
&lt;li>@xieshouyu 在 PR #11177 提交了第一个贡献&lt;/li>
&lt;/ul>
&lt;h1 id="dubbo-320-beta4">Dubbo 3.2.0-beta.4&lt;/h1>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/3-2-0-beta-4.png" alt="image.png">&lt;/p>
&lt;p>&lt;strong>注:Dubbo 3.2.0-beta.4 的代码基础和 Dubbo 3.1.5 完全一致,因此在 Dubbo 3.1.5 中包括的所有修改内容,在 Dubbo 3.2.0-beta.4 中也同样存在,后续说明中对于重复的内容讲不再赘述。&lt;/strong>&lt;/p>
&lt;h3 id="新特性-1">新特性&lt;/h3>
&lt;ul>
&lt;li>支持 bytebuddy 作为动态代理的生成平台&lt;/li>
&lt;li>支持采集超时指标进行上报&lt;/li>
&lt;li>完善 Metrics 上报应用名&lt;/li>
&lt;li>完善 Metrics 上报指标的前缀&lt;/li>
&lt;li>支持上报请求失败的指标&lt;/li>
&lt;li>完善 xDS 的监听逻辑&lt;/li>
&lt;li>完善 xDS 对接路由规则的能力&lt;/li>
&lt;/ul>
&lt;h3 id="bugfix-1">Bugfix&lt;/h3>
&lt;ul>
&lt;li>修复 Token 请求在 Rest 协议下不生效的问题&lt;/li>
&lt;li>修复 GraalVM Native Image 的配置&lt;/li>
&lt;li>修复配置类无法进行序列化的问题&lt;/li>
&lt;li>修复 IPv6 地址段检查无效的问题&lt;/li>
&lt;li>修复路由链切换时地址可能存在异常的情况&lt;/li>
&lt;li>修复缓存文件锁被异常删除的问题&lt;/li>
&lt;li>修复 Deployer Listener 并发修改的问题&lt;/li>
&lt;/ul>
&lt;h3 id="性能优化">性能优化&lt;/h3>
&lt;ul>
&lt;li>优化 ConcurrentHashMap 的使用方式,避免在 JDK 1.8 下出现性能衰减&lt;/li>
&lt;/ul>
&lt;h3 id="代码优化-1">代码优化&lt;/h3>
&lt;p>本次发布中有 8 个提交涉及代码质量的优化。&lt;/p>
&lt;h3 id="依赖升级-1">依赖升级&lt;/h3>
&lt;ul>
&lt;li>升级 protobuf-java: 3.18.3 -&amp;gt; 3.19.6&lt;/li>
&lt;li>升级 cglib-nodep: 2.2 -&amp;gt; 2.2.2&lt;/li>
&lt;li>升级 byte-buddy: 1.12.19 -&amp;gt; 1.12.22&lt;/li>
&lt;li>升级 bouncycastle-bcprov_version: 1.69 -&amp;gt; 1.70&lt;/li>
&lt;li>升级 javax.ws.rs-api: 2.0 -&amp;gt; 2.1.1&lt;/li>
&lt;li>升级 curator_version: 4.2.0 -&amp;gt; 4.3.0&lt;/li>
&lt;li>升级 maven-plugin-plugin: 3.6.0 -&amp;gt; 3.7.1&lt;/li>
&lt;li>升级 javax.el: 3.0.1-b08 -&amp;gt; 3.0.1-b12&lt;/li>
&lt;li>升级 slf4j-api: 1.7.25 -&amp;gt; 1.7.36&lt;/li>
&lt;li>升级 spring-boot-dependencies: 2.3.1.RELEASE -&amp;gt; 2.7.7&lt;/li>
&lt;li>升级 maven-enforcer-plugin: 3.0.0-M3 -&amp;gt; 3.1.0&lt;/li>
&lt;li>升级 javassist: 3.28.0-GA -&amp;gt; 3.29.2-GA&lt;/li>
&lt;li>升级 spring-boot-maven-plugin: 2.1.4.RELEASE -&amp;gt; 2.7.7&lt;/li>
&lt;li>升级 javax.el-api: 2.2.4 -&amp;gt; 2.2.5&lt;/li>
&lt;li>升级 eureka.version: 1.9.12 -&amp;gt; 1.10.18&lt;/li>
&lt;li>升级 jetty-maven-plugin: 9.4.38.v20210224 -&amp;gt; 9.4.50.v20221201&lt;/li>
&lt;li>升级 jetty_version: 9.4.43.v20210629 -&amp;gt; 9.4.50.v20221201&lt;/li>
&lt;li>升级 resteasy_version: 3.0.20.Final -&amp;gt; 3.15.3.Final&lt;/li>
&lt;/ul>
&lt;h3 id="贡献者-1">贡献者&lt;/h3>
&lt;p>Dubbo 感谢以下贡献者对本次发布的贡献:@aamingaa, @AlbumenJ, @CrazyHZM, @fomeiherz, @HHoflittlefish777, @icodening, @jojocodeX, @LXPWing, @MentosL, @mxsm, @schneiderlin, @sconvent, @ShenFeng312, @songxiaosheng, @TigerTurbo, @yuluo-yx, @zeusbee&lt;/p>
&lt;h3 id="新贡献者-1">新贡献者&lt;/h3>
&lt;ul>
&lt;li>@LXPWing 在 PR #11258 提交了第一个贡献&lt;/li>
&lt;li>@HHoflittlefish777 在 PR #11266 提交了第一个贡献&lt;/li>
&lt;li>@sconvent 在 PR #11260 提交了第一个贡献&lt;/li>
&lt;li>@yuluo-yx 在 PR #11291 提交了第一个贡献&lt;/li>
&lt;li>@fomeiherz 在 PR #11295 提交了第一个贡献&lt;/li>
&lt;li>@schneiderlin 在 PR #11324 提交了第一个贡献&lt;/li>
&lt;li>@mxsm 在 PR #11326 提交了第一个贡献&lt;/li>
&lt;/ul>
&lt;h1 id="未来版本规划">未来版本规划&lt;/h1>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/release/release-roadmap.png" alt="image.png">&lt;/p>
&lt;p>Dubbo 版本的发布规划以及在《&lt;a href="https://mp.weixin.qq.com/s?__biz=MzIwODYwNTA4MA==&amp;amp;mid=2247484424&amp;amp;idx=1&amp;amp;sn=2f5ff4846f7dafad325f78fd8cf4d1fc&amp;amp;chksm=9701deffa07657e9a46eb97bb859770b4856599566b992724013a848a730f394702938e72404&amp;amp;token=1547029975&amp;amp;lang=zh_CN#rd">聚焦稳定性,Dubbo 发版规划公布&lt;/a>》一文中正式发布,欢迎查看。&lt;/p></description></item><item><title>Blog: Dubbo Java 3.0.2.1 发版公告</title><link>https://dubbo.apache.org/zh-cn/blog/2021/08/23/dubbo-java-3.0.2.1-%E5%8F%91%E7%89%88%E5%85%AC%E5%91%8A/</link><pubDate>Mon, 23 Aug 2021 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2021/08/23/dubbo-java-3.0.2.1-%E5%8F%91%E7%89%88%E5%85%AC%E5%91%8A/</guid><description>
&lt;p>这是 3.0.2 的错误修正版本。
除了以下更改外,与版本 3.0.2 完全相同。&lt;/p>
&lt;h2 id="bug-修复">Bug 修复&lt;/h2>
&lt;ul>
&lt;li>修复 nacos group 在消费者端不生效的问题 (#8533)&lt;/li>
&lt;li>修复请求超时时序列化检查的 NPE (#8547)&lt;/li>
&lt;li>兼容使用 dubbo-all 时未导入 farbic-io 包的问题 (#8546)&lt;/li>
&lt;/ul></description></item><item><title>Blog: Dubbo Java 3.0.1 发版公告</title><link>https://dubbo.apache.org/zh-cn/blog/2021/07/02/dubbo-java-3.0.1-%E5%8F%91%E7%89%88%E5%85%AC%E5%91%8A/</link><pubDate>Fri, 02 Jul 2021 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2021/07/02/dubbo-java-3.0.1-%E5%8F%91%E7%89%88%E5%85%AC%E5%91%8A/</guid><description>
&lt;h2 id="优化">优化&lt;/h2>
&lt;ul>
&lt;li>重构服务自省映射关系,支持地址迁移时直接配置上游应用名&lt;/li>
&lt;li>为 Spring 扫描添加缓存&lt;/li>
&lt;li>优化配置覆盖逻辑&lt;/li>
&lt;li>支持 Servlet 环境下控制 Dubbo 生命周期&lt;/li>
&lt;li>添加 ServiceListener 用于监听 ServiceConfig&lt;/li>
&lt;li>优化方法回调参数设置&lt;/li>
&lt;/ul>
&lt;h2 id="bug-修复">Bug 修复&lt;/h2>
&lt;ul>
&lt;li>启用强制校验&lt;/li>
&lt;li>更正多注册中心情况下,一个注册中心启动时无地址就销毁的逻辑&lt;/li>
&lt;li>移除冗余的日志输出&lt;/li>
&lt;li>忽略无效的 MetadataReportConfig&lt;/li>
&lt;li>修复消费端启动时 NPE 的情况&lt;/li>
&lt;li>修复若干和低版本兼容问题&lt;/li>
&lt;li>修复若干应用级服务发现逻辑存在的问题&lt;/li>
&lt;li>优化地址迁移规则,支持应用级地址重订阅&lt;/li>
&lt;li>修复 MetadataInfo 存在 NPE 的情况&lt;/li>
&lt;li>修复应用级注册到注册中心的实例信息被错误覆盖的问题&lt;/li>
&lt;/ul>
&lt;h2 id="代码质量提升">代码质量提升&lt;/h2>
&lt;p>感谢以下提高 Apache Dubbo 的稳定性的贡献。&lt;/p>
&lt;p>&lt;a href="https://github.com/apache/dubbo/pull/8043">#8043&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8044">#8044&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8048">#8048&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8071">#8071&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8119">#8119&lt;/a>,
&lt;a href="https://github.com/apache/dubbo/pull/8132">#8132&lt;/a>&lt;/p></description></item><item><title>Blog: Dubbo Go 1.5.0</title><link>https://dubbo.apache.org/zh-cn/blog/2021/01/14/dubbo-go-1.5.0/</link><pubDate>Thu, 14 Jan 2021 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2021/01/14/dubbo-go-1.5.0/</guid><description>
&lt;h2 id="引语">引语&lt;/h2>
&lt;p>计算机技术浪潮每 10 年都有一次技术颠覆,相关知识体系最迟每 5 年都会革新一次,大概每两年贬值一半,在应用服务通信框架领域亦然。凡是有长期生命的通信框架,大概有 5 年的成长期和 5 年的稳定成熟期。每个时代都有其匹配的应用通信框架,在 20 年前的 2G 时代,强跨语言跨平台而弱性能的 gRPC 是不会被采用的。&lt;/p>
&lt;p>每个通信框架,不同的人从不同角度看出不同的结论:初学者看重易用易学,性能测评者注重性能,应用架构师考虑其维护成本,老板则考虑则综合成本。一个应用通信框架的性能固然重要,其稳定性和进化能力更重要,得到有效维护的框架可在长时间单位内降低其综合成本:学习成本、维护成本、升级成本和更换成本。&lt;/p>
&lt;p>什么是 Dubbo-go?第一,它是 Dubbo 的 Go 语言版本,全面兼容 Dubbo 是其第一要义。第二,它是一个 Go 语言应用通信框架,会充分利用作为云原生时代第一语言&amp;mdash;Go 语言的优势,扩展 dubbo 的能力。&lt;/p>
&lt;p>2008 年诞生的 Dubbo 已有十多年历史,依靠阿里和其社区,历久弥新。2016 年发布的 Dubbo-go 也已进入第五个年头,如今全面兼容 Dubbo v2.7.x 的 Dubbo-go v1.5 终于发布了。&lt;/p>
&lt;p>回首过往,Dubbo-go 已经具备如下能力:&lt;/p>
&lt;ul>
&lt;li>互联互通:打通了 gRPC 和 Spring Cloud 生态;&lt;/li>
&lt;li>可观测性:基于 OpenTracing 和 Prometheus,使得其在 Logging、Tracing 和 Metrics 方面有了长足进步;&lt;/li>
&lt;li>云原生:Dubbo-go 实现了基于 Kubernetes API Server 为注册中心的通信能力,做到了升级成本最低。&lt;/li>
&lt;/ul>
&lt;p>毋庸讳言,相较于现有成绩,发展阶段的 Dubbo-go 对未来有更多的期待之处:&lt;/p>
&lt;ul>
&lt;li>易用性:Dubbo-go 的入门成本并不低,把很多感兴趣者挡在了门外。但好消息是,随着 Dubbo-go 在阿里内部的逐步推开,阿里中间件团队对其进行了进一步的封装,经生产环境检验后会开放给社区使用。&lt;/li>
&lt;li>云原生:目前的 Dubbo-go 的基于 kubernetes 的方案,从技术分层角度来看, Kubernetes API Server 终究是系统的运维态组件,不应该暴露给应用层,否则会造成 APIServer 自身通信压力过大,且系统整体风险很高:应用层使用不当,或者框架自身的流量方面的 bug,可能会把 APIServer 打垮,后果就是造成整体后端服务能力的瘫痪!所以应用层需要感知的是 kubernetes 提供给应用层的 Operator,不断进化的 Dubbo-go 计划在 v1.6 版本中发布 Dubbo-go Operator。&lt;/li>
&lt;/ul>
&lt;p>雄关漫道真如铁,而今迈步从头越。Dubbo-go 社区【钉钉群 23331795】与 Dubbo-go 同在。&lt;/p>
&lt;h2 id="应用维度注册模型">应用维度注册模型&lt;/h2>
&lt;p>经过一段时间的努力之后,我们终于完成了应用维度的服务注册与发现。和原本已有的接口维度的注册模型比起来,新的注册模型有两个突出特点:&lt;/p>
&lt;ol>
&lt;li>和主流的注册模型保持一致。目前的主流做法都是按照应用为基本单位来进行注册的,如Spring Cloud。在支持应用维度注册之后,对于接下来的云原生支持,奠定了基础;&lt;/li>
&lt;li>大幅度减轻对注册中心的压力。在该模型之下,从注册中心的视角看过去,集群规模只和实例数量成正比,而不是现有的和服务数量成正比;&lt;/li>
&lt;/ol>
&lt;p>当然,我们在设计的时候就考虑到了用户的迁移成本。要迁移到新的注册模型,只需要将现有使用的注册中心换成新的 &lt;code>ServiceDiscoveryRegistry&lt;/code> 就可以。&lt;/p>
&lt;p>&lt;code>ServiceDiscoveryRegistry&lt;/code> 是支持多种实现的。目前来说,我们支持:&lt;/p>
&lt;ol>
&lt;li>nacos;&lt;/li>
&lt;li>etcd;&lt;/li>
&lt;li>zookeeper;&lt;/li>
&lt;/ol>
&lt;p>我们提倡新上线的业务尽量使用 nacos 和 etcd 这种更可靠稳定的注册中心。&lt;/p>
&lt;h2 id="metadata-report-元数据中心">Metadata Report 元数据中心&lt;/h2>
&lt;p>v1.5 版本在支持应用维度注册模型时,有很重要的一个问题需要解决,即接口维度的元数据存储。服务维度的注册模型和应用维度的注册模型,本质的区别是往注册中心注册的数据维度的不一致。虽然我们在应用维度注册模型中,将接口维度的数据从注册中心中剔除了,但是在rpc的框架中,一个 consumer 要想真正找到想要调用的服务地址,就必须得到 provider 端开放的服务信息。这部分数据,在 v1.5 版本中,我们将它们存储到了元数据中心中。&lt;/p>
&lt;p>元数据中心,是一个接口定义。泛指一块存储区域,可以对接口级别的元数据进行存储、读取,provider 端调用存储,consumer 端调用读取。元数据中心中的数据需要保持准确性、实时性。&lt;/p>
&lt;p>目前元数据中心,有两个父类(Go 中没有继承,此处说的父子类,单纯指子类对父类的组合关系)实现,一个是 local 实现,一个是 remote 实现。local 实现是将 provider 的内存作为虚拟元数据中心,remote 实现是指依赖 ZooKeeper、etcd、nacos 等注册中心作为元数据中心。目前 remote 有 zookeeper、nacos、etcd 和 consul 的子类实现。即用户可以将元数据信息,通过以上的第三方注册中心进行数据存储和分发。&lt;/p>
&lt;h2 id="invocation-接口支持-attribute-属性">Invocation 接口支持 attribute 属性&lt;/h2>
&lt;p>invocation 结构中新增 attribute 属性支持,用于流程内部的属性存储。和 attachment 不同点在于,attachment会从 consumer 传递到 provider,但 attribute 属性不会。&lt;/p>
&lt;h2 id="k8s注册中心">k8s注册中心&lt;/h2>
&lt;p>在 v1.5 版本之前,k8s 注册中心的实现是通过直接使用 &lt;a href="https://github.com/kubernetes/client-go">k8s client&lt;/a> 中Pod对象的 List&amp;amp;&amp;amp;Watch 接口。在本次迭代中引入了 k8s informer。这样做的原因在于两点,首先一定的程度上来讲 dubbo-go 的 k8s 注册中心也是一个 k8s controller,使用 informer 的模式更加 k8s native。更重要的是社区计划后续向 CRD+Operator 的模式演进,informer 模式是对后续的演进的探索。除了这个铺垫之外,本次迭代还对跨 namespace 的服务发现做了支持。再有就是为了减少对 kube-apiserver List&amp;amp;&amp;amp;Watch 的压力,对 provider 和 consumer 的行为进行了区分,provider 不再进行 Watch 而仅对 kube-apiserver 进行写操作。&lt;/p>
&lt;h1 id="优化路由模型">优化路由模型&lt;/h1>
&lt;p>在 1.5 版本之前,Router 模型中属性是包含:优先级与路由属性,Router Chain 只包含路由属性。从中能识别出其实 Router Chain 也是一种特殊 Router。1.5 版本之后,使 Router 更抽象,分离出其优先级属性,新增 Priority Router、Chain 继承 Router 使其变为特殊的 Router,使关系上看起来更加清晰。如下图:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/1.5/router.png" alt="img">&lt;/p>
&lt;h1 id="回顾与展望">回顾与展望&lt;/h1>
&lt;p>Dubbo-go 处于一个比较稳定成熟的状态。目前新版本正处于往云原生方向的尝试,应用服务维度注册是首先推出的功能,这是一个和之前模型完全不一样的新注册模型。该版本是我们朝云原生迈进新一步的关键版本。除此之外,包含在该版本也有一些之前提到的优化。&lt;/p>
&lt;p>下一个版本 v1.5.1,虽然仍是以兼容 Dubbo 2.7.x 为主要任务,但在分布式能力的增强上,也是我们关注的重点。&lt;/p>
&lt;p>在&lt;strong>分布式事务&lt;/strong>方面,有一个重要的基于 Seata 扩展实现。通过增加过滤器,在服务端接收 xid 并结合 seata-golang&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> 达到支持分布式事务的目的。 从而使 Dubbo-go 在分布式场景下,让用户有更多的选择,能适应更多的个性化场景。&lt;/p>
&lt;p>与此同时,在&lt;strong>传输链路安全性&lt;/strong>上,TLS 安全传输链路是该版本重要功能之一。通过提供统一入口,未来能引入更多的与传输链路安全性相关的功能,适应用户不一样的使用场景。&lt;/p>
&lt;p>&lt;strong>注册中心模型&lt;/strong>上,支持多注册中心集群负载均衡。业务部署假设是双注册中心(图 1 ),从原来双注册中心中所有 Provider 一起选址。优化成选址时的多了一层注册中心集群间的负载均衡(图 2 )。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/1.5/multi-registry.png" alt="img">&lt;/p>
&lt;p>(图 1 )&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/1.5/loadbalance.png" alt="img">&lt;/p>
&lt;p>(图 2 )&lt;/p>
&lt;p>以前的 dubbo-go RPC 层直接复用了 getty 框架 的 RPC[&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>(https://github.com/AlexStocks/getty/tree/feature/rpc)],未能实现协议和应用通信地址的隔离。阿里中间件展图同学重构了 dubbo-go RPC 层,实现了连接复用:可以实现 consumer 与 provider 端的同一个 TCP 连接上进行多协议通信。相关 PR 业已合并,会在 dubbo-go v1.5.1 中发布。&lt;/p>
&lt;p>目前下一个版本正在紧锣密鼓的开发中,具体规划及任务清单&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> ,都已经在 Github 上体现。&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://github.com/seata-golang/seata-golang">https://github.com/seata-golang/seata-golang&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://github.com/AlexStocks/getty/tree/feature/rpc">https://github.com/AlexStocks/getty/tree/feature/rpc&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://github.com/apache/dubbo-go/projects/8">https://github.com/apache/dubbo-go/projects/8&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Blog: Dubbo Go Hessian2 v1.6.0</title><link>https://dubbo.apache.org/zh-cn/blog/2021/01/14/dubbo-go-hessian2-v1.6.0/</link><pubDate>Thu, 14 Jan 2021 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2021/01/14/dubbo-go-hessian2-v1.6.0/</guid><description>
&lt;h2 id="1-增加缓存优化">1. 增加缓存优化&lt;/h2>
&lt;p>dubbo-go-hessian2 在解析数据的数据大量使用到了 struct 的结构信息,这部分信息可以缓存起来反复利用,使得性能提升了一倍。优化过程记录可以详细阅读&lt;a href="https://mp.weixin.qq.com/s/ouVxldQAt0_4BET7srjJ6Q">《记一次对 dubbo-go-hessian2 的性能优化》&lt;/a>.&lt;/p>
&lt;p>对应 pr &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/179">#179&lt;/a>,作者 &lt;a href="https://github.com/micln">micln&lt;/a>。&lt;/p>
&lt;h2 id="2-string-解析性能优化">2. string 解析性能优化&lt;/h2>
&lt;p>由于 hessian ( dubbo 序列化协议,下称:hessian )对 string 的定义是16 bit 的 unicode 的 UTF-8 表示形式,字符长度表示是16 bit 的字符数。这是仅针对 java 制定的规范,java 中一个字符是16 bit,对应到 UTF-16. hessian 库也是对每一个字符进行转码序列化。但 golang 里面字符是和 UTF-8 对应的,dubbo-go-hessian2 里面的 rune 是 32bit,和 unicode一一映射。对于 U+10000 ~ U+10FFFF 的字符,需按照 UTF16 的规范,将字符转换为 2 个字节的代理字符,再做转换,才能和 java 的序列化方式对应起来。&lt;/p>
&lt;p>原来不管是编码还是解析都是一个字符一个字符处理,特别是解析的时候,从流里面一个字节一个字节读取并组装成 rune,然后再转换为 string,这样效率特别低。我们的优化方案是,批次读取字节流到 buffer 中,对 buffer 进行解析转为 UTF-8 数组,并统计字符数量。其中需要对代理对字符将其转换为标准 UTF-8 子节数组。如果统计的字符数量不足,再进一步读取流种的数据进行解析。通过此方式提升一倍的解析效率。&lt;/p>
&lt;p>对应 pr &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/188">#188&lt;/a>,作者 &lt;a href="https://github.com/zonghaishang">zonghaishang&lt;/a>。&lt;/p>
&lt;h2 id="3-解析忽略不存在的字段">3. 解析忽略不存在的字段&lt;/h2>
&lt;p>hessian 库在解析数据的时候,对于一个 class 字段,如果不存在,则直接忽略掉。但 v1.6.0 版本之前 dubbo-go-hessian2 解析数据,如果遇到不存在的字段,会返回 error。从 v1.6.0 开始,与 hessian 一样,忽略不存在的字段。&lt;strong>因为这是一个特性的变更,所以升级的同学一定要注意了。&lt;/strong>&lt;/p>
&lt;p>对应 pr &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/201">#201&lt;/a>,作者 &lt;a href="https://github.com/micln">micln&lt;/a> &amp;amp; &lt;a href="https://github.com/fangyincheng">fangyincheng&lt;/a>。&lt;/p>
&lt;h2 id="4-解决浮点数精度丢失问题">4. 解决浮点数精度丢失问题&lt;/h2>
&lt;p>在对 float32 类型进行序列化时,我们一律强制转换为 float64 再进行序列化操作。由于浮点数的精度问题,在这个转换过程中可能出现小数点后出现多余的尾数,例如 (float32)99.8&amp;ndash;&amp;gt;(float64)99.80000305175781。&lt;/p>
&lt;p>1.6.0 版本对 float32 的序列化进行了优化:&lt;/p>
&lt;ul>
&lt;li>如果小数尾数小于 3 位,根据 hessian2 协议序列化为 double 32-bit 格式&lt;/li>
&lt;li>否则先转换为 string 类型,再转换为 float64 类型,这样做可以避免由于浮点数精度问题产生多余的尾数,最后对 float64 进行序列化。&lt;/li>
&lt;/ul>
&lt;p>虽然对 float32 类型进行了优化,但是依然建议使用浮点数的时候优先使用 float64 类型。&lt;/p>
&lt;p>对应 pr &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/196">#196&lt;/a>,作者 &lt;a href="https://github.com/willson-chen">willson-chen&lt;/a>。&lt;/p>
&lt;h2 id="5-解决-attachment-空值丢失问题">5. 解决 attachment 空值丢失问题&lt;/h2>
&lt;p>dubbo 请求中包含 attachment 信息,之前如果 attachment 里面含有如 &lt;code>&amp;quot;key1&amp;quot;:&amp;quot;&amp;quot;&lt;/code>,这种 value 为空的情况,解析出来的结果会直接丢失这个属性 key1 ,v1.6.0 修复了此问题,现在解析出来的 attachment 会正确解析出空 value 的属性。&lt;/p>
&lt;p>对应 pr &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/191">#191&lt;/a>,作者 &lt;a href="https://github.com/champly">champly&lt;/a>。&lt;/p>
&lt;h2 id="6-支持-继承-和忽略冗余字段">6. 支持 ‘继承’ 和忽略冗余字段&lt;/h2>
&lt;p>由于 go 没有继承的概念,所以在之前的版本,Java 父类的字段不被 dubbo-go-hessian2 所支持。新版本中,dubbo-go-hessian2 将Java来自父类的字段用匿名结构体对应,如:&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">type&lt;/span> Dog &lt;span style="color:#268bd2">struct&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Animal
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Gender &lt;span style="color:#dc322f">string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DogName &lt;span style="color:#dc322f">string&lt;/span> &lt;span style="color:#2aa198">`hessian:&amp;#34;-&amp;#34;`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>同时,就像 json 编码中通过 immediately 可以在序列化中忽略该字段,同理,通过 hessian:&amp;quot;-&amp;quot; 用户也可以让冗余字段不参与 hessian 序列化。&lt;/p>
&lt;p>对应pr &lt;a href="https://github.com/apache/dubbo-go-hessian2/pull/154">#154&lt;/a>,作者 &lt;a href="https://github.com/micln">micln&lt;/a>&lt;/p></description></item><item><title>Blog: 都已经十岁的 Apache Dubbo,还能再乘风破浪吗?</title><link>https://dubbo.apache.org/zh-cn/blog/2021/01/14/%E9%83%BD%E5%B7%B2%E7%BB%8F%E5%8D%81%E5%B2%81%E7%9A%84-apache-dubbo%E8%BF%98%E8%83%BD%E5%86%8D%E4%B9%98%E9%A3%8E%E7%A0%B4%E6%B5%AA%E5%90%97/</link><pubDate>Thu, 14 Jan 2021 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2021/01/14/%E9%83%BD%E5%B7%B2%E7%BB%8F%E5%8D%81%E5%B2%81%E7%9A%84-apache-dubbo%E8%BF%98%E8%83%BD%E5%86%8D%E4%B9%98%E9%A3%8E%E7%A0%B4%E6%B5%AA%E5%90%97/</guid><description>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/10years/dubbo-home.png" alt="img">&lt;/p>
&lt;p>纵观中国开源历史,你真的没法找到第二个像 Dubbo 一样自带争议和讨论热度的开源项目。&lt;/p>
&lt;p>一方面,2011 年,它的开源填补了当时生产环境使用的 RPC 框架的空白,一发布就被广泛采用;另一方面,它经历了停止维护、重启维护后捐献给 Apache 基金会、接着又以顶级项目的身份毕业。&lt;/p>
&lt;p>面对多疑的开发者,在云原生时代,Apache Dubbo 将如何延续当前光芒?&lt;/p>
&lt;p>今年是 Dubbo 从 Apache 基金会毕业的一周年,同时也是推进 Dubbo 3.0,即全面拥抱云原生的重要一年。开源中国与 Apaceh Dubbo 共同策划**【Dubbo 云原生之路】**系列文章,和大家一起回顾 Apache Dubbo 社区的发展。系列文章主要涵盖 Dubbo 技术解读、社区、应用案例解析三大部分,之后每周都会和大家见面。&lt;/p>
&lt;p>&lt;strong>在【阿里巴巴云原生公众号】留言说出与 Apache Dubbo 的故事&lt;/strong>,点赞排名前十的同学可领取 Dubbo 送出的专属奖品杯子一只;另外由Apache Dubbo PMC @Chickenlj 随机抽取一名幸运读者,赠送价值 260 元护眼灯一台。下周三开奖。&lt;/p>
&lt;p>&lt;strong>作者简介&lt;/strong>&lt;/p>
&lt;p>&lt;strong>刘军&lt;/strong>,花名陆龟,GitHub 账号 Chickenlj,Apache Dubbo PMC,项目核心开发,见证了 Dubbo 重启开源,到从 Apache 基金会毕业的整个过程。现任职阿里云云原生应用平台团队,参与服务框架、微服务相关工作,目前主要在推动 Dubbo 3.0 - Dubbo 云原生。&lt;/p>
&lt;h1 id="系列开篇30-全面铺开asf-毕业一周年">系列开篇:3.0 全面铺开、ASF 毕业一周年&lt;/h1>
&lt;p>从 2019 年到现在,在 Dubbo 毕业的这一年时间里,Dubbo 社区和产品都取得长足进步,同时 Dubbo 云原生版本 - Dubbo 3.0 的开发工作也已经全面铺开。&lt;/p>
&lt;p>社区方面。需要重点提及的有两点:一个是落地与贡献的企业用户进一步增加,主动与社区取得联系的中、大规模公司达 200 多家,如携程、工商银行、瓜子二手车、网联清算、中通等;另一个是&lt;a href="http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&amp;amp;mid=2650091639&amp;amp;idx=1&amp;amp;sn=9733d57fd9babe53826bc93c2a466adf&amp;amp;chksm=bedaeb1989ad620f99abfee5902d69dc6c7544d1d70803d854f20ea7a1a44c1d0c4ba82f8d3a&amp;amp;scene=21#wechat_redirect">&lt;strong>以 Dubbo-go 为代表的子社区&lt;/strong>&lt;/a>蓬勃发展。&lt;/p>
&lt;p>产品技术演进方面。Dubbo Java 版发布 10 个版本,在多语言、协议、性能、服务治理模型等方面都有深度探索。Dubbo go 发布超过 8 个版本,在功能基本对齐 Java 版本的基础上,一些方向上也已经走在了 Java 版本前面。&lt;/p>
&lt;p>值得一提的是,阿里巴巴内部也正在积极推动 Dubbo 社区版本在内部的落地,从今年开始逐步实现&lt;strong>以 Dubbo 替换其内部的 HSF 框架&lt;/strong>。这一方面有利于阿里将其在 HSF 上的丰富服务治理经验回馈输出到社区,另一方面阿里官方的落地也将直接加速 Dubbo 云原生的发展。&lt;/p>
&lt;p>在云原生大潮下,&lt;strong>3.0 已被正式列为今年 Dubbo 产品建设的核心目标&lt;/strong>,涉及下一代 RPC 协议、服务治理模型、云原生基础设施适配等多方面的内容。其中,很多方面已经在当前的 2.7 版本中做了前置性探索,如近期发布的基于 HTTP/2 的协议支持、应用级服务发现等,后续工作将以此为基础展开。系列文章也会有对 Dubbo 3.0 Roadmap 及技术方案的详细解析。&lt;/p>
&lt;h2 id="dubbo-毕业一周年回顾">Dubbo 毕业一周年回顾&lt;/h2>
&lt;p>2017 年 7 月,Dubbo 开源项目被重新激活,2018 年捐献到 Apache 基金会,2019 年 5 月,Dubbo 正式从 Apache 基金会孵化毕业,成为 Apache 顶级项目。接下来,文章分别从社区、子社区、产品三方面介绍 Dubbo 过去一年的成绩。&lt;/p>
&lt;h3 id="社区一年发布-24-个版本贡献者已超-300">社区一年发布 24 个版本,贡献者已超 300&lt;/h3>
&lt;p>如果说最开始重新激活是以阿里巴巴为主导的项目维护投入,那自 Dubbo 加入 Apache 起,它就已经开始成为一个社区主导、社区贡献为主的完全开放的基金会项目。&lt;/p>
&lt;p>到今天,这一趋势正变得更明显。包括阿里巴巴、携程、工商银行、瓜子二手车、网联清算、中通等在内的互联网、传统企业公司,在 Dubbo 的使用与社区代码贡献上都有投入。Dubbo 社区正变得非常活跃和多样化。&lt;/p>
&lt;p>过去一年,Dubbo 社区项目总共发布 24 个版本,发展 Committer/PMC 27 人,其中有 20% 的贡献者是来自于阿里巴巴,80% 以上来自不同组织的开发者或爱好者。&lt;/p>
&lt;p>Dubbo 社区组织了超过 10 场线下 meetup 活动,基本覆盖了国内开发者聚集的城市。通过线下或线上直播活动,分享超过 100 个 topic 的演讲,深度讲解 Dubbo 社区最新动态、功能模块开发和近期规划等。主题演讲大多是社区采集方式,由 Dubbo 的深度企业分享实践经验,其中典型的代表包括携程、工商银行、考拉、信用算力等。&lt;/p>
&lt;p>从 GitHub 统计数据来看,Dubbo Star 数取得新的里程碑,已超过 3 万,相比重启开源时增长了近 5 倍;贡献者由最初的几十个增长到现在的 300 多个,而这其中有 60 多人已经被提名为 committer,不论是贡献者数量还是 committer 比例都得到很大的提升;Dubbo Java 发布的有 65 个。&lt;/p>
&lt;p>上述主要是对 Dubbo Java 项目社区发展的总结,下面将介绍 Dubbo Java 产品方面的进展。&lt;/p>
&lt;h3 id="dubbo-java-迭代目前主要维护-3-个大版本">Dubbo Java 迭代,目前主要维护 3 个大版本&lt;/h3>
&lt;p>当前社区维护的 Dubbo Java 大版本主要有 3 个,分别是 2.5.x、2.6.x 和 2.7.x。&lt;/p>
&lt;ul>
&lt;li>2.7.x 是社区的主要开发版本,在过去的一年共发布了 8 个版本(2.7.0 - 2.7.7),每个版本都有一些值得关注的特性或功能升级,涵盖从编程模型、服务治理、性能到协议的多个方面的增强;&lt;/li>
&lt;li>2.6.x 版本则定位为 bugfix 版本,过去一年共发布了 3 个版本,主要以修复问题和安全漏洞为主,并没有增加太多新的 feature;&lt;/li>
&lt;li>2.5.x 版本从 2019 年初开始已宣布 EOF,只做安全修复;而到了下半年已经完全停止了维护。&lt;/li>
&lt;/ul>
&lt;p>下面通过一个简要分层模块图,回顾过去一段时间 Dubbo 的技术架构演进,从编程模型、服务治理、传输协议、性能优化等角度切入:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/10years/dubbo-layer.png" alt="img">&lt;/p>
&lt;p>以上很多功能都已被各大厂商落地,用于解决具体的业务问题。我们也期待,接下来这些厂商带来更多关于 Dubbo 实践经验的深度总结。&lt;/p>
&lt;h3 id="dubbo-go-发展的第五年正与-dubbo-齐头并进">Dubbo-go 发展的第五年,正与 Dubbo 齐头并进&lt;/h3>
&lt;p>除 Dubbo Java 之外,Dubbo 周边也发展出了很多优秀的子项目(子社区),其中包括 Dubbo-spring-boot-project、Dubbo-go 等,这里先着重介绍 Dubbo-go 子社区。&lt;/p>
&lt;p>Dubbo-go 项目最早由于雨在 2016 年 5 月构建,同年 9 月发布并开源,如下时间轴图清晰记录了 Dubbo-go 的前世今生。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/10years/dubbo-go-events.png" alt="img">&lt;/p>
&lt;p>秉承 &amp;ldquo;bridge the gap between Java and Go&amp;rdquo; 天然使命的 Dubbo-go,已经进入第五个年头,也走出了自己独特的发展路径:&lt;/p>
&lt;ul>
&lt;li>当前的 v1.4.0 版本已对齐 2.6.x 版本,即将发布的版本将与 v2.7.x【对标 v2.7.5】对齐,而后将会发布对标 Dubbo 3.x 的 v1.6.0版本;&lt;/li>
&lt;li>独立维护从底层的 hessian2 协议库 Dubbo-go-hessian2、网络库 getty 到上层对标 Dubbo 的 Dubbo-go 的全套实现;&lt;/li>
&lt;li>独立的 TCP + Protobuf 和 gRPC + JSON 通信方案也已开发完成【将包含着在版本 v1.5.0 中】;&lt;/li>
&lt;li>已与 Dubbo/gRPC/&lt;a href="https://mp.weixin.qq.com/s?__biz=MzA4ODg0NDkzOA==&amp;amp;mid=2247487916&amp;amp;idx=1&amp;amp;sn=894316507590793285d0e15734db0bde&amp;amp;scene=21#wechat_redirect">Spring Boot&lt;/a> 实现互联互通;&lt;/li>
&lt;li>通过接入 &lt;a href="https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&amp;amp;mid=2247488596&amp;amp;idx=2&amp;amp;sn=4d554d32fdd167b6b74fc792c78fb341&amp;amp;scene=21#wechat_redirect">Opentracing&lt;/a> 和 Promethus,Dubbo-go 在可观测性等微服务方向的进行了自己独特的探索;&lt;/li>
&lt;li>已实现了基于 HTTPS 的&lt;a href="https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&amp;amp;mid=2247489539&amp;amp;idx=3&amp;amp;sn=379514cac71b91d57643e6f3d2701cdf&amp;amp;scene=21#wechat_redirect">可信 RPC 调用&lt;/a>;&lt;/li>
&lt;li>已经实现了自己独特的&lt;a href="https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&amp;amp;mid=2247489465&amp;amp;idx=3&amp;amp;sn=514144ef1a217a50b9f5a640ca122ac8&amp;amp;scene=21#wechat_redirect">把 Kubernetes 作为注册中心的微服务方案&lt;/a>;&lt;/li>
&lt;/ul>
&lt;p>Dubbo-go 从最开始 Dubbo 的 Go 语言实现,已发展成为目前 Dubbo 多语言版本中功能最强大者,它的发展离不开背后强大的 Dubbo-go 社区。除了上述 Dubbo-go 的自身特性外,通过跨社区合作,取得了如下成绩:&lt;/p>
&lt;ul>
&lt;li>通过与 MOSN 社区合作,已经实现 Dubbo/Dubbo-go 应用可以零成本接入基于 MOSN 实现 Dubbo Mesh,实现微服务和云原生共存的 &lt;strong>“双模微服务”&lt;/strong>;&lt;/li>
&lt;li>与 sentinel 社区合作,在 Dubbo/Dubbo-go 完整接入 sentinel 的降级和限流方案;&lt;/li>
&lt;li>与 Apollo 社区合作,在 Dubbo-go 中实现远程配置下发;&lt;/li>
&lt;li>与 Nacos 社区合作,实现基于 Nacos 的服务发现;&lt;/li>
&lt;/ul>
&lt;p>Dubbo-go 社区 2020 年 Q2 主要目标有:&lt;/p>
&lt;ul>
&lt;li>发布完全对齐 Dubbo 2.7.x 的 v1.5.0 版本;&lt;/li>
&lt;li>发布对标 Dubbo 3.0 的 v1.6.0版本;&lt;/li>
&lt;li>在云原生方面继续自己的探索;&lt;/li>
&lt;li>继续与兄弟社区保持合作共进态势,扩大自身使用范围;&lt;/li>
&lt;li>生产实践上推进在阿里集团,以及更多厂家的落地。&lt;/li>
&lt;/ul>
&lt;p>项目(包括子项目)目前已先后在携程、涂鸦智能和蚂蚁金服等公司生产落地。&lt;/p>
&lt;p>今年阿里集团完成 HSF 和 Dubbo 的融合后,项目也将在阿里集团双十一战场经受考验。&lt;/p>
&lt;h2 id="云原生-dubbo---dubbo-30">云原生 Dubbo - Dubbo 3.0&lt;/h2>
&lt;p>3.0 是下一代 Dubbo 架构的代号。一年前,最开始探索 Reactive Stream 之时,社区也曾有过对 Dubbo 3.0的广泛讨论。而这一次,在云原生大背景下,3.0 代表了更全面的 Dubbo 架构升级,涉及到下一代 RPC 协议、全新的服务治理模型和云原生基础设施适配等。&lt;/p>
&lt;p>阿里巴巴是参与 Dubbo 3.0 开发建设的主要力量之一,这款始于阿里的开源项目正重新回归阿里内部落地。&lt;/p>
&lt;p>去年开始,阿里巴巴就已经在逐步推动以 Dubbo 替换其内部的 HSF 框架的工作,通过将 Dubbo 与 HSF 两个框架融为一体,并在此基础上发展出适应云原生架构的 Dubbo 版本。Dubbo 重回阿里巴巴的落地是拥抱社区、拥抱云原生、拥抱标准化的一次很好的实践。&lt;/p>
&lt;p>阿里巴巴内部 Dubbo 3.0 的落地,对社区也是一个重大利好,这一方面有利于阿里巴巴将其在 HSF 上的丰富服务治理经验回馈输出到社区,另一方面也将直接推动 Dubbo 云原生架构的快速演进。除了阿里巴巴之外,包括斗鱼、工商银行、爱奇艺等厂商也都在参与下一代 Dubbo 3.0 的建设。&lt;/p>
&lt;p>下面列出了 Dubbo 3.0 中的三个重要方向,具体的 Roadmap 将在接下来文章中单独说明:&lt;/p>
&lt;ul>
&lt;li>下一代 RPC 协议。新协议将提供更丰富的如 Stream、Flow Control 等内置语义,同时将具有更好的扩展性、网关的友好性等;&lt;/li>
&lt;li>基于应用粒度的服务发现机制。在兼顾 Dubbo 面向接口的易用性与功能性的基础上,解决与 Kubernetes Native Service 适配问题,解决大规模集群下的地址推送性能瓶颈问题;&lt;/li>
&lt;li>适配云原生基础设施的解决方案。这涉及到 Dubbo 服务与基础设施生命周期对接、Kubernetes Native Service 适配、适应基础设施调度的服务治理规则、适配 Service Mesh 架构的解决方案等;&lt;/li>
&lt;/ul>
&lt;p>接下来沿着这三个方面简要展开。&lt;/p>
&lt;h3 id="下一代-rpc-协议">下一代 RPC 协议&lt;/h3>
&lt;p>专注在协议自身来说,下一代的协议主要聚焦在 HTTP/2、Reactive Stream、Flow Control 等方面:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Reactive Stream:&lt;/strong> Reactive Stream 引入 RPC,带来更丰富的通信语义和 API 编程模型支持,如 Request-Stream、Bi-Stream 等;&lt;/li>
&lt;li>&lt;strong>HTTP/2:&lt;/strong> 微服务云原生场景下,基于 HTTP/2 构建的通信协议具有更好的通用性和穿透性;&lt;/li>
&lt;li>&lt;strong>Flow Control:&lt;/strong> 协议内置流控机制,支持类似 Reqctive Stream 的 Request (n) 流控机制。&lt;/li>
&lt;/ul>
&lt;p>从解决的业务场景问题上来说,基于新的协议 Dubbo 在框架层面要支持智能决策的负载均衡算法、对 Mesh 和网关更友好、更容易提供多语言实现与互通等。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Mesh:&lt;/strong> 协议对穿透 Mesh 更友好,区分协议头 Metadata 与 RPC Payload,方便完成与 Mesh 的协作,包括流量控制机制、应用层配置协商等;&lt;/li>
&lt;li>&lt;strong>协议通用性:&lt;/strong> 兼顾通用性与性能,支持协议能在各种设备上运行;&lt;/li>
&lt;li>&lt;strong>多语言支持:&lt;/strong> 如通过支持 Protobuf 提供了更完善的 跨语言服务定义 与 序列化传输的支持。&lt;/li>
&lt;/ul>
&lt;h3 id="应用级服务治理">应用级服务治理&lt;/h3>
&lt;p>面向接口一直以来都是 Dubbo 框架的优势。一方面它的易用性,为开发者屏蔽了远程调用的存在;另一方面面向接口的地址发现、服务治理带来了更强大的能力,使得整个 Dubbo 治理体系非常强大与灵活。&lt;/p>
&lt;p>既然面向接口有如此多的好处,那为什么我们还要探索面向应用的服务治理模式呢?&lt;/p>
&lt;p>听起来似乎有些矛盾。其实到底是面向接口,还是面向应用,只是从不同的角度看 Dubbo。我们所聊的“面向接口 -&amp;gt; 面向应用”的改造,主要体现在服务注册、发现层面:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/10years/dubbo-triangle.png" alt="img">&lt;/p>
&lt;p>而我们说的面向应用的新模型,主要对第 2 点,即注册中心的数据组织转变为 “面向应用/实例” 粒度。这为我们解决两个问题:&lt;/p>
&lt;ul>
&lt;li>在服务发现层面与 Kubernetes Service 等微服务模型对齐;&lt;/li>
&lt;li>服务发现的数据量将有一个量级的下降,从 “接口数 * 实例数 ”下降到 “应用数 * 实例数”。&lt;/li>
&lt;/ul>
&lt;p>具体可以参见文章《&lt;a href="https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&amp;amp;mid=2247489653&amp;amp;idx=1&amp;amp;sn=445692c491f68aed3f649730d3d9ba96&amp;amp;scene=21#wechat_redirect">Dubbo 迈出云原生重要一步 - 应用级服务发现解析&lt;/a>》,本系列文章后续也会有对这部分机制和实现的更深度解析。&lt;/p>
&lt;h3 id="云原生基础设施">云原生基础设施&lt;/h3>
&lt;p>云原生带来了底层基础设施,应用开发、部署和运维等全方位的变化:&lt;/p>
&lt;p>&lt;strong>基础设施&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>基础设施调度机制变化,带来运维(生命周期)、服务治理等方面的变化;&lt;/li>
&lt;li>服务发现能力下沉, Kubernetes 抽象了 Native Service Discovery。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Service Mesh - 云原生微服务解决方案&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Mesh 为跨语言、sdk 升级等提供了解决方案,Dubbo sdk 要与 Mesh 协作,做到功能、协议、服务治理等多方便的适配;&lt;/li>
&lt;li>Mesh 尚未大规模铺开,且其更适合对流量管控更关注的应用,传统 SDK 的性能优势仍旧存在,两者混部迁移场景可能会长期存在。&lt;/li>
&lt;/ul>
&lt;p>从应用场景上,Dubbo 可能的部署环境包括:&lt;/p>
&lt;ol>
&lt;li>不使用 Kubernetes Native Service,Kubernetes 只作为容器编排调度设施,继续使用 Dubbo 自建的服务注册、发现机制;&lt;/li>
&lt;li>复用 Kubernetes Native Service,Dubbo 不再关心服务注册,Dubbo Client 负责服务发现与流量分配;&lt;/li>
&lt;li>Dubbo sdk 往 Mesh 迁移,一方面要做到适应 Mesh 架构,成为 Mesh 体系下的 RPC 编程和通信方案;另一方面要做到 Dubbo 与 Mesh 架构长期共存,互相打通服务发现和治理体系;&lt;/li>
&lt;li>Kubernetes 上与云下混合部署的平滑迁移支持,包括服务发现的统一与网络通信方案的打通。&lt;/li>
&lt;/ol>
&lt;p>从 Dubbo 功能划分上,将着重从以下方面提供对云原生基础设施的支持:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>生命周期&lt;/strong>:Dubbo 与 Kubernetes 调度机制绑定,保持服务生命周期与 Pod 容器等生命周期的自动对齐;&lt;/li>
&lt;li>&lt;strong>治理规则&lt;/strong>:服务治理规则在规则体、规则格式方面进行优化,如规则体以 YAML 描述、取消过滤规则对 IP 的直接依赖,定义规则特有的 CRD 资源等;&lt;/li>
&lt;li>&lt;strong>服务发现&lt;/strong>:支持 K8S Native Service 的服务发现,包括 DNS、API-Server,支持 xDS 的服务发现;&lt;/li>
&lt;li>&lt;strong>Mesh 架构协作&lt;/strong>:构建下一代的基于 HTTP/2的通信协议,支持 xDS 的标准化的数据下发。&lt;/li>
&lt;/ul>
&lt;p>新一代的 RPC 协议和应用级服务发现模型将会是这一部分的前置基础。&lt;/p>
&lt;h1 id="总结与展望">总结与展望&lt;/h1>
&lt;p>作为系列文章开篇,我们在这里对 Dubbo 过去一年的成绩做了简要的总结与回顾,包括 Dubbo 社区、产品迭代的发展。接下来我们会看到更多来自深度 Dubbo 用户的落地经验分享,Dubbo-go 子社区的发展故事等。更重要的,我们也对下一代云原生 Dubbo - Dubbo 3.0 做了展望,后续关于 Dubbo 3.0 Roadmap、方案设计与进展解析等也将在此系列中发布。&lt;/p></description></item><item><title>Blog: Dubbo Go 1.4.0</title><link>https://dubbo.apache.org/zh-cn/blog/2021/01/12/dubbo-go-1.4.0/</link><pubDate>Tue, 12 Jan 2021 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2021/01/12/dubbo-go-1.4.0/</guid><description>
&lt;p>得益于社区活跃的支持,2020 年 3 月 25 日 我们发布了一个让人兴奋的版本——dubbo-go v1.4.0。除了继续支持已有的 Dubbo 的一些特性外, dubbo-go 开始了一些自己的创新尝试。&lt;/p>
&lt;p>这个版本,最大的意义在于,做了一些支持云原生的准备工作。比如说,社区在探讨了很久的 k8s 落地之后,终于拿出来了使用 k8s 作为注册中心的解决方案。&lt;/p>
&lt;p>其次一个比较大的改进是&amp;ndash;我们在可观测性上也迈出了重要的一步。在这之前,dubbo-go只提供了日志这么一个单一手段,内部的信息比较不透明,这个版本将有很大的改善。&lt;/p>
&lt;p>最后一个令人心动的改进是,我们支持了 REST 协议。&lt;/p>
&lt;h2 id="1-k8s-注册中心">1. K8s 注册中心&lt;/h2>
&lt;p>dubbo-go 注册中心的本质为K/V型的数据存储。当前版本实现了以 Endpoint 为维度在 k8s API Server 进行服务注册和发现的方案【下文简称 Endpoint 方案】,架构图如下。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/1.4/k8s.png" alt="img">&lt;/p>
&lt;p>Endpoint 方案,首先将每个 dubbo-go 进程自身服务信息序列化后,通过 Kubernetes 提供的 Patch 的接口写入在自身 Pod 对象的 Annotation 中。其次,通过 Kubernetes 的 Watch 接口观察集群中本 Namespace 内带有某些固定lable [见上图] Pod 的Annotation 信息的更新,处理服务健康检查、服务上下线等情况并实时更新本地缓存。整体流程仅使用 Kubernetes 原生 API 完成将 Kubernetes 作为注册中心的功能特性。&lt;/p>
&lt;p>这个方案非常简洁,不需要实现额外的第三方模块,也不需要对 Dubbo 业务作出改动,仅仅把 k8s 当做部署平台,依赖其容器管理能力,没有使用其 label selector 和 service 等服务治理特性。如果站在 k8s Operator 的角度来看,Operator 方案的优点即 Endpoint 方案的缺点,Endpoint 方案无法使用 k8s 的健康检查能力,亦没有使用 k8s service 的事件监听能力,每个 consumer 冗余监听一些不必要监听的事件,当 Endpoint 过多时会加大 API Server 的网络压力。&lt;/p>
&lt;p>目前 dubbo-go 社区其实已经有了 operator 版本注册中心的技术方案, 后续版本【计划版本是 v1.6】的 dubbo-go 会给出其实现。相比当前实现,operator 方案开发和线上维护成本当然上升很多。二者如同硬币的两面,社区会让两种方式会共存,以满足不同 level 的使用者。&lt;/p>
&lt;p>注意: 因 Pod 被调度而 IP 发生变化时,当前版本的 configuration 以及 router config 模块暂时无法动态更新。这有待于我们进一步解决。&lt;/p>
&lt;p>参考范例&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>.&lt;/p>
&lt;h2 id="2-tracing-和-metric">2. tracing 和 metric&lt;/h2>
&lt;p>可观测性是微服务重要的一环,也是我们1.4版本着力支持的部分。在1.4版本中,我们主要在 tracing 和 metric 两个方向提供了支持。&lt;/p>
&lt;p>为了支持 tracing 和 metric,关键的一点是支持context在整个调用过程中传递。为此我们解决了context跨端传递的问题。目前用户可以在接口中声明 context 并且设置值,dubbo-go 在底层完成 context 内容从 client 传递到 server 的任务。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/1.4/context.png" alt="img">&lt;/p>
&lt;p>在 metric 方面,dubbo-go 开始支持 Prometheus 采集数据了。目前支持 Prometheus中 的 Histogram 和 Summary。用户也可以通过扩展 Reporter 接口来自定义数据采集。&lt;/p>
&lt;p>在 tracing 方面,目前 dubbo-go 的设计是采用 opentracing 作为统一的 API,在该 API 的基础上,通过在 client 和 server 之中传递 context,从而将整个链路串起来。用户可以采用任何支持 opentracing API 的监控框架来作为实现,例如 zipkin,jaeger 等。&lt;/p>
&lt;h2 id="3-rest协议支持">3. rest协议支持&lt;/h2>
&lt;p>Dubbo 生态的应用与其他生态的应用互联互通,一直是 dubbo-go 社区追求的目标。dubbo-go v1.3 版本已经实现了 dubbo-go 与 grpc 生态应用的互联互通,若想与其他生态如 Spring 生态互联互通,借助 rest 协议无疑是一个很好的技术手段。&lt;/p>
&lt;p>Rest 协议是一个很强大并且社区呼声很高的特性,它能够有效解决 open API,前端通信,异构系统通信等问题。比如,如果你的公司里面有一些陈年代码是通过 http 接口来提供服务的,那么使用我们的 rest 协议就可以无缝集成了。&lt;/p>
&lt;p>通过在 dubbo-go 中发布 RESTful 的接口的应用可以调用任意的 RESTful 的接口,也可以被任何客户端以 http 的形式调用,框架图如下:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/1.4/rest.png" alt="img">&lt;/p>
&lt;p>在设计过程中,考虑到不同的公司内部使用的 web 框架并不相同,所以我们允许用户扩展自己 rest server ( web 框架在 dubbo-go的封装)的实现,当然,与 rest server 相关的,诸如 filter 等,都可以在自己的 rest server 实现内部扩展。&lt;/p>
&lt;h2 id="4-路由功能增强">4. 路由功能增强&lt;/h2>
&lt;p>路由规则在发起一次 RPC 调用前起到过滤目标服务器地址的作用,过滤后的地址列表,将作为消费端最终发起 RPC 调用的备选地址。v1.4 版本的 dubbo-go 实现了 Condition Router 和 Health Instance First Router,将在后面版本中陆续给出诸如 Tag Router 等剩余 Router 的实现。&lt;/p>
&lt;h3 id="41-条件路由">4.1 条件路由&lt;/h3>
&lt;p>条件路由,是 dubbo-go 中第一个支持的路由规则,允许用户通过配置文件及远端配置中心管理路由规则。&lt;/p>
&lt;p>与之相似的一个概念是 dubbo-go 里面的 group 概念,但是条件路由提供了更加细粒度的控制手段和更加丰富的表达语义。比较典型的使用场景是黑白名单设置,灰度以及测试等。&lt;/p>
&lt;p>参考范例&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>。&lt;/p>
&lt;h3 id="42-健康实例优先路由">4.2 健康实例优先路由&lt;/h3>
&lt;p>在 RPC 调用中,我们希望尽可能地将请求命中到那些处理能力快、处于健康状态的实例,该路由的功能就是通过某种策略断定某个实例不健康,并将其排除在候选调用列表,优先调用那些健康的实例。这里的&amp;quot;健康&amp;quot;可以是我们自己定义的状态,默认实现即当错误比例到达某一个阈值时或者请求活跃数大于上限则认为其不健康,允许用户扩展健康检测策略。&lt;/p>
&lt;p>在我们服务治理里面,核心的问题其实就在于如何判断一个实例是否可用。无论是负载均衡、&lt;/p>
&lt;p>熔断还是限流,都是对这个问题的解答。所以,这个 feature 是一个很好的尝试。因为我们接下来计划提供的特性,基于规则的限流以及动态限流,都是要解决“如何断定一个实例是否可用”这么一个问题。&lt;/p>
&lt;p>所以欢迎大家使用这个特性,并向社区反馈各自设定的健康指标。这对我们接下来的工作会有很大的帮助。&lt;/p>
&lt;h2 id="5-hessian-协议增强">5. hessian 协议增强&lt;/h2>
&lt;p>相较于 dubbo 的 Java 语言以及其他多语言版本,dubbo-go 社区比较自豪的地方之一就是:无论底层网络引擎还是原生使用的 hessian2 协议,以及整体服务治理框架,都由 dubbo-go 社区从零开发并维护。v1.4 版本的 dubbo-go 对 hessian2 协议又带来了诸多新 feature。&lt;/p>
&lt;h3 id="51-支持-dubbo-协议的-attachments">5.1 支持 dubbo 协议的 attachments&lt;/h3>
&lt;p>在 dubbo-go中,attachments 机制用于传递业务参数之外的附加信息,是在客户端和服务端之间传递非业务参数信息的重要方式。&lt;/p>
&lt;p>hessian 编码协议将之编码在 body 内容的后面进行传输,dubbo-go-hessian2 之前并不支持读/写 attachments,在多个使用方【如蚂蚁金服】的要求下,dubbo-go-hessian2 以兼容已有的使用方式为前提,支持了 attachments 的读/写。&lt;/p>
&lt;p>Request 和 Response 的 struct 中定义了 attachments 的 map,当需要使用 attachments,需要由使用方构造这两种类型的参数或者返回对象。否则,将无法在hessian的传输流中获取和写入attachments。&lt;/p>
&lt;p>另外,利用 dubbo-go 调用链中传输 context 的功能,用户已经可以在服务方法中通过 context 添加 attachments了。&lt;/p>
&lt;h3 id="52-支持忽略非注册-pojo-的解析方式">5.2 支持忽略非注册 pojo 的解析方式&lt;/h3>
&lt;p>由于 hessian 编码协议与 Java 的类型高度耦合,在 golang 的实现中会相对比较麻烦,需要有指明的对应类型。dubbo-go-hessian2 的实现方式是:定义 POJO 接口,要求实现 JavaClassName 方法来供程序获取 Java 对应的类名。这导致了接收到包含未注册类的请求时,将会无法解析而报错,这个问题以前是无法解决的。&lt;/p>
&lt;p>但是,有一些使用场景如网关或者 service mesh 的 sidecar,需要在不关心 Java 类的具体定义的情况下,像 http读取 header 信息一样仅仅读取 dubbo 请求的附加信息,将 dubbo/dubbo-go 请求转发。通过该 feature,网关/sidecar 并不关注请求的具体内容,可以在解析请求的数据流时跳过无法解析的具体类型,直接读取 attachments 的内容。&lt;/p>
&lt;p>该实现通过在 Decoder 中添加的 skip 字段,对每一个 object 做出特殊处理。&lt;/p>
&lt;h3 id="53-支持-javamathbiginteger-和-javamathbigdecimal">5.3 支持 java.math.BigInteger 和 java.math.BigDecimal&lt;/h3>
&lt;p>在 Java 服务中,java.math.BigInteger 和 java.math.BigDecimal 是被频繁使用的数字类型,hessian 库将它们映射为 github.com/dubbogo/gost/math/big 下的对应类型。&lt;/p>
&lt;h3 id="54-支持-继承-和忽略冗余字段">5.4 支持 ‘继承’ 和忽略冗余字段&lt;/h3>
&lt;p>由于 go 没有继承的概念,所以在之前的版本,Java 父类的字段不被 dubbo-go-hessian2 所支持。新版本中,dubbo-go-hessian2 将Java来自父类的字段用匿名结构体对应,如:&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">type&lt;/span> Dog &lt;span style="color:#268bd2">struct&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Animal
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Gender &lt;span style="color:#dc322f">string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DogName &lt;span style="color:#dc322f">string&lt;/span> &lt;span style="color:#2aa198">`hessian:&amp;#34;-&amp;#34;`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>同时,就像 json 编码中通过 &lt;code>immediately&lt;/code> 可以在序列化中忽略该字段,同理,通过 &lt;code>hessian:&amp;quot;-&amp;quot;&lt;/code> 用户也可以让冗余字段不参与 hessian 序列化。&lt;/p>
&lt;p>目前,上述四个特性已被某 Go 版本的 sidecar 集成到其商业版本中提供商业服务。&lt;/p>
&lt;h2 id="6-nacos-配置中心">6. Nacos 配置中心&lt;/h2>
&lt;p>配置中心是现代微服务架构里面的核心组件,现在 dubbo-go 提供了对配置中心的支持。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/1.4/config-center.png" alt="img">&lt;/p>
&lt;p>Nacos 作为一个易于构建云原生应用的动态服务发现、配置管理和服务管理平台,在该版本终于作为配置中心而得到了支持。&lt;/p>
&lt;p>参考范例&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>.&lt;/p>
&lt;h2 id="7-接口级签名认证">7. 接口级签名认证&lt;/h2>
&lt;p>Dubbo 鉴权认证是为了避免敏感接口被匿名用户调用而在 SDK 层面提供的额外保障。用户可以在接口级别进行定义是否允许匿名调用,并对调用方进行验签操作,对于验签不通过的消费端,禁止调用。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/1.4/acl.png" alt="img">&lt;/p>
&lt;p>如上图,总体实现基于 AK/SK 机制,应用通过 HTTPS 通信,启动时向鉴权服务拉取,定期更新。且允许用户自定义获取 AK/SK 的源,在 RPC 层面保障安全性。&lt;/p>
&lt;h2 id="8-回顾与展望">8. 回顾与展望&lt;/h2>
&lt;p>目前 dubbo-go 已经到了一个比较稳定成熟的状态。在接下来的版本里面,我们将集中精力在云原生上。下一个版本,我们将首先实现应用维度的服务注册,这是一个和现有注册模型完全不同的新的注册模型。也是我们朝着云原生努力的一个关键版本。&lt;/p>
&lt;p>在可观测性上,我们计划在整个 dubbo-go 的框架内,引入更多的埋点,收集更加多的内部状态。这需要实际生产环境用户的使用反馈,从而知道该如何埋点,收集何种数据。&lt;/p>
&lt;p>在限流和熔断上,可以进一步扩展。当下的限流算法,是一种静态的算法&amp;ndash;限流参数并没有实时根据当前服务器的状态来推断是否应该限流,它可能仅仅是用户的经验值。其缺点在于,用户难以把握应该如何配置,例如 TPS 究竟应该设置在多大。所以计划引入一种基于规则的限流和熔断。这种基于规则的限流和熔断,将允许用户设置一些系统状态的状态,如 CPU 使用率,磁盘 IO,网络 IO 等。当系统状态符合用户规则时,将触发熔断。&lt;/p>
&lt;p>目前这些规划的 任务清单&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>,都已经放入在 dubbo-go 项目的 issue 里面,欢迎感兴趣的朋友认领参与开发。dubbo-go 社区在 &lt;strong>钉钉群 23331795&lt;/strong> 欢迎你的加入。&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://github.com/apache/dubbo-go-samples/tree/1.5/registry/kubernetes">https://github.com/apache/dubbo-go-samples/tree/1.5/registry/kubernetes&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://github.com/dubbogo/dubbo-samples/tree/master/golang/router/condition">https://github.com/dubbogo/dubbo-samples/tree/master/golang/router/condition&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://github.com/dubbogo/dubbo-samples/tree/master/golang/configcenter/nacos">https://github.com/dubbogo/dubbo-samples/tree/master/golang/configcenter/nacos&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>&lt;a href="https://github.com/apache/dubbo-go/milestone/1">https://github.com/apache/dubbo-go/milestone/1&lt;/a>&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Blog: Dubbo Go 回顾与展望</title><link>https://dubbo.apache.org/zh-cn/blog/2021/01/11/dubbo-go-%E5%9B%9E%E9%A1%BE%E4%B8%8E%E5%B1%95%E6%9C%9B/</link><pubDate>Mon, 11 Jan 2021 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2021/01/11/dubbo-go-%E5%9B%9E%E9%A1%BE%E4%B8%8E%E5%B1%95%E6%9C%9B/</guid><description>
&lt;p>Dubbo 是阿里于 2011 年开源的一款高性能 RPC 框架,在 Java 生态中具有不小的影响力。2019年5月21日,Dubbo 从 Apache 软件基金会毕业,成为 Apache 顶级项目。目前,毕业后的 Dubbo 项目的生态中已经正式官宣引入了 Go 语言,发布了 Dubbogo 项目。本文即是对 Dubbogo 这一项目的完整回顾与真实展望。由蚂蚁金服中间件技术专家于雨和携程基础中台研发部工程师方银城合作完成。&lt;/p>
&lt;h2 id="一-dubbogo-整体框架">一 Dubbogo 整体框架&lt;/h2>
&lt;p>先介绍一下 dubbogo 的缘起,先看下面这幅图:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p1.jpeg" alt="img">&lt;/p>
&lt;p>最右边的 service0 和 service1 是 Dubbo 的服务端,左边的 gateway 是网关,HTTP 请求从网关进来,必须转化成 Dubbo 的协议才能到后面的服务,所以中间加了一层proxy 完成相关功能。基本上每个 service 都需要一个 proxy 去转化协议和请求,所以这个时候 dubbogo 的项目需求就出来了。最初的实现就是以 Dubbo 的 Go 版本作为目标,实现与 Java 版本 Dubbo 的互调。&lt;/p>
&lt;h3 id="dubbogo-目标">Dubbogo 目标&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p2.jpeg" alt="img">&lt;/p>
&lt;p>然后这个图是 dubbogo 的现在达到的目标:用一份 Go 客户端的代码能够在没有任何代理和其他中间件的情况下直接调用其他语言端,主要是Java 服务端的服务和 Go 服务端的服务,而 Go 作为服务端的时候,Java 客户端也可以直接调用 Go 服务端的服务。&lt;/p>
&lt;h3 id="dubbogo-发展历程">Dubbogo 发展历程&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p3.jpeg" alt="img">&lt;/p>
&lt;p>下面介绍 dubbogo 的整个发展历程,在2016年8月份的时候是于雨构建了 dubbogo 项目,那个时候的 dubbogo 只支持通过 jsonrpc 2.0 协议 进行 HTTP 通信,到 2018 年2 月份支持 hessian2 协议进行 TCP 通信,到 2018 年 5 月项目被 dubbo 官方关注后开始从零重构,于雨 2018 年 8 月份初步重构出一个 0.1 版本。由于我们携程这边的一些需求,2019 年初我和我的同事何鑫铭也开始参与了 dubbogo 项目的重构,同时和于雨一起开始组建社区,在 2019 年 6 月份的时候 dubbogo1.0 版本上线,这个版本的重构是参照了 Dubbo 的整体设计,主体功能都在这个版本里面有呈现,同期该项目进入了 Apache 组织。今年 8 月份由社区同学望哥负责的 Dubbo-go-hessian2 的项目也进了 Apache 组织。到目前为止我们社区有些工作已经和 dubbo 齐头并进,例如对 grpc 和 k8s 的支持,相关代码正在 review 中,年底发布的 v1.3 版本会包含 grpc 支持。预计到2020年,也是明年的目标,希望项目能以全新姿态融入云原生时代。&lt;/p>
&lt;h3 id="dubbogo-整体设计">Dubbogo 整体设计&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p4.jpeg" alt="img">&lt;/p>
&lt;p>这个图大家是不是看着很熟悉,是 Dubbo 的整个分层设计图,但是少了 Dubbo 里面的很多东西,因为我们是借鉴了 Dubbo 的分层设计和易拓展性的思想,但是由于 Go 语言和 Java 语言的本质差别决定了我们项目设计不可能完全照搬它,有一些东西就给它简化了,特别是协议层这一块。比如说 Dubbo 里面 SPI 的拓展,在 Go 里面我们是借用了 Go 的非侵入式接口的方式去实现的,由于 Go 禁止 package 循环引用,所以 dubbogo 在代码的分包分层上面也是有严格的规定,这正好跟它的易拓展性的特性结合了起来。&lt;/p>
&lt;p>关于代理部分,因为 Java 有动态代理,Go 的反射就没有 Java 的反射那么强大,所以我们这边代理的实现方式也跟它是不一样的。&lt;/p>
&lt;h3 id="dubbogo-能力大图">Dubbogo 能力大图&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p5.jpeg" alt="img">&lt;/p>
&lt;p>上面的图是我们当前 dubbogo 项目实现的能力大图,最上层是当前实现的一些注册中心有 zk、etcd、nacos、consul,现在与 k8s 关联的功能正在开发中。配置中心目前是支持 Apollo 和 zookeeper。左边是消费端,消费端这边实现的是有 cluster 的,策略上基本上实现了 dubbo 支持的所有策略。然后还有负载均衡策略,fillter 主要是有一个 tps 的限流还有泛化调用,这两个后面会讲到。编码层现在就是 jsonrpc 2.0 和 hessian2,protobuf v3 正在加紧 review 中。目前社区正在开发中的支持,包括 trace、grpc、k8s注册中心,以及对 restful 的支持。&lt;/p>
&lt;h3 id="关键项目">关键项目&lt;/h3>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p6.jpeg" alt="img">&lt;/p>
&lt;p>目前 dubbogo 项目整体由 4 个组成部分。第一个是 getty,一个异步网络 IO 库,是实现 tcp 通信协议最坚实的基础;第二个是 dubbo-go-hessian2,这个是与当前 java hessian2 高度兼容的项目;第三个是 gost,是 dubbogo 的 基础库;最后是 dubbogo 的示例库,目前已经迁移到 &lt;a href="https://github.com/apache/dubbo-samples">https://github.com/apache/dubbo-samples&lt;/a>,和 Java 示例合并了。这些都是当前 dubbogo 主要的组成项目。&lt;/p>
&lt;h2 id="二-协议实现">二 协议实现&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p7.jpeg" alt="img">&lt;/p>
&lt;p>接下来讲一些具体的实现和部分的功能,上图是 dubbo-go-hessian2 实现,列出来是一些主要的功能列表,第一个是 Java 的 JDK Exceptions 的实现,里面实现了 40 多种的 Java JDK 主要的异常,可以与 Java 的 hessian2 版本互相解编码的支持,支持自动扩展自己实现 exceptions,或者是不常见的 Exceptions;第二个是支持字段名的联名,Go 可序列化的字段是大写字母开头,但是 Java 默认是小写开头的,所以有编码的字段名不一致的问题,这就有别名识别和支持自定义命名。&lt;/p>
&lt;p>go-hessian2 还支持 Java 的 bigdecimal、Date、Time、基本类型的包装类型、Generic Invocation、Dubbo Attachements,甚至支持 emoji 表情。&lt;/p>
&lt;p>go-hessian2 里面如果要解码和编码用户自定义类型,用户需要自己把它注册进去,前提是支持 go-hessian2 的 POJO interface,才能跟 JAVA 对应类互相解编码。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p8.jpeg" alt="img">&lt;/p>
&lt;p>上面是 go-hessian2 的类型对应表,需要特别点出的是 int,go 这边的 int 类型在不同字长系统下是有不同的大小,可能是 32 位也可能 64位的,而 Java 的 int 是 32 位的,所以我们以 go 语言的 int32 类型对应 Java int 类型。&lt;/p>
&lt;p>刚才提到了 Java 的 Class 和 go struct 的对应。上图有一个 go-hessian2 的 POJO 接口定义,每个 Java class 对应到 go struct,则 struct 需要给出 Java ClassName。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p9.jpeg" alt="img">&lt;/p>
&lt;p>你也可以加 hessian 标签,解析的时候会把这个字段名用别名写进去,实现自定义 fieldName。默认情况下,go-hessian2 中会自动把 struct field 首字母变成小写作为其 fieldName。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p10.jpeg" alt="img">&lt;/p>
&lt;p>泛化引用,是 dubbogo 里面比较重要的功能。社区一位同学需要基于 dubbogo 实现网关,收集外部的请求,然后通过泛化引用的形式调用其他 Dubbo 服务,最后自己动手把它实现了。使用时,首先需要在项目里内置一个 GenericService 服务,调用Load,然后就像正常的调用服务一样直接调用,跟 Java 是类似的,Go 客户端可以不知道 Java 的接口定义和类定义,把方法名、参数类型、参数数组以一个 map 的形式传输到 Java 服务端,Java 服务端收到请求后进行识别,把它转换成 POJO 类。&lt;/p>
&lt;p>以上是 go-hessian2 一些细节。上文讲到的泛化引用,是把网关作为整个内网 Dubbo 服务的公共消费端,使用的时候只需要知道请求的方法、参数类别,然后就能够调用 Dubbo 的服务。后面主要分享三部分内容:首先是网络引擎、底层网络库这块;其次是服务治理方面的内容,其中包含以 k8s 作为注册中心的一个初步的解决方案;第三部分是互联互通,主要是和 grpc 打通。最后给出一个展望,包含 dubbogo 社区明年的工作内容。&lt;/p>
&lt;h2 id="三-网络引擎">三 网络引擎&lt;/h2>
&lt;p>dubbogo 的网络引擎里面分为三层, 如下图所示:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p11.jpeg" alt="img">&lt;/p>
&lt;p>最底层 streaming 处理二进制流,第二层 codec层,进行协议的序列化和反序列化,第三层是 Eventlistener,提供应用使用接口。streaming 层能支持 websocket、TCP、UDP 三种网络通讯协议,这层具有一定的灵活性,今年年初上海有一个同学今年把 KCP 也加进去了,当时说要开源贡献出来,我还在期待中。codec 层可以适用不同协议,用户自定义即可。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p12.jpeg" alt="img">&lt;/p>
&lt;p>EventListener 对上层暴露了 4 个回调接口。第一个是 OnOpen,网络连接初建成功时被调用,应用层如果判定其为正常连接,则可以把连接 session 存储下来,如果用户判断当前连接过多则返回一个非空的 error,则这个连接会被 dubbogo 关闭。其次是 OnError 事件,当网络连接出错,就会回调到这个接口,在 dubbogo 关闭这个连接之前允许用户做相应处理,如把网络连接 session 从应用层的 session 池中删除。第三个是 OnCron,处理定时任务,如心跳,dubbogo 针对 websocket 协议在底层直接把心跳热任务处理了,针对 tcp 和 udp 协议需要用户在这个回调函数中自己实现。第四个接口是 OnMessage,用作处理一个完整的网络包。可以看到整个回调接口风格跟 websocket 的接口很像。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p13.jpeg" alt="img">&lt;/p>
&lt;h3 id="协程池">协程池&lt;/h3>
&lt;p>dubbogo 的 goroutine pool 里有 worker channel 【数量为 M】和逻辑处理 goroutine 【数量为 N】和网络任务【网络包】三种角色,网络解包后把把包按照某种规则放入某个 worker pool,然后逻辑处理 goroutine 从 channel 中读取数据包并执行逻辑处理,其目的是是为了把网络 I/O 与逻辑处理分开。不同的 goroutine pool 设计中,有的 N 大小会变化,有的不变,分别可称之为可伸缩 goroutine pool 和不可伸缩 goroutine pool,可伸缩 goroutine pool 可以对机器资源的使用不可预计。dubbogo 采用了不可伸缩 goroutine pool,其考量是限定其网络资源使用的上限。&lt;/p>
&lt;p>另外,dubbogo 的 goroutine pool 不考虑收包后的处理顺序。譬如,dubbogo 服务端收到了 A 和 B 两个网络包,dubbogo 有可能先处理网络包 B,后处理网络包 A。如果客户端的每次请求都是独立的,没有前后顺序关系,则带有不考虑网络包处理顺序是没有问题的。如果有强顺序要求,譬如上层用户关注 A 和 B 请求处理的前后顺序,则可以把 A 和 B 两个请求合并为一个请求,或者把 dubbogo 的 goroutine pool 特性关闭。&lt;/p>
&lt;p>一般情况下,不建议大家自己写 goroutine pool,因为 Go 语言对 goroutine 资源的管理已经非常先进,比如释放一个协程,Go 不会马上销毁掉相关的资源,一旦有创建 goroutine 的需要,马上就可复用这个成本是很低的。什么情况下使用 Goroutine Pool 呢?个人觉得像网络库逻辑处理这类场景下执行同样类型任务场景下确定 goroutine 会被迅速重复使用时可以尝试使用,但是怎么用好还是需要仔细考量,即需要仔细考量 M 与 N 的比例关系。&lt;/p>
&lt;p>假设处理某种网络任务请求,有的请求1秒就处理完了,有的可能10毫秒处理完了,设置 M 与 N 比例为 1:1,这样 1 对 1 造成的后果可能是饥饿,就是有一些队列处理的很快,有的处理很慢,整体负载不均衡,这种情况下就不推荐你用协成池了。&lt;/p>
&lt;p>还有一个比例模型是是1:N的,一写多读,比如说所有的请求都交给一个队列,所有逻辑处理 goroutine pool 都消费这个队列,造成的结果是什么呢?因为你只有一个生产者,那你就只有一个队列,多个消费者消费这一个队列,造成的结果是什么呢?因为 go channel 的低效率【整体使用一个 mutex lock】造成消费者 goroutine hang 在锁竞争上,当然其网络包处理顺序更无从保证。&lt;/p>
&lt;p>比较均衡的效果就是 M 和 N 都大于 1,dubbogo 的的 goroutine pool 模型中 M 和 N 的取值可以自行配置,其效果是每个 channel 被 N/M 个 goroutine 消费,这种模型类似于 kafka 的 consumer group,其优点是兼顾处理效率和锁压力平衡,可以做到总体层面的任务处理均衡。&lt;/p>
&lt;h3 id="优化改进">优化改进&lt;/h3>
&lt;p>优化改进主要从三个方面入手, 如下图所示:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p14.jpeg" alt="img">&lt;/p>
&lt;ol>
&lt;li>内存池。goroutine pool 是管理对 CPU 资源的分配,内存池就是管理内存资源的分配。我个人反对纯粹为了炫技没有目的地写内存池,其实 Go 的内存管理这块目前优化的很好了。Go 语言初始版本的内存管理使用了谷歌自家的 tcmalloc 库,这个库把应用释放的内存自己先缓存住,待失效期后才释放,那这样造成的结果是什么呢?就是早期的 Go 程序的内存成本很高。假设程序一个 sidecar 程序的资源限制是内存2G,CPU 核数是 2 核,用这样一个内存管理库,内存用完不释放给操作系统,那么没人敢用这个项目,当然最新的 Go 内存管理器是经过完全重构的,虽然也区分不同大小 span 的内存在 P 级别和全局级别进行缓存,但是基本上不用考虑这种内存膨胀不可控的问题了。那么什么情况下使用内存池呢?你确定你的业务有一些对象是频繁的复用则可以尝试使用。 目前大部分内存池技术底层依赖的底座都是 sync.Pool,自己写一个也不难。而且 Go 1.13 之后的 sync.Pool 已经可以做到跨 GC span 不释放缓存对象,非常之好。&lt;/li>
&lt;li>定时器。Go 语言早期定时器因为整体使用一把大锁的缘故效率极差,当然最新的就相当好了,通过每个 CPU 核下一个定时器的方法【类似于分片锁】分散了竞争压力,但是很多情况下还是有竞争压力,如果对时间精度要求不高个人建议在自己的应用中自己写一个简单的时间轮实现一个定时器,释放 CPU 压力。&lt;/li>
&lt;li>网络写 buffer 合并。写 buffer 合并一般采用 writev,但是 Go 语言的 writev 有内存泄露问题,我这边一个负责 MOSN 开发的同事元总发现的。他先给 Go 语言官方提交了 PR,然后在 MOSN 中把 writev 扔掉自己写了一个简单好用的写 buffer 合并发送实现:通过 for 循环 10 次从发送 channel 中把网络包读取出来然后合并发送,当然循环中间网络发送 channel 没有足够的网络包就通过 &lt;code>select-default&lt;/code> 分支立即退出循环。&lt;/li>
&lt;/ol>
&lt;h3 id="channel-使用">channel 使用&lt;/h3>
&lt;p>Go 语言是一个适合处理 IO 密集型任务的语言,不擅长处理 CPU 密集型任务,其内存通信的基础就是 channel。channel 整体的内存基础是一个 ring buffer 数组和一个 lock,外加其他一些读写通知队列等,也是因为一把大锁的缘故,则 buffer 型 channel 如果使用不当则效率不会很高,如每个 channel element 的内存使用过大。channel 还有一个 closed 字段,用于判定 channel 的写是否被关闭掉,Go 语言对其操作是以原子锁方式进行的,很多人以这个字段为基础进行信号通知,如果使用不当很可能造成 for 循环 CPU 100% 的问题,所以在 for-select 循环中特别要谨慎使用,dubbogo 在这方面踩过坑。&lt;/p>
&lt;h2 id="四-服务治理">四 服务治理&lt;/h2>
&lt;p>下面为大家讲一下服务治理,说到服务治理,其实最重要的还是服务发现和服务注册,这块逻辑跟 Dubbo 类似,这次不作展开。下面主要包含两方面的内容,分别是限流算法和优雅退出。&lt;/p>
&lt;h3 id="限流算法">限流算法&lt;/h3>
&lt;p>限流算法首先需要考虑限流的对象,dubbogo 需要考虑 interface 和 method。其次是限流方法,首先需要考虑的是单机限流还是集群限流,单机限流算法很多,譬如常用的固定窗口算法和滑动窗口算法,以及更进一步的自适应限流。限流时一个重要问题就是限流参数是很难配的,譬如线上服务到底需要使用多少机器资源合理,限流窗口的时间窗口时长应该多长合适,其 qps 值设置多少合适呢?这都是 dubbogo 需要解决的问题。先进如谷歌的 BBR 算法,可以在当前的网络环境恶化前不断尝试改进相关参数,直到尝试出一段时间内的最佳参数。还有一些业务形态下的限流,如针对会员和非会员分别设计不同的限流链路。&lt;/p>
&lt;p>Dubbo 的限流接口源码如下:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p15.png" alt="img">&lt;/p>
&lt;p>这个接口抽象是非常漂亮的,第一个是限流 url,第二个服务调用。下面是 Dubbo 的固定窗口限流源码:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p16.png" alt="img">&lt;/p>
&lt;p>上面的代码很明显,&amp;ldquo;private final&amp;rdquo; 决定了 Dubbo 使用者只能使用期给定的固定窗口限流限算法,无法扩展。&lt;/p>
&lt;p>以下是 dubbogo 的限流接口:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p17.jpeg" alt="img">&lt;/p>
&lt;p>TpsLimiter 是限流对象,TpsLimitStrategy 是限流算法,RejectedExecutionHandle 是限流动作。&lt;/p>
&lt;p>接下来是一个固定窗口算法实现:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p18.jpeg" alt="img">&lt;/p>
&lt;p>上图是 dubbogo 的固定窗口算法实现,其非线程安全,大家看一下代码就可以了,不推荐大家用。下图是 dubbogo 的滑动窗口算法实现:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p19.jpeg" alt="img">&lt;/p>
&lt;p>其基本原理是用一个队列存储一段时间内的请求,然后根据队列长度判定即可。&lt;/p>
&lt;p>不管是固定窗口还是滑动窗口,其判定算法简单,麻烦的是其参数设置,如下图:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p20.png" alt="img">&lt;/p>
&lt;p>固定窗口时长精度很难控制。比如说限流一秒 QPS 值 1000,前 100 毫秒来了一千个请求,然后判定算法把请求放过了,而其后 900 毫秒 任何请求都无法处理。一般的处理方法是把时间粒度更精细一些,dubbogo 的时间窗口最小单位是一毫秒,则用户可以把时间窗口设定为 100 毫秒,总体来说一段时间内是很平稳的。下面这个图是我们社区的 commiter 邓明写完博客发出来,行业大佬微信评论如下:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p21.png" alt="img">&lt;/p>
&lt;p>图中第一个问题是 qps 和 tps 每个请求成本不同,这个问题怎么处理呢?个人觉得这是一个分级限流问题,在同一个服务下针对不同的请求做不同的分级处理。第二个问题 ”配置了 qps 1000,但是请求过来是10万你还是死“,这个就需要更上层的运维能力进行应对,譬如判定为恶意流量攻击就应该在网关层拦截掉,如果是服务能力不行就扩容。&lt;/p>
&lt;p>针对分级限流,dubbogo 目前尚无法在同一个进程内完成,这需要 dubbogo 的配置中心更完善以后进行处理,用户可以通过搭建不同的服务链路处理之。譬如会员/非会员分级,同一个服务针对不同的会员等级搭建相应的链路,在网关层就判定一个 userID 是否是会员,然后发送不同的链路。&lt;/p>
&lt;p>dubbogo 的单机熔断是基于 hystrix-go 实现的,其判定参数有最大并发请求数、超时时间、错误率;其次是保护窗口,是熔断时长,熔断多久后进行服务恢复;第三个是保护性动作,就是在保护时间窗口之内执行什么样的动作,具体实现用户自定义。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p22.jpeg" alt="img">&lt;/p>
&lt;h3 id="优雅退出">优雅退出&lt;/h3>
&lt;p>优雅退出也是邓明同学的大作,可以在网络上搜到相关博客。实现优雅退出的步骤有:&lt;/p>
&lt;ol>
&lt;li>告知注册中心,服务即将关闭,此时等待并处理请求;&lt;/li>
&lt;li>注册中心通知别的客户端,别的客户端停止发送新请求,等待已发请求的响应;&lt;/li>
&lt;li>节点处理完所有接收到的请求并且返回响应后,释放作为服务端相关的组件和资源;&lt;/li>
&lt;li>节点释放作为客户端的组件和资源。&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p23.jpeg" alt="img">&lt;/p>
&lt;p>所以每一步基本上都要给程序一定的时间进行等待,所以等的时间窗口是多少呢?dubbogo 默认每个步骤大概花2秒,总体一个时间窗口是10秒。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p24.png" alt="img">&lt;/p>
&lt;p>基本上在别的 RPC 框架里面,可能不太常见到这种处理。&lt;/p>
&lt;h2 id="五-dubbogo-上云">五 Dubbogo 上云&lt;/h2>
&lt;p>dubbogo 作为微服务框架如何适配 k8s,如何部署?dubbogo 本身是一个 RPC 框架,但是其又有了服务治理能力,这部分能力与 k8s 的部分能力有些重合,不可能为了适配 k8s 就彻底抛弃。目前 Dubbo 官方也没有很好的解决方案供我们参考,所以这里我们 dubbogo 先给出一个简单的常识性的实践方案。下面先分析下 dubbogo 的 interface/service 和 k8s service 两者直接的差别。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p25.jpeg" alt="img">&lt;/p>
&lt;p>k8s service 是许多具有相同服务能力 pod 资源的聚合,它自己的负载均衡算法以及健康检查等功能。而 Dubbo 里面的 interface/service 仅仅是服务 provider 集合,服务治理能力依赖 dubbo 的 directory、router 和 loadbalace 等额外的功能模块。并且Dubbo 服务区分 group/version,还有 provider、consumer 角色等等。Dubbo interface/service 无法与 k8s service 对标,Dubbo interface/service 和其整体服务治理能力才能对标成 k8s service。二者差异这么大,如何将 dubbo 集成到 k8s 中呢?&lt;/p>
&lt;p>k8s 提供了 pod/endpoint/service 三层维度的资源。简单的做法,可以通过监听pod/endpoint/service 三层维度资源的事件,作出合理的处理以达到服务治理的目的。目前我们社区成员王翔提交了一个基于监听 pod 事件来实现服务治理的 pr,优点就是不需要引入额外组件,通过监听 k8s 中最细粒度资源 pod 的事件,通过 k8s apiserver 获取 pod 列表,只是通过 apiserver 使用 etcd 的服务注册和服务通知能力,其他继续使用 Dubbo 的服务治理能力。其优点是模型简单,不需要实现额外的模块,几乎不需要对 Dubbo 作出改动,缺点就是其实无法使用 k8s 自己的健康检查能力,需要自己监听很细粒度的 pod 事件来综合处理服务健康、服务上下线等情况,而且还存在没有使用 k8s service 的事件监听能力,每个 consumer 冗余监听一些不必要监听的事件,加大 apiserver 的网络压力。所以其实现目前来看可能还不是最优解,与 k8s 建议的operator 方式也有一定的背离。社区目前还在讨论新方案,寻求 k8s 最优解,大部分人倾向于采用 k8s 社区推荐的 operator 方案,但是其开发和线上维护成本就上升了。后面两种方式会共存,使用者见仁见智。&lt;/p>
&lt;h2 id="六-互融互通">六 互融互通&lt;/h2>
&lt;p>关于互融互通,Dubbo 明年有个三个重要目标,其中一个目标是与外面的微服务生态进行互联互通,比如说跟 grpc 互通。目前 dubbo 的 grpc 的解决方案已经开放出来,dubbogo 与 grpc 互通的开发工作也几近完成。&lt;/p>
&lt;p>下面左边 dubbogo 的代码生成器工具根据 grpc 的 pb 服务定义文件自动生成的适配 dubbogo 的代码,右边是对应的使用示例。不同于 k8s service 的复杂性,grpc 整体仅仅具有 rpc 能力,没有服务治理能力,所以原始的 grpc 就可以很好的嵌入到 dubbogo 里面,grpc server 的 methodhandler 对我们 dubbogo 来说就是 dubbo invoker,grpc 的一些相关的接口直接跟我们的接口嵌套起来,两个生态就对接起来了。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-go/gochina/p26.jpeg" alt="img">&lt;/p>
&lt;h2 id="七-展望未来">七 展望未来&lt;/h2>
&lt;p>最后就是展望未来,也就是明年的规划。&lt;/p>
&lt;p>明年我们将会很快实现 dubbo router。社区在 8月份已经实现了 router 功能需要的底层的算法模块,但是当时配置中心下发相关的参数的能力还不是很强,所以没有最终完成。最近服务治理配置刚刚支持了 zookeeper 和 apollo,预计很快就可以将 router 的参数通过配置中心下发的形式支持掉。另外,还有 tracing,我们将会引入社区主流的 tracing 方案,以 opentracing 为标准,去集成 opentracing 开源生态的相关能力。第三个是 kubernetes operator,这个就是刚才说的 K8s 的服务调用,我们会基于 operator 的方案做一版新的基于 k8s 的注册中心实现。最后就是云原生生态的融入,即与 istio 的集成,dubbogo 将会成为 dubbo 在 service mesh 生态中的重要角色。&lt;/p>
&lt;p>目前 dubbogo 项目,今年是能 run 起来,质量方面还有很多工作要做,功能基本上到明年可与 dubbo 2.7 补齐,目前已经基本够用。目前落地实践的是 3 个比较典型的公司,一个是携程,还有一个是涂鸦智能。&lt;/p>
&lt;p>dubbogo 本身是一个 go 语言项目,也期待与其他 go 社区的指正或者需求,一起成长。&lt;/p></description></item><item><title>Blog: Dubbo Java 2.7.5 功能解析</title><link>https://dubbo.apache.org/zh-cn/blog/2020/05/18/dubbo-java-2.7.5-%E5%8A%9F%E8%83%BD%E8%A7%A3%E6%9E%90/</link><pubDate>Mon, 18 May 2020 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2020/05/18/dubbo-java-2.7.5-%E5%8A%9F%E8%83%BD%E8%A7%A3%E6%9E%90/</guid><description>
&lt;p>近日,备受瞩目的 Dubbo 2.7.5 版本正式发布,在 2.7.5 版本中,Dubbo 引入了很多新的特性、对现有的很多功能做了增强、同时在性能上也有了非常大的提升,这个版本无论对 Dubbo 社区亦或是开发者来说,都将是一个里程碑式的版本。&lt;/p>
&lt;ul>
&lt;li>应用粒度服务注册【beta】&lt;/li>
&lt;li>HTTP/2 (gRPC) 协议支持&lt;/li>
&lt;li>Protobuf 支持&lt;/li>
&lt;li>性能优化,调用链路性能提升 30%&lt;/li>
&lt;li>支持 TLS 安全传输链路&lt;/li>
&lt;li>优化的消费端线程模型&lt;/li>
&lt;li>新增更适应多集群部署场景的负载均衡策略&lt;/li>
&lt;li>全新的应用开发 API (兼容老版本应用)【beta】&lt;/li>
&lt;li>其他一些功能增强与 bugfix&lt;/li>
&lt;/ul>
&lt;p>首先,从服务发现上,新版本突破以往基于接口粒度的模型,引入了全新的基于应用粒度的服务发现机制 - 服务自省,虽然该机制当前仍处于 beta 阶段,但对于 Dubbo 向整个微服务云原生体系靠齐,都打下了非常好的基础;得益于紧凑的协议设计和代码实现上的优化,Dubbo 一直以来都具有较好的性能表现,在 2.7.5 版本中,性能上有了进一步的提升,根据来自官方维护团队的压测,新版本在调用链路上性能提升达到 30%;云原生微服务时代,多语言需求变得越来越普遍,协议的通用性和穿透性对于构建打通前后端的整套微服务体系也变得非常关键,Dubbo 通过实现 gRPC 协议实现了对 HTTP/2 协议的支持,同时增加了与 Protobuf 的结合。&lt;/p>
&lt;h2 id="1--应用粒度服务注册beta">1. 应用粒度服务注册【beta】&lt;/h2>
&lt;p>从 Java 实现版本的角度来说,Dubbo 是一个面向接口代理的服务开发框架,服务定义、服务发布以及服务引用都是基于接口,服务治理层面包括服务发现、各种规则定义也都是基于接口定义的,基于接口可以说是 Dubbo 的一大优势,比如向开发者屏蔽了远程调用细节、治理粒度更精细等。但基于接口的服务定义同时也存在一些问题,如服务,与业界通用的微服务体系等。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/servicediscovery-old.png" alt="servicediscovery-old.png">&lt;/p>
&lt;p>针对以上问题,2.7.5 版本引入了一种新的服务定义/治理机制:&lt;strong>服务自省&lt;/strong>,简单来说这是一种基于应用粒度的服务治理方案。一个实例只向注册中心注册一条记录,彻底解决服务推送性能瓶颈,同时由于这样的模型与主流微服务体系如 SpringCloud、K8S 等天然是对等的,因此为 Dubbo 解决和此类异构体系间的互联互通清除了障碍。有兴趣进一步了解 Dubbo 服务自省机制如何解决异构微服务体系互联互通问题的,可具体参考我们之前的文章解析《Dubbo 如何成为联通异构微服务体系的最佳服务开发框架》。&lt;/p>
&lt;p>以下是服务自省机制的基本工作原理图。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/servicediscovery-new.png" alt="servicediscovery-new.png">&lt;/p>
&lt;p>要了解更多关于服务自省工作原理的细节,请参与官方文档及后续文章。&lt;/p>
&lt;p>服务自省与当前已有的机制之间可以说是互补的关系,Dubbo 框架会继续保持接口粒度的服务治理的优势,实现接口和应用两个粒度互为补充的局面,兼顾性能、灵活性和通用性,力争使 Dubbo 成为微服务开发的最佳框架。&lt;/p>
&lt;h2 id="2-http2-grpc-协议支持">2. HTTP/2 (gRPC) 协议支持&lt;/h2>
&lt;p>Dubbo RPC 协议是构建在 TCP 之上,这有很多优势也有一些缺点,缺点比如通用性、协议穿透性不强,对多语言实现不够友好等。HTTP/2 由于其标准 HTTP 协议的属性,无疑将具有更好的通用性,现在或将来在各层网络设备上肯定都会得到很好的支持,gRPC 之所以选在 HTTP/2 作为传输层载体很大程度上也是因为这个因素。当前 gRPC 在云原生、Mesh 等体系下的认可度和采用度逐步提升,俨然有成为 RPC 协议传输标准的趋势,Dubbo 和 gRPC 在协议层面是对等竞争的,但是在框架实现上却各有侧重,Dubbo 无疑有更丰富的服务开发和治理体验 。&lt;/p>
&lt;p>Dubbo 支持 gRPC 协议带来的直观好处有:&lt;/p>
&lt;ul>
&lt;li>正式支持基于 HTTP/2 的远程通信,在协议通用性和穿透性上进一步提升。&lt;/li>
&lt;li>支持跨进程的 Stream 流式通信,支持 Reactive 风格的 RPC 编程。&lt;/li>
&lt;li>解决了 gRPC 框架难以直接用于微服务开发的问题,将其纳入 Dubbo 的服务治理体系。&lt;/li>
&lt;li>为联通组织内部已有的 gRPC 或多语言体系提供支持。&lt;/li>
&lt;/ul>
&lt;p>2.7.5 版本开始,gRPC (HTTP/2) 成为 Dubbo 协议体系中的一等公民,对于有需求的开发者完全可以在 Dubbo 开发的微服务体系中启用 gRPC 协议,而不必束缚在 Dubbo 协议自身上,关于这点我们在《Dubbo 如何成为联通异构微服务体系的最佳服务开发框架》一文中也有类似的观点表述。&lt;/p>
&lt;p>关于 Dubbo 中如何开发 grpc (HTTP/2) 服务的细节,请参考文章《Dubbo 在跨语言与协议穿透性等方面的探索》,关于如何开启 TLS 和使用 Reactive RPC 编程,请参见示例。另外,Dubbo 的 go 版本目前同样也提供了对 gRPC 协议对等的支持,具体请关注 dubbogo 社区的发版计划。&lt;/p>
&lt;h2 id="3-protobuf-支持">3. Protobuf 支持&lt;/h2>
&lt;p>支持 Protobuf 更多的是从解决 Dubbo 跨语言易用性的角度考虑的。&lt;/p>
&lt;p>跨语言的服务开发涉及到多个方面,从服务定义、RPC 协议到序列化协议都要做到语言中立,同时还针对每种语言有对应的 SDK 实现。虽然得益于社区的贡献,现在 Dubbo 在多语言 SDK 实现上逐步有了起色,已经提供了包括 Java, Go, PHP, C#, Python, NodeJs, C 等版本的客户端或全量实现版本,但在以上提到的跨语言友好性方面,以上三点还是有很多可改进之处。&lt;/p>
&lt;p>协议上 2.7.5 版本支持了 gRPC,而关于服务定义与序列化,Protobuf 则提供了很好的解决方案。&lt;/p>
&lt;ul>
&lt;li>服务定义。当前 Dubbo 的服务定义和具体的编程语言绑定,没有提供一种语言中立的服务描述格式,比如 Java 就是定义 Interface 接口,到了其他语言又得重新以另外的格式定义一遍。因此 Dubbo 通过支持 Protobuf 实现了语言中立的服务定义。&lt;/li>
&lt;li>序列化。Dubbo 当前支持的序列化包括 Json、Hessian2、Kryo、FST、Java 等,而这其中支持跨语言的只有 Json、Hessian2,通用的 Json 有固有的性能问题,而 Hessian2 无论在效率还是多语言 SDK 方面都有所欠缺。为此,Dubbo 通过支持 Protobuf 序列化来提供更高效、易用的跨语言序列化方案。&lt;/li>
&lt;/ul>
&lt;p>日后,不论我们使用什么语言版本来开发 Dubbo 服务,都可以直接使用 IDL 定义如下服务,具体请参见示例&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-go" data-lang="go">&lt;span style="display:flex;">&lt;span>syntax = &lt;span style="color:#2aa198">&amp;#34;proto3&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>option java_multiple_files = &lt;span style="color:#cb4b16">true&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>option java_package = &lt;span style="color:#2aa198">&amp;#34;org.apache.dubbo.demo&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>option java_outer_classname = &lt;span style="color:#2aa198">&amp;#34;DemoServiceProto&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>option objc_class_prefix = &lt;span style="color:#2aa198">&amp;#34;DEMOSRV&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:#719e07">package&lt;/span> demoservice;
&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">// The demo service definition.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span>service DemoService {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> rpc &lt;span style="color:#268bd2">SayHello&lt;/span> (HelloRequest) &lt;span style="color:#268bd2">returns&lt;/span> (HelloReply) {}
&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>&lt;span style="color:#586e75">// The request message containing the user&amp;#39;s name.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span>message HelloRequest {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">string&lt;/span> name = &lt;span style="color:#2aa198">1&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>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">// The response message containing the greetings
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span>message HelloReply {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">string&lt;/span> message = &lt;span style="color:#2aa198">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="4-性能优化">4. 性能优化&lt;/h2>
&lt;h3 id="41-调用链路优化">4.1 调用链路优化&lt;/h3>
&lt;p>2.7.5 版本对整个调用链路做了全面的优化,根据压测结果显示,总体 QPS 性能提升将近 30%,同时也减少了调用过程中的内存分配开销。其中一个值得提及的设计点是 2.7.5 引入了 Servicerepository 的概念,在服务注册阶段提前生成 ServiceDescriptor 和 MethodDescriptor,以减少 RPC 调用阶段计算 Service 元信息带来的资源消耗。&lt;/p>
&lt;h3 id="42-消费端线程池模型优化">4.2 消费端线程池模型优化&lt;/h3>
&lt;p>对 2.7.5 版本之前的 Dubbo 应用,尤其是一些消费端应用,当面临需要消费大量服务且并发数比较大的大流量场景时(典型如网关类场景),经常会出现消费端线程数分配过多的问题,具体问题讨论可参见以下 issue :&lt;/p>
&lt;p>&lt;a href="https://github.com/apache/dubbo/issues/2013">https://github.com/apache/dubbo/issues/2013&lt;/a>&lt;/p>
&lt;p>改进后的消费端线程池模型,通过复用业务端被阻塞的线程,很好的解决了这个问题。&lt;/p>
&lt;p>&lt;strong>老的线程池模型&lt;/strong>&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/consumer-threadpool0.png" alt="消费端线程池.png">&lt;/p>
&lt;p>我们重点关注 Consumer 部分:&lt;/p>
&lt;ol>
&lt;li>业务线程发出请求,拿到一个 Future 实例。&lt;/li>
&lt;li>业务线程紧接着调用 future.get 阻塞等待业务结果返回。&lt;/li>
&lt;li>当业务数据返回后,交由独立的 Consumer 端线程池进行反序列化等处理,并调用 future.set 将反序列化后的业务结果置回。&lt;/li>
&lt;li>业务线程拿到结果直接返回&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>2.7.5 版本引入的线程池模型&lt;/strong>&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/consumer-threadpool1.png" alt="消费端线程池新.png">&lt;/p>
&lt;ol>
&lt;li>业务线程发出请求,拿到一个 Future 实例。&lt;/li>
&lt;li>在调用 future.get() 之前,先调用 ThreadlessExecutor.wait(),wait 会使业务线程在一个阻塞队列上等待,直到队列中被加入元素。&lt;/li>
&lt;li>当业务数据返回后,生成一个 Runnable Task 并放入 ThreadlessExecutor 队列&lt;/li>
&lt;li>业务线程将 Task 取出并在本线程中执行:反序列化业务数据并 set 到 Future。&lt;/li>
&lt;li>业务线程拿到结果直接返回&lt;/li>
&lt;/ol>
&lt;p>这样,相比于老的线程池模型,由业务线程自己负责监测并解析返回结果,免去了额外的消费端线程池开销。&lt;/p>
&lt;p>关于性能优化,在接下来的版本中将会持续推进,主要从以下两个方面入手:&lt;/p>
&lt;ol>
&lt;li>RPC 调用链路。目前能看到的点包括:进一步减少执行链路的内存分配、在保证协议兼容性的前提下提高协议传输效率、提高 Filter、Router 等计算效率。&lt;/li>
&lt;li>服务治理链路。进一步减少地址推送、服务治理规则推送等造成的内存、cpu 资源消耗。&lt;/li>
&lt;/ol>
&lt;h2 id="5-tls-安全传输链路">5. TLS 安全传输链路&lt;/h2>
&lt;p>2.7.5 版本在传输链路的安全性上做了很多工作,对于内置的 Dubbo Netty Server 和新引入的 gRPC 协议都提供了基于 TLS 的安全链路传输机制。&lt;/p>
&lt;p>TLS 的配置都有统一的入口,如下所示:&lt;/p>
&lt;p>&lt;strong>Provider 端&lt;/strong>&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>SslConfig sslConfig &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> SslConfig();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sslConfig.setServerKeyCertChainPath(&lt;span style="color:#2aa198">&amp;#34;path to cert&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sslConfig.setServerPrivateKeyPath(args&lt;span style="color:#719e07">[&lt;/span>1&lt;span style="color:#719e07">]&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">// 如果开启双向 cert 认证&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">if&lt;/span> (mutualTls) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sslConfig.setServerTrustCertCollectionPath(args&lt;span style="color:#719e07">[&lt;/span>2&lt;span style="color:#719e07">]&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>&lt;/span>&lt;span style="display:flex;">&lt;span>ProtocolConfig protocolConfig &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo/grpc&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>protocolConfig.setSslEnabled(&lt;span style="color:#cb4b16">true&lt;/span>);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Consumer 端&lt;/strong>&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:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>mutualTls) {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sslConfig.setClientTrustCertCollectionPath(args&lt;span style="color:#719e07">[&lt;/span>0&lt;span style="color:#719e07">]&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sslConfig.setClientTrustCertCollectionPath(args&lt;span style="color:#719e07">[&lt;/span>0&lt;span style="color:#719e07">]&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sslConfig.setClientKeyCertChainPath(args&lt;span style="color:#719e07">[&lt;/span>1&lt;span style="color:#719e07">]&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sslConfig.setClientPrivateKeyPath(args&lt;span style="color:#719e07">[&lt;/span>2&lt;span style="color:#719e07">]&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>为尽可能保证应用启动的灵活性,TLS Cert 的指定还能通过 -D 参数或环境变量等方式来在启动阶段根据部署环境动态指定,具体请参见 Dubbo 配置读取规则与 TLS 示例&lt;/p>
&lt;p>Dubbo 配置读取规则:/zh-cn/docs/user/configuration/configuration-load-process.html&lt;/p>
&lt;p>TLS 示例:https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-ssl&lt;/p>
&lt;blockquote>
&lt;p>如果要使用的是 gRPC 协议,在开启 TLS 时会使用到协议协商机制,因此必须使用支持 ALPN 机制的 Provider,推荐使用的是 netty-tcnative,具体可参见 gRPC Java 社区的总结: &lt;a href="https://github.com/grpc/grpc-java/blob/master/SECURITY.md">https://github.com/grpc/grpc-java/blob/master/SECURITY.md&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;p>在服务调用的安全性上,Dubbo 在后续的版本中会持续投入,其中服务发现/调用的鉴权机制预计在接下来的版本中就会和大家见面。&lt;/p>
&lt;h2 id="6-bootstrap-apibeta">6. Bootstrap API【beta】&lt;/h2>
&lt;p>在上面讲《服务自省》时,我们提到了 Dubbo 面向接口的设计,面向接口编程、面向接口做服务发现和服务治理。在引入应用粒度服务发现的同时,2.7.5 版本对编程入口也做了优化,在兼容老版本 API 的同时,新增了新的面向应用的编程接口 - DubboBootstrap。&lt;/p>
&lt;p>以面向 Dubbo API 编程为例,以前我们要这么写:&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>ServiceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>GreetingsService&lt;span style="color:#719e07">&amp;gt;&lt;/span> service1 &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>service1.setApplication(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;first-dubbo-provider&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>service1.setRegistry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://&amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> zookeeperHost &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;:2181&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>service1.export();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ServiceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>GreetingsService&lt;span style="color:#719e07">&amp;gt;&lt;/span> service2 &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>service2.setApplication(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;first-dubbo-provider&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>service2.setRegistry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://&amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> zookeeperHost &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;:2181&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>service2.export();
&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;/code>&lt;/pre>&lt;/div>&lt;p>ApplicationConfig、RegistryConfig、ProtocolConfig 等全局性的配置要在每个服务上去配置;并且从 Dubbo 框架的角度,由于缺少一个统一的 Server 入口,一些实例级别的配置如 ShutdownHook、ApplicationListener、应用级服务治理组件等都缺少一个加载驱动点。&lt;/p>
&lt;p>在引入 DubboBootstrap 后,新的编程模型变得更简单,并且也为解决了缺少实例级启动入口的问题&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>ProtocolConfig protocolConfig &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(&lt;span style="color:#2aa198">&amp;#34;grpc&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>protocolConfig.setSslEnabled(&lt;span style="color:#cb4b16">true&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>SslConfig sslConfig &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> SslConfig();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sslConfig.setXxxCert(...);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bootstrap.application(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;ssl-provider&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://127.0.0.1:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .protocol(protocolConfig)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .ssl(sslConfig);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ServiceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>GreetingsService&lt;span style="color:#719e07">&amp;gt;&lt;/span> service1 &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ServiceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>GreetingsService&lt;span style="color:#719e07">&amp;gt;&lt;/span> service2 &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bootstrap.service(service1).service(service2);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bootstrap.start();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="7-多注册中心集群负载均衡">7. 多注册中心集群负载均衡&lt;/h2>
&lt;p>对于多注册中心订阅的场景,选址时的多了一层注册中心集群间的负载均衡:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/cluster-lb.png" alt="cluster-lb.png">&lt;/p>
&lt;p>在 Cluster Invoker 这一级,我们支持的选址策略有(2.7.5+ 版本,具体使用请参见文档):&lt;/p>
&lt;ul>
&lt;li>
&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-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 来自 preferred=“true” 注册中心的地址将被优先选择,只有该中心无可用地址时才 Fallback 到其他注册中心 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:registry&lt;/span> address=&lt;span style="color:#2aa198">&amp;#34;zookeeper://${zookeeper.address1}&amp;#34;&lt;/span> preferred=&lt;span style="color:#2aa198">&amp;#34;true&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>同 zone 优先&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-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 选址时会和流量中的 zone key 做匹配,流量会优先派发到相同 zone 的地址 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:registry&lt;/span> address=&lt;span style="color:#2aa198">&amp;#34;zookeeper://${zookeeper.address1}&amp;#34;&lt;/span> zone=&lt;span style="color:#2aa198">&amp;#34;beijing&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&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-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 来自北京和上海集群的地址,将以 10:1 的比例来分配流量 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:registry&lt;/span> id=&lt;span style="color:#2aa198">&amp;#34;beijing&amp;#34;&lt;/span> address=&lt;span style="color:#2aa198">&amp;#34;zookeeper://${zookeeper.address1}&amp;#34;&lt;/span> weight=&lt;span style="color:#2aa198">”100“&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:registry&lt;/span> id=&lt;span style="color:#2aa198">&amp;#34;shanghai&amp;#34;&lt;/span> address=&lt;span style="color:#2aa198">&amp;#34;zookeeper://${zookeeper.address2}&amp;#34;&lt;/span> weight=&lt;span style="color:#2aa198">”10“&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>默认,stick to 任意可用&lt;/p>
&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>关于多注册中心订阅模型,Dubbo 同时也提供了 Multi-Registry 合并的解决思路,欢迎参与到以下 PR 的讨论中: &lt;a href="https://github.com/apache/dubbo/issues/5399">https://github.com/apache/dubbo/issues/5399&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;h2 id="8-其他功能增强">8. 其他功能增强&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>新增地址变更事件通知接口,方便业务侧感知地址变化&lt;/p>
&lt;/li>
&lt;li>
&lt;p>新增外围配置加载入口,方便开发者在启动阶段定制服务启动参数&lt;/p>
&lt;/li>
&lt;li>
&lt;p>config 模块重构&lt;/p>
&lt;/li>
&lt;li>
&lt;p>parameters 扩展配置增强&lt;/p>
&lt;/li>
&lt;li>
&lt;p>其他一些 Bugfix&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>从 Dubbo 框架自身的角度来说,2.7.5 版本也做了很多的重构与优化(比如说 config 模块的重构),这些改动对于使用者来说并无感知的,但是从优化整个 Dubbo 代码内部结构的角度来说,这些改动对后续的功能开发与新机制的引入是一个很好的铺垫。&lt;/p>
&lt;h2 id="9-总结与展望">9. 总结与展望&lt;/h2>
&lt;p>在后续的版本中,Dubbo 会持续快速的优化与迭代,主要从以下几个方面发力:&lt;/p>
&lt;ul>
&lt;li>继续探索服务自省成为 Dubbo 主推的服务治理模型。&lt;/li>
&lt;li>对于企业用户关心的微服务解决方案场景,会持续推进框架的演进,包括当前正在开发的配置、服务鉴权机制、熔断等功能。后续还会尝试联合社区推动周边配套设施如网关、治理平台 Admin 等的建设,非常期待社区能踊跃参与到此部分的建设中。&lt;/li>
&lt;li>性能优化上。主要从两个方面着手,一是调用链路的持续优化,同时继续探索新的更通用的 RPC 协议;另一方面是在服务治理推送机制上的优化,以进一步提高 Dubbo 在大规模服务地址推送场景下的表现。&lt;/li>
&lt;li>云原生方向。接下来的版本将重点探索,1. 如何更好的支持 Dubbo 在 Kubernetes 上的部署和服务治理;2. 对于混合部署的场景,如传统 VM 和 K8S 体系混合部署、SDK Dubbo 与 Mesh 混合部署的场景,如何提供更好的支持以实现混部场景的长期共存或迁移。&lt;/li>
&lt;/ul></description></item><item><title>Blog: 从 2019 到 2020,Apache Dubbo 年度回顾与总结</title><link>https://dubbo.apache.org/zh-cn/blog/2020/05/11/%E4%BB%8E-2019-%E5%88%B0-2020apache-dubbo-%E5%B9%B4%E5%BA%A6%E5%9B%9E%E9%A1%BE%E4%B8%8E%E6%80%BB%E7%BB%93/</link><pubDate>Mon, 11 May 2020 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2020/05/11/%E4%BB%8E-2019-%E5%88%B0-2020apache-dubbo-%E5%B9%B4%E5%BA%A6%E5%9B%9E%E9%A1%BE%E4%B8%8E%E6%80%BB%E7%BB%93/</guid><description>
&lt;p>非常感谢大家对 Dubbo 社区的关注,通过这篇文章我们将:总结过去一年 Dubbo 社区取得的成绩,包括社区和框架演进两个方面;展望未来 Dubbo 社区和框架的新的规划(roadmap)。社区建设是推动 Dubbo 健康持续发展的一个非常重要的环节,我们需要与社区保持良性的互动、有活跃的贡献者、有积极的富有建设性的讨论,而整个 Dubbo 社区过去一年在这方面都做的不错;在框架演进上,我们主要发布了 2.7.0 - 2.7.5 共 6 个特性版本,功能层面涵盖编程模型、协议、服务治理、性能优化等多个方面;除了已经发布的功能外,我们在 Dubbo 3.0 协议、服务自省和云原生等方向上也做了深入的探索,对这些方向的支持将是 Dubbo 接下来的重要工作方向,希望能通过这篇文章将其中更详细的思考和计划同步给大家。&lt;/p>
&lt;h2 id="社区回顾">社区回顾&lt;/h2>
&lt;p>回顾 Dubbo 社区过去一年的发展,其中一个重要的节点就是 2019 年 5 月从 Apache 孵化毕业。成为第二个由 Alibaba 捐献后从 Apache 毕业的项目,我有幸参与到了从重启开源、进入 Apache 孵化到毕业的整个过程,社区在此过程中做了大量的工作,包括邮件列表建设、代码规范检查、文档和代码国际化、issue/pr 处理等,这些一方面是 Apache 社区要求的工作,同时也为推动 Dubbo 的发展起到了正面的作用。&lt;/p>
&lt;p>在从 Apache 毕业之后,Dubbo 相关的项目也进行了迁移,都迁移到了 &lt;a href="https://github.com/apache?utf8=%E2%9C%93&amp;amp;q=dubbo&amp;amp;type=&amp;amp;language=">Apache&lt;/a> 组织之下:&lt;/p>
&lt;p>Dubbo 社区的项目总共有 24 个之多,维护如此多的项目,并不是单纯靠几个活跃的开发者就能做到的,而是靠整个社区努力的结果。我总结了过去一年提名的所有 Committer/PMC,总过有 27 人获得提名(23 名 committer、4 名 PMC),通过下方的饼状图可以看出,只有不到 20% 的贡献者是来自于 Alibaba,而 80% 以上是来自各个不同组织的开发者或爱好者。这样的 Committer 分布,是加入 Apache 带给 Dubbo 社区的一个最重要的变化之一:Dubbo 项目是属于整个社区的,反映的是不同组织不同开发者的共同诉求,它的发展不是由一个公司控制或决定的,而是由社区共同讨论后决定的。如果你对参与到 Dubbo 社区感兴趣,都可以参与到 Dubbo 发展的讨论、决策和 coding 中来,也非常期待各位能成为下一个 Committer。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/community-distribution.png" alt="community distribution">&lt;/p>
&lt;p>过去一年 Dubbo 社区组织了超过 10 场的线下 meetup 活动,覆盖了国内基本所有的开发者聚集的城市,与广大 Dubbo 开发者和使用者保持了密切交流。通过这些线下或线上的直播活动,分享了超过 100 个 topic 的演讲,深度讲解了 Dubbo 社区最新动态、功能模块开发和近期规划等。并且在所有的这些主题演讲中,绝大多数都是通过社区采集的方式,最终由 Dubbo 的深度企业分享的实践主题,其中典型的代表包括携程、工商银行、考拉、信用算力等。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/community-meetup.png" alt="community meetup">&lt;/p>
&lt;p>从 Github 上来看,Dubbo 在过去一年也受到了非常高的关注度,一个重要的里程碑是 Star 数突破 3w,相比重启开源时增长了近 5 倍;贡献者由最初的几十个增长到现在的 282 个,而这其中有六七十个已经被提名为 committer,不论是贡献者数量还是 committer 比例都得到很大的提升;另一个数据是发布的版本,总共发布了 64 个版本,大家如果要了解每个版本的具体信息,也可以从这里点进去查看。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/community-github.png" alt="community github">&lt;/p>
&lt;p>当前社区维护的大版本主要有 3 个,分别是 2.5.x 2.6.x 和 2.7.x。&lt;/p>
&lt;p>其中,2.7.x 是我们的主要开发版本,在过去的一年共发布了 6 个版本(2.7.0 - 2.7.5),每个版本都带来了一些值得关注的特性或功能升级,涵盖从编程模型、服务治理、性能到协议的多个方面的增强。&lt;/p>
&lt;p>2.6.x 版本则定位为 bugfix 版本,过去一年共发布了 3 个版本,主要以修复问题和安全漏洞为主,并没有增加什么新 feature,因此这一系列的版本在稳定性上是得到保证的。&lt;/p>
&lt;p>2.5.x 版本当前从去年初开始已宣布 EOF,只做安全修复;而到了下半年已经完全停止了维护。还在使用这个版本的用户建议尽快升级到 2.6 或 2.7 版本。&lt;/p>
&lt;p>关于 2.6 和 2.7 版本的用户分布情况,目前并没有官方的统计数据,但是根据我们从 issue 分布及一些深度用户的跟踪情况来看,这两个版本的使用分布大概是 40% - 60% 的状态。同时我们还观察到一个趋势,即很大一部分 2.6 的用户都已经开始调研升级到 2.7 版本或在升级的过程中,毕竟一个框架是否能很好的满足业务开发诉求,一个重要的因素是其是否不断的有功能的加入,是否能跟进新的技术趋势,2.6 版本已很难满足这些诉求。&lt;/p>
&lt;p>对于很多开发者来说,要升级到 2.7 版本,当前最大的顾虑即是其稳定性。因为 2.7 每个版本都会增加很多新内容且迭代速度较快,要保证每个发布版本的稳定性对社区来说也是一个充满挑战的事情。为了方便用户更好的完成升级评估,我们近期在 github 上列出了单独列了一个 issue 来统计现在包括未来版本的稳定性:&lt;a href="https://github.com/apache/dubbo/issues/5669">Dubbo 各版本总结与升级建议 #5669&lt;/a>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>&lt;/th>
&lt;th>&lt;strong>版本&lt;/strong>&lt;/th>
&lt;th>&lt;strong>重要功能&lt;/strong>&lt;/th>
&lt;th>&lt;strong>升级建议&lt;/strong>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>2.7.5&lt;/td>
&lt;td>服务自省 HTTP/2(gRPC) Protobuf TLS 性能优化 &lt;a href="https://github.com/apache/dubbo/releases/tag/dubbo-2.7.5">https://github.com/apache/dubbo/releases/tag/dubbo-2.7.5&lt;/a>&lt;/td>
&lt;td>不建议大规模生产使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2&lt;/td>
&lt;td>2.7.4.1&lt;/td>
&lt;td>&lt;a href="https://github.com/apache/dubbo/releases/tag/dubbo-2.7.4.1">bugfixes and enhancements of 2.7.3&lt;/a>&lt;/td>
&lt;td>&lt;strong>推荐生产使用&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>2.7.3&lt;/td>
&lt;td>&lt;a href="https://github.com/apache/dubbo/releases/tag/dubbo-2.7.3">bigfixes of and enhancements of 2.7.2&lt;/a>&lt;/td>
&lt;td>&lt;strong>推荐生产使用&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4&lt;/td>
&lt;td>2.7.2&lt;/td>
&lt;td>&lt;a href="https://github.com/apache/dubbo/releases/tag/dubbo-2.7.2">bigfixes of and enhancements of 2.7.1&lt;/a>&lt;/td>
&lt;td>不建议大规模生产使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>2.7.1&lt;/td>
&lt;td>&lt;a href="https://github.com/apache/dubbo/releases/tag/dubbo-2.7.1">bigfixes of and enhancements of 2.7.0&lt;/a>&lt;/td>
&lt;td>不建议大规模生产使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>2.7.0&lt;/td>
&lt;td>异步编程模型 - 消费端/提供端异步 服务治理规则增强 简化的注册模型 配置中心、元数据中心 package 重构 &lt;a href="https://github.com/apache/dubbo/releases/tag/dubbo-2.7.0">https://github.com/apache/dubbo/releases/tag/dubbo-2.7.0&lt;/a>&lt;/td>
&lt;td>beta 版本,2.6.x 重构后首个版本&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>其中 2.7.5 版本预计将在接下来的 1-2 个版本之后逐步达到稳定状态。&lt;/p>
&lt;p>对于后续的版本是否通过标识性的后缀如 -beta、RC 等来区分不同阶段的发布版本,社区也有过类似的讨论,后续我们将视未来发展情况而定。&lt;/p>
&lt;h2 id="重点功能回顾">重点功能回顾&lt;/h2>
&lt;p>接下来针对 2.7 版本中发布的新功能,从编程模型、性能优化、服务治理、传输协议、生态发展等几个角度来做具体的讲解。&lt;/p>
&lt;h3 id="编程模型">编程模型&lt;/h3>
&lt;p>Dubbo 中涉及编程模型相关的改动主要是以下几点:&lt;/p>
&lt;ul>
&lt;li>CompletableFuture 异步方法签名的服务&lt;/li>
&lt;li>服务端异步支持 API&lt;/li>
&lt;li>IDL 跨语言服务定义&lt;/li>
&lt;li>Reactive-style 方法签名的服务&lt;/li>
&lt;/ul>
&lt;p>首先,我们先来看一下异步化相关的增强。
Dubbo Java 版本的典型服务定义如下:&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">HelloService&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Synchronous style&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String &lt;span style="color:#268bd2">sayHello&lt;/span>(String name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果要实现消费端的异步服务调用,则需要单独配置异步标识,并通过 RpcContext API 配合使用&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>String result &lt;span style="color:#719e07">=&lt;/span> helloService.sayHello(&lt;span style="color:#2aa198">&amp;#34;world&amp;#34;&lt;/span>); &lt;span style="color:#586e75">// result is always null&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Future future &lt;span style="color:#719e07">=&lt;/span> RpcContext.getContext().getFuture();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 2.7 版本之后,我们可以直接定义如下方法接口,以更直观的实现消费端/提供端异步:&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">HelloService&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Asynchronous style&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CompletableFuture&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">sayHello&lt;/span>(String name);
&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>CompletableFuture&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span> future &lt;span style="color:#719e07">=&lt;/span> helloService.sayHello(&lt;span style="color:#2aa198">&amp;#34;world&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>以上示例都是基于 Java Interface 来描述 Dubbo 服务的,如果要和多语言异构的微服务实现互调,则服务又需要用相应语言的方式重新定义一遍,无法实现跨语言的服务复用;另外跨语言的序列化也是需要注意的一个问题。&lt;/p>
&lt;p>为此 2.7.5 版本引入了对 IDL + Protobuf 的支持,以解决跨语言的服务定义问题,具体可参见示例:&lt;/p>
&lt;p>&lt;a href="https://github.com/apache/dubbo-samples/tree/master/3-extensions/serialization/dubbo-samples-protobuf">dubbo-samples-protobuf&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/service-idl.png" alt="service idl">&lt;/p>
&lt;p>对 Reactive-style API 的支持则和上面 CompletableFuture 有些类似,允许用户定义 RxJava、Reactor API 的服务接口&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/idl-dubbo-compiler.png" alt="idl dubbo compiler">&lt;/p>
&lt;p>但是需要注意的一定是,由于外围的 Reactive API 需要有底层传输协议的支持才有意义,因此,目前 Reactive API 只能在使用 gRPC 协议时才有意义,具体请参见示例以及下面关于 ”&lt;a href="https://github.com/apache/dubbo-samples/tree/master/99-integration/dubbo-samples-grpc/dubbo-samples-rxjava">Dubbo 对 gRPC 的支持&lt;/a>” 一节的讲解。&lt;/p>
&lt;h3 id="性能优化">性能优化&lt;/h3>
&lt;p>2.7 版本在性能优化方面也做了很多的工作,对 Dubbo 业务系统的吞吐量、调用链路响应速度、服务治理链路性能等都有明显提升。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>系统吞吐量&lt;/p>
&lt;p>和提升系统吞吐量相关的增强主要有框架的全异步化改造、消费端线程模型优化、引入 Stream 语义协议等。&lt;/p>
&lt;p>全异步化改造,很关键的一点是 Filter 链路的异步化,之前的 Filter 只有一个同步的 invoke 方法,现在为了支持异步回调,增加了 Listener 回调监听器,从而可以实现对异步调用结果的监听与拦截。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/filter.png" alt="filter">&lt;/p>
&lt;p>关于消费端线程模型的优化,对于网关类应用,需要消费大量服务的应用,都会在系统稳定性和性能表现上有很大提升,其优化后的总体工作原理图所下所示,具体解析可以参见之前发布的文章:&lt;a href="https://dubbo.apache.org/zh-cn/docsv2.7/user/examples/consumer-threadpool/">《消费端线程池模型》&lt;/a>&lt;/p>
&lt;p>老线程模型工作原理:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/consumer-threadpool0.png" alt="consumer threadpool">&lt;/p>
&lt;p>新线程模型工作原理:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/consumer-threadpool1.png" alt="consumer threadpool new">&lt;/p>
&lt;ol start="2">
&lt;li>
&lt;p>RPC 调用链路&lt;/p>
&lt;p>从 2.7.0 到 2.7.5,从我们的测试数据来看,通过一系列的优化调用链路性能提升在 30% 以上。总体来说,优化的目标是减少调用过程中的内存分配和 cpu 计算,主要有两个方面的改造:&lt;/p>
&lt;ul>
&lt;li>服务元数据静态化,在启动阶段尽可能多的计算并缓存,以减少调用过程中的计算成本,加快响应速度&lt;/li>
&lt;li>减少调用过程中的 URL 操作产生的内存分配&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>服务治理链路&lt;/p>
&lt;p>服务治理链路上主要有以下几点值得关注:地址推送、服务治理规则推送、服务治理规则计算、路由选址等,尤其是在大规模服务集群的场景下,以上每个点都可能成为性能或稳定性瓶颈。在 2.7 版本中,目前着重对 “地址推送” 相关计算路径做了优化,简单概括起来主要是以下几点:&lt;/p>
&lt;ul>
&lt;li>地址推送事件合并,避免短时间重复计算&lt;/li>
&lt;li>全量地址推送时,避免 URL 重新分配&lt;/li>
&lt;li>在 URL 合并链路上,引入 URL 可变状态,避免 URL 拷贝造成的开销&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="服务治理">服务治理&lt;/h3>
&lt;p>服务治理也是 2.7 版本中着重增强的一个模块。总体上可以分为三部分&lt;/p>
&lt;ul>
&lt;li>普通路由规则相关的优化和增强&lt;/li>
&lt;li>增强对跨区域、跨机房部署的路由支持&lt;/li>
&lt;li>元数据中心、配置中心&lt;/li>
&lt;/ul>
&lt;p>我们针对这三部分逐步展开讲解。以下是 2.7 版本路由规则的几个例子。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/route-app.png" alt="route app">&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/route-service.png" alt="route service">&lt;/p>
&lt;p>其中,最明显的一个变化是路由规则都以 YAML 进行了重写,并且后续所有的路由规则都计划以 YAML 为基本描述语言;相比于之前路由规则直接存储于注册中心,在 2.7 版本中增加了配置中心后,新版本的路由规则默认将存储在于独立的配置中心,配置格式推送机制都得到了优化;另外,2.7 版本中还增加了应用粒度的路由规则,方便从整个应用的角度去设置流量规则。&lt;/p>
&lt;p>新增加的跨注册中心的路由机制,可以实现调用流量在多个注册中心间的负载均衡,对于需要做异地容灾、同机房优先或者注册中心迁移的场景比较有用处。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/cluster-lb.png" alt="cluster load balance">&lt;/p>
&lt;p>当前支持的注册中心集群负载均衡策略有:&lt;/p>
&lt;ul>
&lt;li>同区域优先&lt;/li>
&lt;li>权重轮询&lt;/li>
&lt;li>指定优先级&lt;/li>
&lt;li>任意可用&lt;/li>
&lt;/ul>
&lt;p>元数据中心存储了 Dubbo 服务方法定义的描述,目前主要的用途是服务测试,将来也可用作服务 API 管理、网关参数映射等。&lt;/p>
&lt;p>新增的配置中心主要有两个用途:存储/推送配置规则、应用配置托管,接下来着重讲解应用配置托管相关功能,看其对 Dubbo 的开发与运维配置的影响。Dubbo 当前支持 JVM 动态参数、配置中心、API、本地配置文件等几种配置源,他们之间按照优先级从高到低的顺序实现配置覆盖,如下图所示:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/config.png" alt="config">&lt;/p>
&lt;p>配置中心相当于是共享版本的 &lt;code>dubbo.properties&lt;/code> 的远程托管,其中,key 值有特定的命名规范:&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-properties" data-lang="properties">&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>dubbo.{config-type}[.{config-id}].{config-item} &lt;span style="color:#2aa198">{config-item-value}&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>dubbo.service.{interface-name}[.{method-name}].{config-item} &lt;span style="color:#2aa198">{config-item-value}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dubbo.reference.{interface-name}[.{method-name}].{config-item} &lt;span style="color:#2aa198">{config-item-value}&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>dubbo.{config-type}s.{config-id}.{config-item} &lt;span style="color:#2aa198">{config-item-value}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="传输协议">传输协议&lt;/h3>
&lt;p>2.7 版本在 RPC 协议层和序列化层进行了扩展,RPC 协议层增加了对 gRPC 协议的支持,序列化层增加了对 Protobuf 协议的支持。&lt;/p>
&lt;p>支持 gRPC 其中一个重要原因是其基于 HTTP/2 协议构建,HTTP/2 协议作为 HTTP 标准协议,在各个层次的网络设备及网关代理上都得到了很好的支持,因此具有更好的穿透性和通用性。通过支持 gRPC 协议,对于期望使用 HTTP/2 的 Dubbo 用户提供了一种传输协议选择。&lt;/p>
&lt;p>gRPC 在 HTTP/2 上构建了 Stream 的 RPC 语义,支持 Request - Response、Stream - Response、Request - Stream、Bi-Stream 等多种语义,能满足不同的业务调用场景。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/service-idl2.png" alt="service idl2">&lt;/p>
&lt;p>在 Dubbo 的设计中,所有的 RPC 协议都处于一个平等的地位,无论是自有的 Dubbo 协议,还是扩展的其他三方协议如 Thrift、Hessian、gRPC 等,得益于这样的设计,我们可以扩展任何新协议支持。关于如何扩展 RPC 协议及其应用场景,请参见之前发布的&lt;a href="https://mp.weixin.qq.com/s/-fvDeGlCLjz0n60naZJnQg">《使用 Dubbo 连接异构微服务体系》&lt;/a>文章。&lt;/p>
&lt;p>Protobuf 序列化协议支持更多的是考虑其在跨语言、安全性和性能方面。&lt;/p>
&lt;h2 id="roadmap">Roadmap&lt;/h2>
&lt;p>未来社区将会持续推动 Dubbo 的发展,重点来说有以下几个方向:&lt;/p>
&lt;ul>
&lt;li>继续增强服务治理相关能力,以更好的满足微服务开发和运维的需求;&lt;/li>
&lt;li>协议层面,着手研发下一代的 RPC 协议,新协议将提供更丰富的如 Stream、Flow Control 等内置语义,同时将具有更好的扩展性、网关的友好性等;&lt;/li>
&lt;li>基于应用粒度的服务发现机制,&lt;/li>
&lt;li>云原生带来了底层基础设施的变化,同时在此基础上衍生出了如 ServiceMesh 的微服务解决方案,我们需要继续探索 Dubbo ;&lt;/li>
&lt;/ul>
&lt;h3 id="微服务功能">微服务功能&lt;/h3>
&lt;p>目前正在开发或规划中的微服务功能有服务鉴权、熔断、路由规则增强等,预计将在接下来的 2.7.6 等版本中陆续发布。后续也将会根据社区中的诉求,陆续增加其他的微服务功能支持。&lt;/p>
&lt;p>以当前正在开发的服务鉴权功能为例,这是社区中很多 Dubbo 使用者在实际使用中遇到的需求:虽然 Dubbo 服务主要是在内部运转,但有些服务仍期望只对部分场景或用户开放,比如某些涉及到敏感数据操作的服务,这就需要有鉴权能力的支持。&lt;/p>
&lt;p>&lt;a href="https://github.com/apache/dubbo/issues/5461">Dubbo调用鉴权认证方案 #5461&lt;/a> 中有关于 Dubbo 当前正在开发中的鉴权功能的详细讨论,总体来说 Dubbo 提供的鉴权功能约束了 Dubbo 侧鉴权的基本流程,这是一套通用鉴权的方案,在 token 计算、校验等环节都被设计为可扩展的,因此可以方便的对接到各种认证及权限管理系统。&lt;/p>
&lt;p>非常感谢社区的活跃开发者,现就职于爱奇艺的 &lt;a href="https://github.com/CodingSinger">CodingSinger&lt;/a>,其是鉴权模块的发起者和主要开发贡献者。&lt;/p>
&lt;h3 id="协议---30">协议 - 3.0&lt;/h3>
&lt;p>以下是 Dubbo 2.0 协议,我们之前已经在多个场合做过详细的讲解&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/grpc/dubbo-ptotocol.png" alt="Dubbo Protocol 2.0">&lt;/p>
&lt;p>Dubbo 2.0 协议在云原生、mesh 等场景下暴露出一些问题,如:&lt;/p>
&lt;ul>
&lt;li>协议缺少扩展性&lt;/li>
&lt;li>RPC 协议层和 payload 耦合在一起&lt;/li>
&lt;li>基于 TCP 构建的二进制私有协议&lt;/li>
&lt;li>缺少 Stream 语义的支持&lt;/li>
&lt;/ul>
&lt;p>所以,针对以上问题,新一代的 Dubbo 协议将突出以下特点:&lt;/p>
&lt;p>&lt;strong>Reactive Stream&lt;/strong>
Reactive Stream 引入 RPC,带来更丰富的通信语义和 API 编程模型支持,如 Request-Stream、Bi-Stream 等&lt;/p>
&lt;p>&lt;strong>协议升级&lt;/strong>
协议内置应⽤层协议协商机制,包括自建协议升级机制、ALPN 等,以方面将来协议升级或兼容老版本协议的迁移&lt;/p>
&lt;p>&lt;strong>HTTP/2&lt;/strong>
微服务云原⽣生场景下,基于 HTTP/2 构建的通信协议具有更更好的通⽤用性和穿透性&lt;/p>
&lt;p>&lt;strong>可扩展&lt;/strong>
协议可扩展,区分协议头 Metadata 与 RPC 方法的参数&lt;/p>
&lt;p>&lt;strong>多语⾔支持&lt;/strong>
如通过支持 Protobuf 提供了更完善的 跨语言服务定义 与 序列化传输 的支持&lt;/p>
&lt;p>&lt;strong>Mesh&lt;/strong>
协议对 Mesh 更友好,方便完成与 Mesh 的协作,包括流量控制机制、应用层配置协商等&lt;/p>
&lt;p>&lt;strong>流量控制&lt;/strong>
协议内置流控机制,支持类似 Reqctive Stream 的 Request (n) 流控机制&lt;/p>
&lt;p>&lt;strong>协议通用性&lt;/strong>
兼顾通用性与性能,支持协议能在各种设备上运行&lt;/p>
&lt;h3 id="服务自省---应用粒度的服务注册">服务自省 - 应用粒度的服务注册&lt;/h3>
&lt;p>Dubbo 最大的优势之一在于其易用性,其面向接口(RPC 方法)的编程模型。同时,面向接口的治理也带来了一些问题:&lt;/p>
&lt;ul>
&lt;li>地址数量成倍增长,给地址推送带来很大压力&lt;/li>
&lt;li>和主流微服务体系模型不匹配,如 SpringCloud、Kubernetes 等&lt;/li>
&lt;/ul>
&lt;p>为此,我们计划引入应用粒度的服务注册机制,主要有以下几个重点:&lt;/p>
&lt;ul>
&lt;li>注册中心按 “应用 - 实例IP” 组织,不再关心 RPC 接口同步&lt;/li>
&lt;li>引入独立的元数据服务完成 RPC 接口同步工作&lt;/li>
&lt;/ul>
&lt;p>以下是应用粒度服务注册(服务自省)的基本工作原理,请持续关注后续对这部分的具体解析和开发进展。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/servicediscovery-new.png" alt="service discovery new">&lt;/p>
&lt;h3 id="云原生">云原生&lt;/h3>
&lt;p>云原生带来了底层基础设施,应用开发、部署和运维等全方位的变化:&lt;/p>
&lt;p>&lt;strong>基础设施&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>基础设施调度机制变化,带来运维(生命周期)、服务治理等方面的变化。&lt;/li>
&lt;li>服务发现能力下沉, Kubernetes 抽象了 Native Service Discovery。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Service Mesh - 云原生微服务解决方案&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Mesh 为跨语言、sdk 升级等提供了解决方案,Dubbo sdk 要与 Mesh 协作,做到功能、协议、服务治理等多方便的适配。&lt;/li>
&lt;li>Mesh 尚未大规模铺开,且其更适合对流量管控更关注的应用,传统 SDK 的性能优势仍旧存在,两者混部迁移场景可能会长期存在。&lt;/li>
&lt;/ul>
&lt;p>从应用场景上,Dubbo 可能的部署环境包括:&lt;/p>
&lt;ol>
&lt;li>不使用 Kubernetes Native Service,Kubernetes 只作为容器编排调度设施,继续使用 Dubbo 自建的服务注册、发现机制。&lt;/li>
&lt;li>复用 Kubernetes Native Service,Dubbo 不再关心服务注册,Dubbo Client 负责服务发现与流量分配。&lt;/li>
&lt;li>Dubbo sdk 往 Mesh 迁移,一方面要做到适应 Mesh 架构,成为 Mesh 体系下的 RPC 编程和通信方案;另一方面要做到 Dubbo 与 Mesh 架构长期共存,互相打通服务发现和治理体系。&lt;/li>
&lt;li>Kubernetes 上与云下混合部署的平滑迁移支持,包括服务发现的统一与网络通信方案的打通。&lt;/li>
&lt;/ol>
&lt;p>从 Dubbo 功能划分上,将着重从以下方面提供对云原生基础设施的支持:&lt;/p>
&lt;p>&lt;strong>生命周期:&lt;/strong> Dubbo 与 Kubernetes 调度机制绑定,保持服务生命周期与 Pod 容器等生命周期的自动对齐
&lt;strong>治理规则:&lt;/strong> 服务治理规则在规则体、规则格式方面进行优化,如规则体以 YAML 描述、取消过滤规则对 IP 的直接依赖,定义规则特有的 CRD 资源等。
&lt;strong>服务发现:&lt;/strong> 支持 K8S Native Service 的服务发现,包括 DNS、API-Server,支持 xDS 的服务发现
&lt;strong>Mesh 架构协作:&lt;/strong> 构建下一代的基于 HTTP/2 的通信协议,支持 xDS 的标准化的数据下发&lt;/p></description></item><item><title>Blog: 遇见Dubbo</title><link>https://dubbo.apache.org/zh-cn/blog/2019/01/26/%E9%81%87%E8%A7%81dubbo/</link><pubDate>Sat, 26 Jan 2019 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2019/01/26/%E9%81%87%E8%A7%81dubbo/</guid><description>
&lt;p>我是一个有Dubbo情节的程序员。&lt;/p>
&lt;p>Dubbo以不同方式,陪伴了我时间不长的整个代码生涯。不久前,通过社区投票,我被选举为&lt;code>Committer&lt;/code>。当时我在朋友圈发了一句话,也是贯穿我从开始使用Dubbo、研究Dubbo、贡献Dubbo到最后成为&lt;code>Committer&lt;/code>的全过程,一直为我提供内心无与伦比愉悦的源泉:成长这种事,能看见脚印特别幸福。&lt;/p>
&lt;p>今天来个回忆杀,把我和Dubbo的那些事拿出来说说。&lt;/p>
&lt;h2 id="小白">小白&lt;/h2>
&lt;p>我知道Dubbo,是在我大三翘课出去实习的时候,那个时候是无知的,我眼里最牛的人就是能熟练使用各种配置,精通SSH框架的人。就是在那种情况下,我外出实习,遇到了一群影响我至今的人。当时也是机缘巧合,我们进行了两个非常小的模块的服务化改造。那时的团队除了我们老大,全是一群新兵蛋子,老大指哪我们打哪。老大说,就用Dubbo吧,从那时候开始,我才知道,哦!原来还有一种东西叫做RPC,还有个阿里巴巴的RPC框架叫Dubbo。&lt;/p>
&lt;p>苦于当时非常有限的水平和高强度的工作,我和Dubbo的缘分也就停留在一面之缘的程度——要说认识谈不上,说不认识也牵强。&lt;/p>
&lt;h2 id="contributor">Contributor&lt;/h2>
&lt;p>我在二维火任职的一年算是我Dubbo生涯里承上启下的一年。二维火当时自己维护了一个Dubbo的分支,有一群对Dubbo非常了解的人。那时候,工作结束搞Dubbo,周六加班研究Dubbo。看源码,看不懂就debug一下,debug也不明白就问,问人,问google,里外折腾了个遍。&lt;/p>
&lt;p>后来毕业加入网易云音乐。大概是今年五月份的时候,我发现了一个Dubbo的小bug,并且给Dubbo提交了pull request。在第一次被merge之后,非常受鼓舞,这才有了后续的故事。后来,回看这第一次提交,真的算是我和Dubbo的一个拐点,拐弯之后,我才逐渐走上一条成为&lt;code>Committer&lt;/code>的路。&lt;/p>
&lt;p>可能很多人看到这里要望而却步了,这也是做开源给很多人留下的固有的印象——是不是没发现BUG就不能提交pull request,不能做贡献?其实完全不是的,这里给大家敲黑板划重点:其实很多贡献者的第一次贡献,贡献的并非代码,而是文档修改或者单元测试。相比于BUG或者新的Feature,单测和文档上的修复门槛就比较低了。&lt;/p>
&lt;p>我自己的方法论就是:&lt;strong>先尝试增加单元测试,写单测的时候顺手debug+看代码。或者多看文档,了解框架的同时,发现错别字、语意不明或者文档上的链接干脆点不开的情况,直接提交PR到对应的仓库&lt;/strong>。&lt;/p>
&lt;p>万事开头难。第一次被merge代码,你就可以成为一个&lt;code>Contributor&lt;/code>了。&lt;code>Contributor&lt;/code>很多,但是&lt;code>Committer&lt;/code>很少,下面继续说怎么从一个&lt;code>Contributor&lt;/code>成长为独当一面的&lt;code>Committer&lt;/code>。&lt;/p>
&lt;h2 id="committer">Committer&lt;/h2>
&lt;p>做开源和写代码一样,都不是一朝一夕的事情,而是量变促成质变的过程。这是一个没捷径可走的过程,欲带皇冠必承其重。身后的Dubbo功底自不必多说,这个部分主要是想跟大家说一下除了钻研和热爱之外,其他需要注意的地方。&lt;/p>
&lt;p>首先是多提交高质量PR。任何一个PR都会被review,代码中的问题,思路上的偏差,都会被指正。提交PR是一个反复琢磨的过程。PR的质量不能简单的归结于新增了多少行代码,高质量的PR一定是经过缜密思考的,为什么删除代码,新增的代码有什么意义,修改之后有什么效果等等。希望大家更加重视质量而非数量,眼光放长远,相信你的收获一定会非常大!&lt;/p>
&lt;p>第二个就是,我们需要培养一种思维方式——Apache Way。一句话概括就是&lt;strong>社区重于代码&lt;/strong>。Apache是一个注重社区的的开源组织,其行为方式相比于目前我们的开发方式,还是有所不同,这里我举一个Apache Way的例子,用以说明传统方式相较于Apache Way的区别在哪里,这里假设我想为Dubbo开发一个功能A。&lt;/p>
&lt;p>&lt;strong>Old Way&lt;/strong>:&lt;/p>
&lt;ol>
&lt;li>功能设计:做一个设计文档(根据功能大小而定),大概划定需要修改或新增的类,大体设计接口等。&lt;/li>
&lt;li>开发代码。&lt;/li>
&lt;li>提交PR。&lt;/li>
&lt;li>Review &amp;amp; Merge&lt;/li>
&lt;/ol>
&lt;p>可以看到,我们整个过程中,真正与社区交互的只有最后一步。&lt;/p>
&lt;p>&lt;strong>Apache Way&lt;/strong>:&lt;/p>
&lt;ol>
&lt;li>功能设计:发送邮件至mailing list并且提交ISSUE,与社区成员共同探讨,产出一个设计文档(根据功能大小而定),大概划定需要修改或新增的类,大体设计接口等。然后再次发送邮件并且回复ISSUE,通知社区设计文档定稿或者方案确定。&lt;/li>
&lt;li>开发代码:发送邮件至社区,通知社区成员我即将投入开发功能A,如需帮助,可以同时说明需要协助。&lt;/li>
&lt;li>提交PR:发送邮件并且回复ISSUE,提醒社区开发结束,贴上PR地址以通知社区review代码。&lt;/li>
&lt;li>Review + Merge后,发送邮件并且关闭ISSUE,通知社区功能A的开发功能告一段落。&lt;/li>
&lt;/ol>
&lt;p>可以看到,Apache Way就是在整个开发过程中,不断地与社区交互,最大发挥社区的功能,汲取众人之力,这才是所谓&lt;strong>社区&lt;/strong>以及所谓&lt;strong>开源&lt;/strong>的含义。&lt;/p>
&lt;h2 id="结尾">结尾&lt;/h2>
&lt;p>Dubbo目前还在孵化阶段,整个Dubbo社区还不完善,我们也在跟着Dubbo一起成长,我们非常希望更多的Dubbo爱好者深度参与到Dubbo中,为你的代码生涯树一个里程碑。&lt;/p>
&lt;p>相信过程,收获结果;天道酬勤,功不唐捐!&lt;/p></description></item><item><title>Blog: 第五届Dubbo开发者沙龙在杭州成功举办</title><link>https://dubbo.apache.org/zh-cn/blog/2018/12/10/%E7%AC%AC%E4%BA%94%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E5%9C%A8%E6%9D%AD%E5%B7%9E%E6%88%90%E5%8A%9F%E4%B8%BE%E5%8A%9E/</link><pubDate>Mon, 10 Dec 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/12/10/%E7%AC%AC%E4%BA%94%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E5%9C%A8%E6%9D%AD%E5%B7%9E%E6%88%90%E5%8A%9F%E4%B8%BE%E5%8A%9E/</guid><description>
&lt;p>第五届Dubbo开发者沙龙在杭州成功举办,&lt;/p>
&lt;p>分享嘉宾&lt;/p>
&lt;ul>
&lt;li>李鼎: 如何参与Dubbo开源社区 &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201812%40hangzhou/how-to-involve-in-dubbo-community.pdf">slides&lt;/a>&lt;/li>
&lt;li>曹胜利: Dubbo 2.7新特性介绍及演示 &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201812%40hangzhou/dubbo-2.7-introduction.pdf">slides&lt;/a>&lt;/li>
&lt;li>陶杨: Dubbo在考拉的应用实践 &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201812%40hangzhou/dubbo-practice-in-netease-koala.pdf">slides&lt;/a>&lt;/li>
&lt;li>小马哥: Dubbo+Nacos服务治理重新实现 &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201812%40hangzhou/nacos-support-in-dubbo.pdf">slides&lt;/a>&lt;/li>
&lt;li>赵奕豪: Sentinel:分布式服务的流量防卫兵 &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201812%40hangzhou/sentinel-support-for-dubbo.pdf">slides&lt;/a>&lt;/li>
&lt;li>陈志轩: 当Dubbo遇上Arthas:排查问题的实践 &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201812%40hangzhou/troubleshooting-dubbo-with-arthas.pdf">slides&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Blog: 如何准备Apache Release</title><link>https://dubbo.apache.org/zh-cn/blog/2018/09/02/%E5%A6%82%E4%BD%95%E5%87%86%E5%A4%87apache-release/</link><pubDate>Sun, 02 Sep 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/09/02/%E5%A6%82%E4%BD%95%E5%87%86%E5%A4%87apache-release/</guid><description>
&lt;h2 id="理解apache发布的内容和流程">理解Apache发布的内容和流程&lt;/h2>
&lt;p>总的来说,Source Release是Apache关注的重点,也是发布的必须内容;而Binary Release是可选项,Dubbo可以选择是否发布二进制包到Apache仓库或者发布到Maven中央仓库。&lt;/p>
&lt;p>请参考以下链接,找到更多关于ASF的发布指南:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://www.apache.org/dev/release-publishing">Apache Release Guide&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.apache.org/dev/release.html">Apache Release Policy&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.apache.org/dev/publishing-maven-artifacts.html">Maven Release Info&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="本地构建环境准备">本地构建环境准备&lt;/h2>
&lt;p>主要包括签名工具、Maven仓库认证相关准备&lt;/p>
&lt;h3 id="安装gpg">安装GPG&lt;/h3>
&lt;p>详细文档请参见&lt;a href="https://www.gnupg.org/download/index.html">这里&lt;/a>, Mac OS下配置如下&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>$ brew install gpg
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ gpg --version &lt;span style="color:#586e75">#检查版本,应该为2.x&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="用gpg生成key">用gpg生成key&lt;/h3>
&lt;p>根据提示,生成key&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ gpg --full-gen-key
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gpg &lt;span style="color:#719e07">(&lt;/span>GnuPG&lt;span style="color:#719e07">)&lt;/span> 2.0.12; Copyright &lt;span style="color:#719e07">(&lt;/span>C&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#2aa198">2009&lt;/span> Free Software Foundation, Inc.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>This is free software: you are free to change and redistribute it.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>There is NO WARRANTY, to the extent permitted by law.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Please &lt;span style="color:#719e07">select&lt;/span> what kind of key you want:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">(&lt;/span>1&lt;span style="color:#719e07">)&lt;/span> RSA and RSA &lt;span style="color:#719e07">(&lt;/span>default&lt;span style="color:#719e07">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">(&lt;/span>2&lt;span style="color:#719e07">)&lt;/span> DSA and Elgamal
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">(&lt;/span>3&lt;span style="color:#719e07">)&lt;/span> DSA &lt;span style="color:#719e07">(&lt;/span>sign only&lt;span style="color:#719e07">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">(&lt;/span>4&lt;span style="color:#719e07">)&lt;/span> RSA &lt;span style="color:#719e07">(&lt;/span>sign only&lt;span style="color:#719e07">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Your selection? &lt;span style="color:#2aa198">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>RSA keys may be between &lt;span style="color:#2aa198">1024&lt;/span> and &lt;span style="color:#2aa198">4096&lt;/span> bits long.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>What keysize &lt;span style="color:#719e07">do&lt;/span> you want? &lt;span style="color:#719e07">(&lt;/span>2048&lt;span style="color:#719e07">)&lt;/span> &lt;span style="color:#2aa198">4096&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Requested keysize is &lt;span style="color:#2aa198">4096&lt;/span> bits
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Please specify how long the key should be valid.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">0&lt;/span> &lt;span style="color:#719e07">=&lt;/span> key does not expire
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;n&amp;gt; &lt;span style="color:#719e07">=&lt;/span> key expires in n days
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;n&amp;gt;w &lt;span style="color:#719e07">=&lt;/span> key expires in n weeks
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;n&amp;gt;m &lt;span style="color:#719e07">=&lt;/span> key expires in n months
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;n&amp;gt;y &lt;span style="color:#719e07">=&lt;/span> key expires in n years
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Key is valid &lt;span style="color:#719e07">for&lt;/span>? &lt;span style="color:#719e07">(&lt;/span>0&lt;span style="color:#719e07">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Key does not expire at all
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Is this correct? &lt;span style="color:#719e07">(&lt;/span>y/N&lt;span style="color:#719e07">)&lt;/span> y
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>GnuPG needs to construct a user ID to identify your key.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Real name: Robert Burrell Donkin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Email address: rdonkin@apache.org
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Comment: CODE SIGNING KEY
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>You selected this USER-ID:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#2aa198">&amp;#34;Robert Burrell Donkin (CODE SIGNING KEY) &amp;lt;rdonkin@apache.org&amp;gt;&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>Change &lt;span style="color:#719e07">(&lt;/span>N&lt;span style="color:#719e07">)&lt;/span>ame, &lt;span style="color:#719e07">(&lt;/span>C&lt;span style="color:#719e07">)&lt;/span>omment, &lt;span style="color:#719e07">(&lt;/span>E&lt;span style="color:#719e07">)&lt;/span>mail or &lt;span style="color:#719e07">(&lt;/span>O&lt;span style="color:#719e07">)&lt;/span>kay/&lt;span style="color:#719e07">(&lt;/span>Q&lt;span style="color:#719e07">)&lt;/span>uit? O
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>You need a Passphrase to protect your secret key. &lt;span style="color:#586e75"># 填入密码,以后打包过程中会经常用到&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="查看key-id">查看key id&lt;/h3>
&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>$ gpg --list-keys
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pub rsa4096/28681CB1 2018-04-26 &lt;span style="color:#586e75"># 28681CB1就是key id&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>uid &lt;span style="color:#719e07">[&lt;/span>ultimate&lt;span style="color:#719e07">]&lt;/span> liujun &lt;span style="color:#719e07">(&lt;/span>apache-dubbo&lt;span style="color:#719e07">)&lt;/span> &amp;lt;liujun@apache.org&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sub rsa4096/D3D6984B 2018-04-26
&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"># 通过key id发送public key到keyserver&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ gpg --keyserver pgpkeys.mit.edu --send-key 28681CB1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># 其中,pgpkeys.mit.edu为随意挑选的keyserver,keyserver列表为:https://sks-keyservers.net/status/,为相互之间是自动同步的,选任意一个都可以。&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果有多个public key,设置默认key。修改&lt;code>~/.gnupg/gpg.conf&lt;/code>&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># If you have more than 1 secret key in your keyring, you may want to&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># uncomment the following option and set your preferred keyid.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>default-key 28681CB1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果有多个public key, 也可以删除无用的key:&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-sh" data-lang="sh">&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>$ gpg --yes --delete-secret-keys shenglicao2@gmail.com &lt;span style="color:#586e75">###老的私钥,指明邮箱即可&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ gpg --delete-keys 1808C6444C781C0AEA0AAD4C4D6A8007D20DB8A4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>PS: 最新版本经过实测,本地没有gpg.conf这个文件,因此如果在执行过程中遇到签名失败,可以参考这个文章:https://blog.csdn.net/wenbo20182/article/details/72850810 或 &lt;a href="https://d.sb/2016/11/gpg-inappropriate-ioctl-for-device-errors">https://d.sb/2016/11/gpg-inappropriate-ioctl-for-device-errors&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;h3 id="设置apache中央仓库">设置Apache中央仓库&lt;/h3>
&lt;p>Dubbo项目的父pom为Apache pom(2.7.0以上版本需要,2.6.x发布版本不需要此操作)&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-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;parent&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;groupId&amp;gt;&lt;/span>org.apache&lt;span style="color:#268bd2">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;artifactId&amp;gt;&lt;/span>apache&lt;span style="color:#268bd2">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;version&amp;gt;&lt;/span>19&lt;span style="color:#268bd2">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/parent&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>添加以下内容到.m2/settings.xml
所有密码请使用&lt;a href="http://maven.apache.org/guides/mini/guide-encryption.html">maven-encryption-plugin&lt;/a>加密后再填入&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-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;settings&amp;gt;&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:#268bd2">&amp;lt;servers&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">&amp;lt;!-- To publish a snapshot of some part of Maven --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;server&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;id&amp;gt;&lt;/span>apache.snapshots.https&lt;span style="color:#268bd2">&amp;lt;/id&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;username&amp;gt;&lt;/span> &lt;span style="color:#586e75">&amp;lt;!-- YOUR APACHE LDAP USERNAME --&amp;gt;&lt;/span> &lt;span style="color:#268bd2">&amp;lt;/username&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;password&amp;gt;&lt;/span> &lt;span style="color:#586e75">&amp;lt;!-- YOUR APACHE LDAP PASSWORD (encrypted) --&amp;gt;&lt;/span> &lt;span style="color:#268bd2">&amp;lt;/password&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/server&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">&amp;lt;!-- To stage a release of some part of Maven --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;server&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;id&amp;gt;&lt;/span>apache.releases.https&lt;span style="color:#268bd2">&amp;lt;/id&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;username&amp;gt;&lt;/span> &lt;span style="color:#586e75">&amp;lt;!-- YOUR APACHE LDAP USERNAME --&amp;gt;&lt;/span> &lt;span style="color:#268bd2">&amp;lt;/username&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;password&amp;gt;&lt;/span> &lt;span style="color:#586e75">&amp;lt;!-- YOUR APACHE LDAP PASSWORD (encrypted) --&amp;gt;&lt;/span> &lt;span style="color:#268bd2">&amp;lt;/password&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/server&amp;gt;&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">&amp;lt;!-- gpg passphrase used when generate key --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;server&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;id&amp;gt;&lt;/span>gpg.passphrase&lt;span style="color:#268bd2">&amp;lt;/id&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;passphrase&amp;gt;&lt;/span>&lt;span style="color:#586e75">&amp;lt;!-- yourKeyPassword --&amp;gt;&lt;/span>&lt;span style="color:#268bd2">&amp;lt;/passphrase&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/server&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;/servers&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/settings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="打包上传">打包&amp;amp;上传&lt;/h2>
&lt;h3 id="准备分支">准备分支&lt;/h3>
&lt;p>从主干分支拉取新分支作为发布分支,如现在要发布$&lt;code>{release_version}&lt;/code>版本,则从2.6.x拉出新分支&lt;code>${release_version}-release&lt;/code>,此后&lt;code>${release_version}&lt;/code> Release Candidates涉及的修改及打标签等都在&lt;code>${release_version}-release&lt;/code>分支进行,最终发布完成后合入主干分支。&lt;/p>
&lt;h3 id="编译打包">编译打包&lt;/h3>
&lt;p>首先,在&lt;code>${release_version}-release&lt;/code>分支验证maven组件打包、source源码打包、签名等是否都正常工作。&lt;strong>2.6.x记得要使用1.6进行编译打包&lt;/strong>&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ mvn clean install -Prelease
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ mvn deploy
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上述命令将snapshot包推送到maven中央仓库&lt;/p>
&lt;h3 id="用maven-release-plugin发布">用maven-release-plugin发布&lt;/h3>
&lt;p>先用dryRun验证是否ok&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ mvn release:prepare -Prelease -Darguments&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">&amp;#34;-DskipTests&amp;#34;&lt;/span> -DautoVersionSubmodules&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#b58900">true&lt;/span> -Dusername&lt;span style="color:#719e07">=&lt;/span>YOUR GITHUB ID-DdryRun&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#b58900">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>验证通过后,执行release:prepare&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ mvn release:clean
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ mvn release:prepare -Prelease -Darguments&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">&amp;#34;-DskipTests&amp;#34;&lt;/span> -DautoVersionSubmodules&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#b58900">true&lt;/span> -Dusername&lt;span style="color:#719e07">=&lt;/span>YOUR GITHUB ID -DpushChanges&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#b58900">false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>执行release插件时,如果指定了&lt;code>-DpushChanges=true&lt;/code>, 插件会自动提交到远端的GitHub仓库中,此时就需要输入GitHub的密码,注意不是输入web页面的登录密码,而是一个&lt;code>Personal access tokens&lt;/code>,获取方式详见&lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token">这里&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>这里有一点要注意的是tag, 在执行过程中,需要选择发布的artifactId, 下一个版本artifactId以及发布版本的tag, tag默认的是dubbo-parent-xxxx,需要改成dubbo-xxxx&lt;/p>
&lt;/blockquote>
&lt;p>执行完上述步骤后,你会发现:&lt;/p>
&lt;ol>
&lt;li>&lt;code>source-release.zip&lt;/code> 和 &lt;code>bin-release.zip&lt;/code>包已经生成在&lt;code>dubbo-distribution&lt;/code>目录下,请解压并检查文件是否完整&lt;/li>
&lt;li>本地已经打出相应的tag,同时新增一个commit,名叫&lt;code>[maven-release-plugin] prepare release dubbo-x.x.x&lt;/code>&lt;/li>
&lt;li>分支版本自动升级为&lt;code>${release_version+1}-SNAPSHOT&lt;/code>,同时新增一个commit,名叫&lt;code>[[maven-release-plugin] prepare for next development iteration&lt;/code>&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>如果指定了&lt;code>-DpushChanges=true&lt;/code>, 则本地提交会自动推送到远端的GitHub仓库。根据经验,建议不要指定为true,请设置为false,待本地检查通过之后再手动提交&lt;/p>
&lt;/blockquote>
&lt;p>执行release:perform,做staging发布&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ mvn -Prelease release:perform -Darguments&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">&amp;#34;-DskipTests&amp;#34;&lt;/span> -DautoVersionSubmodules&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#b58900">true&lt;/span> -Dusername&lt;span style="color:#719e07">=&lt;/span>YOUR GITHUB ID
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>此时插件会自动下载远端的tag对应的源码,编译后,将所有Artifacts发布到配置的远程&lt;a href="http://repository.apache.org">maven仓库&lt;/a>,处于staging状态。&lt;/p>
&lt;h4 id="注意点">注意点&lt;/h4>
&lt;ul>
&lt;li>在deploy执行过程中,有可能因为网络等原因被中断,如果是这样,可以重新开始执行。&lt;/li>
&lt;li>deploy执行到maven仓库的时候,请确认下包的总量是否正确。多次出现了包丢失的情况,特别是dubbo-parent包。&lt;/li>
&lt;/ul>
&lt;h2 id="准备apache发布">准备Apache发布&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>准备svn本机环境(Apache使用svn托管项目的发布内容)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>将dubbo checkout到本地目录&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ svn checkout https://dist.apache.org/repos/dist/dev/dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># 假定本地目录为 ~/apache/incubator/dubbo&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>当前发布版本为${release_version},新建目录&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#b58900">cd&lt;/span> ~/apache/incubator/dubbo &lt;span style="color:#586e75"># dubbo svn根目录&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ mkdir &lt;span style="color:#2aa198">${&lt;/span>&lt;span style="color:#268bd2">release_version&lt;/span>&lt;span style="color:#2aa198">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>添加public key到&lt;a href="https://dist.apache.org/repos/dist/dev/dubbo/KEYS">KEYS&lt;/a>文件并提交到SVN仓库(第一次做发布的人需要做这个操作,具体操作参考KEYS文件里的说明)。KEYS主要是让参与投票的人在本地导入,用来校验sign的正确性&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>$ gpg -a --export your_key_id &amp;gt;&amp;gt; KEYS
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>拷贝&lt;code>distribution/target&lt;/code>下的source相关的包到svn本地仓库&lt;code>dubbo/${release_version}&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>生成sha512签名&lt;/p>
&lt;p>针对&lt;code>source-release.zip&lt;/code>&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ shasum -a &lt;span style="color:#2aa198">512&lt;/span> apache-dubbo-&lt;span style="color:#2aa198">${&lt;/span>&lt;span style="color:#268bd2">release_version&lt;/span>&lt;span style="color:#2aa198">}&lt;/span>-source-release.zip &amp;gt;&amp;gt; apache-dubbo-&lt;span style="color:#2aa198">${&lt;/span>&lt;span style="color:#268bd2">release_version&lt;/span>&lt;span style="color:#2aa198">}&lt;/span>-source-release.zip.sha512
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>针对&lt;code>bin-release.zip&lt;/code>,需要增加&lt;code>-b&lt;/code>参数,表明是一个二进制文件&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ shasum -b -a &lt;span style="color:#2aa198">512&lt;/span> apache-dubbo-&lt;span style="color:#2aa198">${&lt;/span>&lt;span style="color:#268bd2">release_version&lt;/span>&lt;span style="color:#2aa198">}&lt;/span>-bin-release.zip &amp;gt;&amp;gt; apache-dubbo-&lt;span style="color:#2aa198">${&lt;/span>&lt;span style="color:#268bd2">release_version&lt;/span>&lt;span style="color:#2aa198">}&lt;/span>-bin-release.zip.sha512
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>如果有binary release要同时发布&lt;/p>
&lt;p>在&lt;code>distribution/target&lt;/code>目录下,拷贝&lt;code>bin-release.zip&lt;/code>以及&lt;code>bin-release.zip.asc&lt;/code>到svn本地仓库&lt;code>dubbo/${release_version}&lt;/code>,参考第6步,生成sha512签名。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>提交到Apache svn&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-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ svn status
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ svn commit -m &lt;span style="color:#2aa198">&amp;#39;prepare for ${release_version} RC1&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;h2 id="验证release-candidates">验证Release Candidates&lt;/h2>
&lt;p>详细的检查列表请参考官方的&lt;a href="https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist">check list&lt;/a>&lt;/p>
&lt;p>首先,从一下地址下载要发布的Release Candidate到本地环境:&lt;/p>
&lt;pre>
https://dist.apache.org/repos/dist/dev/dubbo/${release_version}/
&lt;/pre>
&lt;p>然后,开始验证环节,验证包含但不限于以下内容和形式&lt;/p>
&lt;h3 id="检查签名和hash等信息">检查签名和hash等信息&lt;/h3>
&lt;h4 id="检查sha512哈希">检查sha512哈希&lt;/h4>
&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>$ shasum -c apache-dubbo-&lt;span style="color:#2aa198">${&lt;/span>&lt;span style="color:#268bd2">release_version&lt;/span>&lt;span style="color:#2aa198">}&lt;/span>-source-release.zip.sha512
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ shasum -c apache-dubbo-&lt;span style="color:#2aa198">${&lt;/span>&lt;span style="color:#268bd2">release_version&lt;/span>&lt;span style="color:#2aa198">}&lt;/span>-bin-release.zip.sha512
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="检查gpg签名">检查gpg签名&lt;/h4>
&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span> $ curl https://dist.apache.org/repos/dist/dev/dubbo/KEYS &amp;gt;&amp;gt; KEYS &lt;span style="color:#586e75"># download public keys to local directory&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ gpg --import KEYS &lt;span style="color:#586e75"># import keys&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ gpg —edit-key liujun
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;gt; trust &lt;span style="color:#586e75"># type trust command&lt;/span>
&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>gpg --verify apache-dubbo-2.6.3-source-release.zip.asc apache-dubbo-2.6.3-source-release.zip
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gpg --verify apache-dubbo-2.6.3-bin-release.zip.asc apache-dubbo-2.6.3-bin-release.zip
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="检查源码包的文件内容">检查源码包的文件内容&lt;/h3>
&lt;p>解压缩&lt;code>apache-dubbo-${release_version}-source-release.zip&lt;/code>,进行如下检查:&lt;/p>
&lt;ul>
&lt;li>Directory with &amp;lsquo;incubating&amp;rsquo; in name
&lt;code>apache-dubbo-${release_version}-source-release&lt;/code>&lt;/li>
&lt;li>DISCLAIMER exists&lt;/li>
&lt;li>LICENSE and NOTICE exists and contents are good&lt;/li>
&lt;li>All files and no binary files exist&lt;/li>
&lt;li>All files has standard ASF License header&lt;/li>
&lt;li>Can compile from source&lt;/li>
&lt;li>All unit tests can pass
&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>mvn clean &lt;span style="color:#b58900">test&lt;/span> &lt;span style="color:#586e75"># This will run all unit tests&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"># you can also open rat and style plugin to check if every file meets requirements.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mvn clean &lt;span style="color:#b58900">test&lt;/span> -Drat.skip&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#b58900">false&lt;/span> -Dcheckstyle.skip&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#b58900">false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>Release candidates match with corresponding tags, you can find tag link and hash in vote email.
&lt;ul>
&lt;li>check the version number in pom.xml are the same&lt;/li>
&lt;li>check there are no extra files or directories in the source package, for example, no empty directories or useless log files,这里需要注意换行符是否一致&lt;br>
&lt;code>diff -r a rc_dir tag_dir&lt;/code>&lt;/li>
&lt;li>check the top n tag commits, dive into the related files and check if the source package has the same changes&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="检查二进制包的文件内容c">检查二进制包的文件内容C&lt;/h3>
&lt;p>解压缩&lt;code>apache-dubbo-${release_version}-bin-release.zip&lt;/code>,进行如下检查:&lt;/p>
&lt;ul>
&lt;li>Check signatures are good&lt;/li>
&lt;li>&amp;lsquo;incubating&amp;rsquo; in name&lt;/li>
&lt;li>LICENSE and NOTICE exists and contents are good&lt;/li>
&lt;/ul>
&lt;p>注意,如果二进制包里面引入了第三方依赖,则需要更新LICENSE,加入第三方依赖的LICENSE,如果第三方依赖的LICENSE是Apache 2.0,并且对应的项目中包含了NOTICE,还需要更新NOTICE文件&lt;/p>
&lt;h2 id="进入投票">进入投票&lt;/h2>
&lt;p>投票分两个阶段:&lt;/p>
&lt;ol>
&lt;li>Dubbo社区投票,发起投票邮件到dev@dubbo.apache.org。在社区开发者Review,经过至少72小时并统计到3个同意发版的binding票后(只有PMC的票才是binding),即可进入下一阶段的投票。&lt;/li>
&lt;li>Apache社区投票,发起投票邮件到general@incubator.apache.org。经过至少72小时并统计到3个同意发版的binding票后(只有IPMC Member的票才是binding),即可进行正式发布。&lt;/li>
&lt;/ol>
&lt;p>Dubbo社区投票邮件模板:&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-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Hello Dubbo Community,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>This is a call for vote to release Apache Dubbo (Incubating) version 2.6.2.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The release candidates:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://dist.apache.org/repos/dist/dev/dubbo/2.6.2/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Git tag for the release:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://github.com/apache/dubbo/tree/dubbo-2.6.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Hash for the release tag:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>afab04c53edab38d52275d2a198ea1aff7a4f41e
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Release Notes:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://github.com/apache/dubbo/releases/tag/untagged-4775c0a22c60fca55118
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The artifacts have been signed with Key : 28681CB1, which can be found in the keys file:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://dist.apache.org/repos/dist/dev/dubbo/KEYS
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The vote will be open for at least 72 hours or until necessary number of votes are reached.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Please vote accordingly:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] +1 approve
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] +0 no opinion
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] -1 disapprove with the reason
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Thanks,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The Apache Dubbo (Incubating) Team
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Apache社区投票邮件模板:&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-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Hello all,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>This is a call for vote to release Apache Dubbo (Incubating) version 2.6.4.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The Apache Dubbo community has voted on and approved a proposal to release
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Apache Dubbo (Incubating) version 2.6.4.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>We now kindly request the Incubator PMC members review and vote on this
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>incubator release.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Apache Dubbo™ is a high-performance, java based, open source
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>RPC framework. Dubbo offers three key functionalities, which include
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>interface based remote call, fault tolerance &amp;amp; load balancing, and
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>automatic service registration &amp;amp; discovery.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Dubbo community vote and result thread:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://lists.apache.org/thread.html/8d5c39eece6288beed2e22ca976350728c571d2a9cef1c9a9e56a409@%3Cdev.dubbo.apache.org%3E
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>A minor issue also can be found in the above thread.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The release candidates (RC1):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://dist.apache.org/repos/dist/dev/dubbo/2.6.4
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Git tag for the release (RC1):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://github.com/apache/dubbo/tree/dubbo-2.6.4
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Hash for the release tag:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>88037747a3b69d3225c73f6fbcda36ebd8435887
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Release Notes:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*https://github.com/apache/dubbo/blob/dubbo-2.6.4/CHANGES.md
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;https://github.com/apache/dubbo/blob/dubbo-2.6.4/CHANGES.md&amp;gt;*
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The artifacts have been signed with Key : 7955FB6D1DD21CF7, which can be
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>found in the keys file:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://dist.apache.org/repos/dist/dev/dubbo/KEYS
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Look at here for how to verify this release candidate:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://github.com/apache/dubbo-website/blob/asf-site/blog/en-us/prepare-an-apache-release.md#prepare-apache-release
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The vote will be open for at least 72 hours or until necessary number of
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>votes are reached.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Please vote accordingly:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] +1 approve
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] +0 no opinion
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ ] -1 disapprove with the reason
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Thanks,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The Apache Dubbo (Incubating) Team
&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-text" data-lang="text">&lt;span style="display:flex;">&lt;span>We’ve received 3 +1 binding votes and one +1 non-binding vote:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+1 binding, Ian Luo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+1 binding, Huxing Zhang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+1 binding, Jun Liu
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+1 non-binding, Jerrick
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>I will create a new vote thread in Apache community now.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Best regards,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The Apache Dubbo (Incubating) Team
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="正式发布">正式发布&lt;/h2>
&lt;ol>
&lt;li>将&lt;a href="https://dist.apache.org/repos/dist/dev/dubbo">dev&lt;/a>目录下的发布包添加到&lt;a href="https://dist.apache.org/repos/dist/release/dubbo">release&lt;/a>目录下,KEYS有更新的,也需要同步更新。&lt;/li>
&lt;li>删除&lt;a href="https://dist.apache.org/repos/dist/dev/dubbo">dev&lt;/a>目录下的发布包&lt;/li>
&lt;li>删除&lt;a href="https://dist.apache.org/repos/dist/release/dubbo">release&lt;/a>目录下上一个版本的发布包,这些包会被自动保存在&lt;a href="https://archive.apache.org/dist/incubator/dubbo">这里&lt;/a>&lt;/li>
&lt;li>发布GitHub上的&lt;a href="https://github.com/apache/dubbo/releases">release notes&lt;/a>&lt;/li>
&lt;li>修改GitHub的Readme文件,将版本号更新到最新发布的版本&lt;/li>
&lt;li>在官网下载&lt;a href="https://dubbo.apache.org/en/blog/2020/05/18/past-releases/">页面&lt;/a>上添加最新版本的下载链接。最新的下载链接应该类似&lt;code>https://www.apache.org/dyn/closer.cgi?path=incubator/dubbo/$VERSION/apache-dubbo-$VERSION-source-release.zip&lt;/code>. 同时更新以前版本的下载链接,改为类似&lt;code>https://archive.apache.org/dist/dubbo/$VERSION/apache-dubbo-$VERSION-bin-release.zip&lt;/code>. 具体可以参考过往的&lt;a href="https://dubbo.apache.org/en/blog/2020/05/18/past-releases/">下载链接&lt;/a>&lt;/li>
&lt;li>合并&lt;code>${release-version}-release&lt;/code>分支到对应的主干分支, 然后删除相应的release分支,例如: &lt;code>git push origin --delete 2.7.0-release&lt;/code>&lt;/li>
&lt;li>发邮件到 &lt;code>dev@dubbo.apache.org&lt;/code> 和 &lt;code>general@incubator.apache.org&lt;/code>
宣布release邮件模板:&lt;/li>
&lt;/ol>
&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-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Hello Community,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The Apache Dubbo team is pleased to announce that the
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>2.6.6 has just been released.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Apache Dubbo™ is a high-performance, java based, open source
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>RPC framework. Dubbo offers three key functionalities, which include
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>interface based remote call, fault tolerance &amp;amp; load balancing, and
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>automatic service registration &amp;amp; discovery.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Both the source release[1] and the maven binary release[2] are available
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>now, you can also find the detailed release notes in here[3].
&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>If you have any usage questions, or have problems when upgrading or find
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>any problems about enhancements included in this release, please don’t
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hesitate to let us know by sending feedback to this mailing list or filing
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>an issue on GitHub[4].
&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>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>=====
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*Disclaimer*
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Apache Dubbo is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.
&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>[1] https://dubbo.apache.org/en/blog/2020/05/18/past-releases/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[2] http://central.maven.org/maven2/com/alibaba/dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[3] https://github.com/apache/dubbo/releases
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[4] https://github.com/apache/dubbo/issues
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="完成maven-convenient-binary发布可选">完成Maven Convenient Binary发布(可选)&lt;/h2>
&lt;p>&lt;strong>repository.apache.org&lt;/strong> nexus仓库的权限已经申请,参见&lt;a href="https://issues.apache.org/jira/browse/INFRA-16451">jira&lt;/a>&lt;/p>
&lt;p>发布jar包到maven仓库,首先访问&lt;a href="https://repository.apache.org">repository.apache.org&lt;/a>, 选择&lt;code>staging repository&lt;/code>, 点击&lt;code>release&lt;/code>按钮。等待一段时间之后,在&lt;a href="https://repository.apache.org/content/repositories/releases/org/apache/dubbo/">这里&lt;/a>确认完整性和正确性. 发布到Maven中央仓库则还需要等待一段时间。可以在&lt;a href="https://repo.maven.apache.org/maven2/org/apache/dubbo">这里&lt;/a>进行确认。&lt;/p>
&lt;h2 id="faq">FAQ&lt;/h2>
&lt;h4 id="gpg-signing-failed-inappropriate-ioctl-for-device">gpg: signing failed: Inappropriate ioctl for device&lt;/h4>
&lt;p>If you&amp;rsquo;ve encoutered this error, try the following commands:&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-gdscript3" data-lang="gdscript3">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">export&lt;/span> GPG_TTY&lt;span style="color:#719e07">=$&lt;/span>(tty)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Blog: 第四届Dubbo开发者沙龙于8月26日在成都举行</title><link>https://dubbo.apache.org/zh-cn/blog/2018/08/26/%E7%AC%AC%E5%9B%9B%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E4%BA%8E8%E6%9C%8826%E6%97%A5%E5%9C%A8%E6%88%90%E9%83%BD%E4%B8%BE%E8%A1%8C/</link><pubDate>Sun, 26 Aug 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/08/26/%E7%AC%AC%E5%9B%9B%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E4%BA%8E8%E6%9C%8826%E6%97%A5%E5%9C%A8%E6%88%90%E9%83%BD%E4%B8%BE%E8%A1%8C/</guid><description>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/meetup-chengdu/all-hands.webp" alt="img">&lt;/p>
&lt;h2 id="用户深度沟通交流">用户深度沟通交流&lt;/h2>
&lt;p>8.26上午10:00-12:00,邀请到货车帮,云图金控,前BBD,飞鱼星四家公司开源爱好者及重度用户参与面对面交流;据参与者反馈,解答了对Dubbo的诸多疑惑,特别是如何参与贡献社区,以及捐献代码所带来的价值点。希望后面可以更加深入参与Dubbo社区及活动中。&lt;/p>
&lt;h2 id="meetup活动信息">meetup活动信息&lt;/h2>
&lt;p>本次活动依旧爆满,总报名人数976,现场用户350+,直播PV 13207。&lt;/p>
&lt;h2 id="报名信息">报名信息&lt;/h2>
&lt;p>Aliware Open Source•成都站-Apache Dubbo开发者沙龙于8月26日(周日)在成都高新区天府五街200号菁蓉国际广场8号楼2楼会议厅举办,技术GG们的思想盛宴,干货与福利一个都不会少。&lt;/p>
&lt;p>报名链接:http://www.huodongxing.com/event/7453091088400&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dubbo-chengdu-meetup-img.jpg" alt="img">&lt;/p></description></item><item><title>Blog: 第三届Dubbo开发者沙龙在深圳成功举办</title><link>https://dubbo.apache.org/zh-cn/blog/2018/07/30/%E7%AC%AC%E4%B8%89%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E5%9C%A8%E6%B7%B1%E5%9C%B3%E6%88%90%E5%8A%9F%E4%B8%BE%E5%8A%9E/</link><pubDate>Mon, 30 Jul 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/07/30/%E7%AC%AC%E4%B8%89%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E5%9C%A8%E6%B7%B1%E5%9C%B3%E6%88%90%E5%8A%9F%E4%B8%BE%E5%8A%9E/</guid><description>
&lt;p>第三届Dubbo开发者沙龙在深圳成功举办,超过2000位开发者报名,现场参与人数700+,通过阿里云天池、云栖社区、大咖说引导线上直播观看次数17000+&lt;/p>
&lt;p>分享嘉宾&lt;/p>
&lt;ul>
&lt;li>陈志轩: Dubbo开源现状和2.7规划&lt;/li>
&lt;li>康彬: 乐信集团的微服务化之路&lt;/li>
&lt;li>林佳梁: Sentinel——企业用户的全方位流量哨兵&lt;/li>
&lt;/ul></description></item><item><title>Blog: 第二届Dubbo开发者沙龙在上海成功举办</title><link>https://dubbo.apache.org/zh-cn/blog/2018/06/23/%E7%AC%AC%E4%BA%8C%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E5%9C%A8%E4%B8%8A%E6%B5%B7%E6%88%90%E5%8A%9F%E4%B8%BE%E5%8A%9E/</link><pubDate>Sat, 23 Jun 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/06/23/%E7%AC%AC%E4%BA%8C%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E5%9C%A8%E4%B8%8A%E6%B5%B7%E6%88%90%E5%8A%9F%E4%B8%BE%E5%8A%9E/</guid><description>
&lt;p>第二届Dubbo开发者沙龙在上海成功举办,超过700位开发者报名,现场参与人数300+,通过阿里云天池、云栖社区、大咖说引导线上直播观看次数10000+&lt;/p>
&lt;p>分享嘉宾及PPT:&lt;/p>
&lt;ul>
&lt;li>朱勇: Dubbo开源现状与未来规划 (中文) &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-status-and-roadmap.pdf">slides&lt;/a>&lt;/li>
&lt;li>小马哥: Dubbo Cloud Native 之路的实践与思考 (中文) &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-cloud-native-practices-and-thoughts.pdf">slides&lt;/a>&lt;/li>
&lt;li>郭平: Nacos - 贡献Dubbo生态,阿里巴巴注册中心和配置中心开源计划 (中文) &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/nacos-open-source-initiative.pdf">slides&lt;/a>&lt;/li>
&lt;li>潘志伟: Dubbo在互金行业的应用场景 (中文) &lt;a href="https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-practices-on-internet-finance-industries.pdf">slides&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Blog: 首届Dubbo开发者沙龙在北京成功举办</title><link>https://dubbo.apache.org/zh-cn/blog/2018/05/12/%E9%A6%96%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E5%9C%A8%E5%8C%97%E4%BA%AC%E6%88%90%E5%8A%9F%E4%B8%BE%E5%8A%9E/</link><pubDate>Sat, 12 May 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/05/12/%E9%A6%96%E5%B1%8Adubbo%E5%BC%80%E5%8F%91%E8%80%85%E6%B2%99%E9%BE%99%E5%9C%A8%E5%8C%97%E4%BA%AC%E6%88%90%E5%8A%9F%E4%B8%BE%E5%8A%9E/</guid><description>
&lt;p>首届Dubbo开发者沙龙在北京成功举办, 超过400位开发者参加。这是一个很好的开始!&lt;/p>
&lt;p>分享嘉宾及主体如下:&lt;/p>
&lt;ul>
&lt;li>罗毅: Dubbo 的现状现状与未来规划 &lt;a href="https://github.com/dubbo/awesome-dubbo/raw/master/slides/meetup/201805%40Beijing/dubbo-present-and-future.pdf">PDF&lt;/a>&lt;/li>
&lt;li>刘军: 第四届阿里中间件性能挑战赛 &lt;a href="https://github.com/dubbo/awesome-dubbo/raw/master/slides/meetup/201805%40Beijing/introduction-to-4th-aliware-performance-challenge.pdf">PDF&lt;/a>&lt;/li>
&lt;li>陈志轩: 通过 Dubbo 和 Spring-boot 快速构建微服务 &lt;a href="https://github.com/dubbo/awesome-dubbo/raw/master/slides/meetup/201805%40Beijing/quickly-building-microservice-with-dubbo-and-springboot.pdf">PDF&lt;/a>&lt;/li>
&lt;li>王欣: Dubbo 和微店的服务化实践历程分享 &lt;a href="https://github.com/dubbo/awesome-dubbo/raw/master/slides/meetup/201805%40Beijing/dubbo-and-weidian's-practice-on-microservice-architecture.pdf">PDF&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Blog: ApacheCon NA 大会议程公布</title><link>https://dubbo.apache.org/zh-cn/blog/2018/05/02/apachecon-na-%E5%A4%A7%E4%BC%9A%E8%AE%AE%E7%A8%8B%E5%85%AC%E5%B8%83/</link><pubDate>Wed, 02 May 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/05/02/apachecon-na-%E5%A4%A7%E4%BC%9A%E8%AE%AE%E7%A8%8B%E5%85%AC%E5%B8%83/</guid><description>
&lt;p>罗毅/刘军将在蒙特利尔举办的 ApacheCon 大会上进行题为&amp;quot;Introducing Apache Dubbo(Incubating): What is Dubbo and How it Works&amp;quot;的演讲。请点击&lt;a href="https://apachecon.dukecon.org/acna/2018/#/scheduledEvent/b8db9dc580d85853f">此处&lt;/a>查看大会议程,并在&lt;a href="https://www.eventbrite.com/e/apachecon-north-america-2018-registration-43200327342">此处&lt;/a>中进行注册。&lt;/p></description></item><item><title>Blog: 谷歌编程之夏会议上2018个项目被宣布</title><link>https://dubbo.apache.org/zh-cn/blog/2018/04/25/%E8%B0%B7%E6%AD%8C%E7%BC%96%E7%A8%8B%E4%B9%8B%E5%A4%8F%E4%BC%9A%E8%AE%AE%E4%B8%8A2018%E4%B8%AA%E9%A1%B9%E7%9B%AE%E8%A2%AB%E5%AE%A3%E5%B8%83/</link><pubDate>Wed, 25 Apr 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/04/25/%E8%B0%B7%E6%AD%8C%E7%BC%96%E7%A8%8B%E4%B9%8B%E5%A4%8F%E4%BC%9A%E8%AE%AE%E4%B8%8A2018%E4%B8%AA%E9%A1%B9%E7%9B%AE%E8%A2%AB%E5%AE%A3%E5%B8%83/</guid><description>
&lt;p>谷歌编程之夏会议上2018个项目被宣布, Raghu Reddy 的项目&amp;quot;Apache Dubbo 扩展串行协议支持&amp;quot; 被&lt;a href="https://summerofcode.withgoogle.com/projects/#4747840161579008">接受&lt;/a>! 祝贺他!&lt;/p></description></item><item><title>Blog: 在DockerHub发布Dubbo Admin镜像</title><link>https://dubbo.apache.org/zh-cn/blog/2018/04/23/%E5%9C%A8dockerhub%E5%8F%91%E5%B8%83dubbo-admin%E9%95%9C%E5%83%8F/</link><pubDate>Mon, 23 Apr 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/04/23/%E5%9C%A8dockerhub%E5%8F%91%E5%B8%83dubbo-admin%E9%95%9C%E5%83%8F/</guid><description>
&lt;p>Dubbo Admin是Dubbo的服务治理中心,提供了大量日常运维所需的服务治理、配置管理等功能。&lt;/p>
&lt;p>Dubbo Admin同时包含了前端代码和后端代码,如果用户需要自己下载源码并编译打包,需要花费一定时间。
特别是对于一些希望快速调研和试用Dubbo Admin的用户,这种流程的体验并不是很好。&lt;/p>
&lt;p>Docker是一个开源的应用容器引擎,让开发者可以打包应用以及依赖包到一个可移植的镜像中,社区对于提供Dubbo Admin镜像的呼声较高。
Docker官方维护了一个公共仓库DockerHub,该仓库还有很多国内镜像,访问速度快,将Dubbo Admin镜像发布到DockerHub是一个较好的选择。&lt;/p>
&lt;h2 id="dockerhub账号申请">DockerHub账号申请&lt;/h2>
&lt;p>要在DockerHub上发布镜像,自然需要对应的账号。
而DockerHub有两种常见账号,一种是面向个人的,一种是面向组织的。Apache在DockerHub上有一个组织账号&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>。
自然我们首选是发布在组织账号下。&lt;/p>
&lt;p>DockerHub对于组织账号的管理是基于组的,也就是一个组织账号下有多个组,每个组有不同的成员,而一个组可以管理一个或者多个镜像。&lt;/p>
&lt;p>所以要做的第一步就是申请权限,这个需要提一个issue给Apache Infrastructure团队,申请DockerHub的镜像仓库和组权限。
目前镜像和组已经申请好了,只需要申请组的权限就行了,可以参考之前的申请&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>。&lt;/p>
&lt;p>申请完权限以后使用Apache账号登陆应该就可以看到对应的镜像和配置选项了。&lt;/p>
&lt;h2 id="添加新的构建规则">添加新的构建规则&lt;/h2>
&lt;p>发布镜像到DockerHub有两种办法,一种是本地构建好镜像以后远程push到DockerHub,另外一种是提供Dockerfile并借助DockerHub提供的构建功能直接在DockerHub构建。
后者明显操作性和便捷性要好很多,目前Dubbo Admin的镜像也是这样构建发布的。&lt;/p>
&lt;p>当Dubbo Admin有新版本发布以后,需要在项目的docker目录新增一个Dockerfile文件,可以参考目前0.1.0版本的Dockerfile&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>,其中的配置根据具体的版本可能有细微差别,但是大致上是一致的。&lt;/p>
&lt;p>在添加了Dockerfile之后,进入DockerHub对应的管理界面新增Build Rules&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/dockerhub-build-rules.png" alt="dockerhub-build-rules.png">&lt;/p>
&lt;p>根据实际情况填写即可。这里需要注意两点:&lt;/p>
&lt;ul>
&lt;li>latest 版本要和最新的版本配置一致&lt;/li>
&lt;li>不要勾选Autobuild&lt;/li>
&lt;/ul>
&lt;p>勾选Autobuild会导致每次git提交都会触发自动构建,但是由于Dubbo Admin不提供snapshot的Docker镜像,所以只有发布新版本的时候才需要构建发布。&lt;/p>
&lt;p>修改以后点Save,然后手动触发构建即可。&lt;/p>
&lt;h2 id="总结">总结&lt;/h2>
&lt;p>总的来说DockerHub上发布镜像的步骤并不复杂,如果已经申请过权限的话,操作起来是很流畅的。&lt;/p>
&lt;p>另外DockerHub的构建是需要排队的,有时候会遇到长时间没有开始构建的情况,需要耐心等待。&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://hub.docker.com/r/apache">https://hub.docker.com/r/apache&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://issues.apache.org/jira/browse/INFRA-18167">https://issues.apache.org/jira/browse/INFRA-18167&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://github.com/apache/dubbo-admin/blob/develop/docker/0.1.0/Dockerfile">https://github.com/apache/dubbo-admin/blob/develop/docker/0.1.0/Dockerfile&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Blog: Dubbo路线图在QCon Beijing 2018上公布</title><link>https://dubbo.apache.org/zh-cn/blog/2018/04/22/dubbo%E8%B7%AF%E7%BA%BF%E5%9B%BE%E5%9C%A8qcon-beijing-2018%E4%B8%8A%E5%85%AC%E5%B8%83/</link><pubDate>Sun, 22 Apr 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/04/22/dubbo%E8%B7%AF%E7%BA%BF%E5%9B%BE%E5%9C%A8qcon-beijing-2018%E4%B8%8A%E5%85%AC%E5%B8%83/</guid><description>
&lt;p>罗毅在Qcon Beijing 2018上进行了Dubbo开源现状及未来规划的主题演讲。详细内容请查看&lt;a href="https://github.com/dubbo/awesome-dubbo/raw/master/slides/qcon2018/dubbo-present-and-future.pdf">幻灯片&lt;/a>。&lt;/p></description></item><item><title>Blog: 如何参与贡献Dubbo社区</title><link>https://dubbo.apache.org/zh-cn/blog/2018/03/11/%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8E%E8%B4%A1%E7%8C%AEdubbo%E7%A4%BE%E5%8C%BA/</link><pubDate>Sun, 11 Mar 2018 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/blog/2018/03/11/%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8E%E8%B4%A1%E7%8C%AEdubbo%E7%A4%BE%E5%8C%BA/</guid><description>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/involve-dubbo/head.jpg" alt="img">&lt;/p>
&lt;h2 id="前言">前言&lt;/h2>
&lt;p>本文首次分享是在Apache Dubbo成都meetup上,这个话题是第一次在meetup上讲,不是我们没有更好的话题,相反,我们认为这个话题非常重要,甚至建议这个话题以后每次meetup都要讲。&lt;/p>
&lt;p>Dubbo的发展历史大家应该并不陌生了,这里我还是简单回顾一下。Dubbo于2011年在github开源,后面几年由于一些原因停止了维护,直接去年7月份阿里重启维护,并于2018年2月16日捐献给Apache。&lt;/p>
&lt;p>为什么会选择捐献给Apache,主要是为了打消社区对Dubbo未来发展的顾虑,给Dubbo用户足够的信心;Apache认为&lt;code>社区大于代码&lt;/code>,非常注重多样性,强调一个项目需要有多个公司和个人贡献者参与,现在Dubbo的发展完全是按&lt;code>The Apache Way&lt;/code>社区化的方式来运作的。&lt;/p>
&lt;h2 id="apache的诞生">Apache的诞生&lt;/h2>
&lt;p>说到Apache,大家都非常熟悉了,它是全球目前最大的软件基金;Apache的很多项目我们都用过,比如Maven、Log4j、Tomcat等,但有一个项目要特别强调的,那就是 Apache httpd server,这是Apache的第一个项目。&lt;/p>
&lt;p>Apache软件基金会正式创建于1999年,主要是为公众提供有用的免费软件,并为软件开发者社区提供支持和服务;它的创建者是一个自称为&lt;code>Apache组织&lt;/code>的群体;&lt;/p>
&lt;p>早在1995年,这个组织就存在了,他们聚集在一起,在美国伊利诺伊大学超级计算机应用程序国家中心开发的NCSA HTTPd服务器的基础上开发与维护了一个叫Apache的HTTP服务器。&lt;/p>
&lt;p>最早NCSA HTTPd服务器是一个叫Rob McCool的人开发的,但是后来慢慢失去了兴趣,导致这个功能强大又好用的服务器没人维护;于是一些爱好者和用户就自发开始维护起来,并不断改善功能、发布版本;为了更好进行沟通,一哥们就创建了一个邮件组,并把维护工作高效组织起来,且自称是&lt;code>Apache组织&lt;/code>,并把这个软件叫&lt;code>Apache 服务器&lt;/code>。&lt;/p>
&lt;p>这也是为什么Apache的所有的项目到今天为止依然以邮件列表作为沟通的主要方式。&lt;/p>
&lt;p>关于Apache的命名来源,从北美当地的一支叫&lt;code>Apache&lt;/code>的印第安部落名称而来,这支部落以高超的军事素养和超人的忍耐力著称,19世纪后半期对侵占他们领土的入侵者进行了反抗;为了对这支部落表示敬仰,就取了这个名字;但这里还流传着一个小故事,说是在NCSA HTTPd基础上,大家都通过打补丁不断在修改这个软件,被戏称为&lt;code>A Patchy Server&lt;/code>,和&lt;code>Apache Server&lt;/code>读音很像。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/involve-dubbo/apache-history.png" alt="img">&lt;/p>
&lt;p>随着后来商业需求扩大,围绕Apache HTTP服务器的项目越来越多,后来越来越多的项目启动,也有很多外部组织捐献项目;为了让这些外部项目能顺利进入到Apache基金会,2002年创建了Incubator(孵化)项目。可以看到,经过10多年的发展,到2010年,75个顶级项目,30个孵化项目,每天2697封讨论邮件;2018年这个数据进一步增长,194个顶级项目,54个孵化项目,3255个committers;其中中国人主导的项目,有RocketMQ,WeeX,ECharts,Skywalking等。&lt;/p>
&lt;p>Dubbo正在成为Apache顶级项目的路上——Apache孵化项目中。&lt;/p>
&lt;p>回顾一下Apache这些历史和数据,我们不难发现几个关键词:兴趣、参与、邮件;这些就是我们后面要重点介绍的&lt;code>The Apache Way&lt;/code>。&lt;/p>
&lt;h2 id="asf组织架构">ASF组织架构&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/involve-dubbo/apache-org.png" alt="img">&lt;/p>
&lt;p>我们知道每个组织都有它自己的架构,ASF同样也不例外;那Apache的组织架构是什么样的呢?它有什么独特的地方吗?这里特别要强调的是Project Management Committees,即 PMC,每个项目从孵化阶段开始就会有PMC,主要负责保证开源项目的社区活动都能运转良好,这里运转的机制就是&lt;code>The Apache Way&lt;/code>。&lt;/p>
&lt;p>图中,Board就是负责整个基金会符合章程的运作。Board我们一般很少能接触到,接触更多的是PMC以及下面的这几层。&lt;/p>
&lt;p>参与Apache项目社区活动的人,一般分为以下几类:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>直接用户:在座的都是Dubbo的用户,可能部分现在还不是,但将来肯定会是&lt;/p>
&lt;/li>
&lt;li>
&lt;p>贡献者:部分用户在使用Dubbo过程中,遇到问题,自己通过分析调试找到解决方案,并提交给Dubbo官方,最终被接受,这些用户就是Dubbo的贡献者&lt;/p>
&lt;/li>
&lt;li>
&lt;p>提交者:贡献多了,经过PMC的提议和投票,就会成为Committer;Committer即意味着正式加入Apache,拥有个人Apache帐号以及相应项目的写权限&lt;/p>
&lt;/li>
&lt;li>
&lt;p>PMC:Committer再往上走就是PMC,这个必须由现有PMC成员提名&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>个人在社区的成长,就像我们在公司晋升一样,一步一步往上走。&lt;/p>
&lt;p>本文的目的就是告诉大家,从User到Contributor没有大家想像的那么难,从Contributor到Committer也不是不可能;只要大家拥有一颗开源的心,找到自己感兴趣的项目,并持续投入,付出肯定会有回报。&lt;/p>
&lt;h2 id="the-apache-way">The Apache Way&lt;/h2>
&lt;p>就像你加入一家公司需要了解这家公司的文化一样,参与Apache开源项目之前,同样我们需要需要了解ASF的文化,这个文化就称为&lt;code>The Apache Way&lt;/code>。&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/involve-dubbo/apache-way.png" alt="img">&lt;/p>
&lt;p>这里想特别强调以下几点:&lt;/p>
&lt;ul>
&lt;li>社区胜于代码:把项目构建出来这不是开源,去构建社区才是真正的开源;对社区而言,一切都是围绕代码而生,无代码则社区不复存在;在代码之上,则是如何做事、如何待人、如何决策的理念体现;一个健康的社区远比优秀的代码重要——如果代码奇烂无比,社区可以重写,但社区有了毛病,代码最终也会付之东流;&lt;/li>
&lt;li>公开透明与共识决策:&lt;code>If it doesn't happen on email, it doesn't happen.&lt;/code> 所有的决定,不管是技术feature、发展方向,还是版本发布等,都应该被公开讨论,而形式就是邮件列表,这些讨论过程和结论都会被永久存档;而讨论的过程,就是大家自由发表意见的过程,但最终大家要投票,比较民主的做法;&lt;/li>
&lt;li>任人唯贤:&lt;code>Those that have proven they can do, get to do more.&lt;/code> 特别强调一点,贡献绝不仅仅是代码,贡献可以是很多方面,接下来我们结合Dubbo来讲,大家如何参与并贡献;&lt;/li>
&lt;/ul>
&lt;h2 id="参与dubbo社区">参与Dubbo社区&lt;/h2>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/involve-dubbo/dubbo-community.png" alt="img">&lt;/p>
&lt;p>要参与Dubbo社区,就要先大概了解一下目前社区的工作方式。总结一句话就是4个角色、3个途径以及2个代码组;&lt;/p>
&lt;ol>
&lt;li>4个角色前面也提到过了,分别是User、Contributor、Committer、PMC;这里特别要强调用的是,角色之间不是孤立的,比如提功能建议的也可以是Committer或Contributor等;PMC有投票权,但其他人一样也可以投票,这本身就是一种参与、一种贡献;&lt;/li>
&lt;li>3个途径,分别是Dubbo官网、github、dev邮件列表;目前比较活跃的是github issue/PR;我们鼓励按&lt;code>The Apache Way&lt;/code>的方式,使用邮件列表交流,让导师看到我们的贡献;&lt;/li>
&lt;li>2个代码组,一个是 &lt;code>github.com/apache/dubbo*&lt;/code> ,这里是dubbo孵化的项目,目前主要包含dubbo-rpc、dubbo-spring-boot-start、dubbo-ops三个部分;另外一个就是 &lt;code>github.com/dubbo&lt;/code>,这个是dubbo作为微服务解决方案的所有相关的生态部分,包括dubbo-rpc的扩展、dubbo与其他产品集成、dubbo多语言客户端实现以及一些工具和套件等;&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/involve-dubbo/dubbo-project.png" alt="img">&lt;/p>
&lt;p>所以,对于想参与Dubbo社区、想为Dubbo这个微服务解决方案自己一份力量的人来说,以下就是你们现在就可以开始做的:&lt;/p>
&lt;ol>
&lt;li>开发邮件组可以订阅起来,可以参考这里:https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide&lt;/li>
&lt;li>github.com/apache/dubbo star起来,fork起来&lt;/li>
&lt;li>学习中英文文档,进行修正或优化,提PR;有疑问的地方,可以email到邮件组或提issue;官方开发者的回复总比google或stackoverflow里找到的答案要强的多吧?&lt;/li>
&lt;li>如果你正在使用dubbo,可以将经验总结出来,写篇blog,分享给社区;真实的案例总是最具有说服力;&lt;/li>
&lt;li>如果你有时间,可以参与issue和PR的解决,回条用户的问题、PR的review;&lt;code>Good first issue&lt;/code>以及&lt;code>Help wanted&lt;/code>的issue,总有一个是适合你的;&lt;/li>
&lt;li>如果你想深入学习dubbo-rpc框架,UT是一个非常好的开始,完善和补充现有的UT,一边学习一边贡献,何乐而不为?&lt;/li>
&lt;li>发现了bug,报issue;通过自己的努力最终解决了,提一个issue,&lt;code>first-contributor&lt;/code>并不是那么难;哦,对了,拼写错误也算哦;&lt;/li>
&lt;li>如果你发现一个可以帮助用户更方便地使用dubbo,开发、测试、调试、mock、工具等;都可以贡献到Dubbo生态中来;&lt;/li>
&lt;li>最后我们非常欢迎大家通过邮件提想法,也欢迎大家多讨论;你会发现,技术变牛的同时,英文也变的66的了;&lt;/li>
&lt;/ol>
&lt;h2 id="加入apache孵化">加入Apache孵化&lt;/h2>
&lt;p>如果大家有好的项目希望捐献给Apache,这个流程可以参考一下;&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/blog/involve-dubbo/get-into-apache.png" alt="img">&lt;/p>
&lt;p>进入 Apache 分为三个阶段,准备阶段、孵化阶段和毕业阶段。准备阶段需要做的事情要找到愿意帮助孵化的导师,向Apache 提交进入孵化的申请,经过导师们讨论并投票,如果通过的话就可以进入孵化。孵化阶段分为两大环节,第一个环节是公司和个人签署协议向Apache 移交代码和知识产权,之后就是在导师的指导下按照Apache的规范做版本迭代、社区运营、发展更多的Committer;如果最终通过了成熟度评估,就可以顺利毕业成为Apache的顶级项目。&lt;/p>
&lt;h2 id="结语">结语&lt;/h2>
&lt;p>希望越来越多的公司团队和个人能够贡献到国际化的开源社区里去,一起打造我们中国的开源品牌!也希望大家都能愉快去贡献,罗马非一日建成,但付出一定会有回报。&lt;/p>
&lt;p>这里透露一个小福利,所有Apache Committer可以免费使用IntelliJ的全套付费产品,包括全宇宙最好用的IDEA。&lt;/p></description></item></channel></rss>