关于dubbo:Dubbogo应用维度注册模型

7次阅读

共计 3002 个字符,预计需要花费 8 分钟才能阅读完成。

本文作者:白泽(蒋超),Github ID @Patrick0308,开源爱好者。

Dubbo 3.0 将至。其最重要的一点就是服务自省,其根底即是利用维度的注册模型,作为目前与 Dubbo 在性能上齐全对齐的 Dubbo-go,已于 本年【2020 年】7 月份公布了其 v1.5.0 版本,实现了该模型,为年底实现与 Dubbo 3.0 对齐的新版本奠定了根底。

Dubbo-go 作为 Dubbo 的 Go 语言版本,因跨语言之故,二者针对同一模型的实现必然有较大差别,故本文重视探讨 Dubbo-go 社区本身对该模型的了解和实现,以及其与 Dubbo 之间的差别。

1 引语

在 v1.5 以前,Dubbo-go 注册模型都是以服务为维度的,直观的了解可认为其是接口维度。譬如注册信息,依照服务维度模型其示例如下:

"com.xxx.User":[{"name":"instance1", "ip":"127.0.0.1", "metadata":{"timeout":1000}},
  {"name":"instance2", "ip":"127.0.0.2", "metadata":{"timeout":2000}},
  {"name":"instance3", "ip":"127.0.0.3", "metadata":{"timeout":3000}}, 
]

这种模式的益处是显而易见的,简略直观,提供了细粒度的服务管制伎俩。

而近两年,随着云时代的到来,这种模式就裸露了有余:

  1. 支流的注册模型都是利用维度的;
  2. 以服务维度来注册,那么规模与服务数量成正比,大规模集群之下,注册核心压力十分大;

2 Dubbo-go v1.5.0 的新注册模型

这次 Dubbo-go 反对了新的注册模型,也就是利用维度的注册模型。简略而言,在利用维度注册下,其注册信息相似:

"application1": [{"name":"instance1", "ip":"127.0.0.1", "metadata":{}},
  {"name":"instance2", "ip":"127.0.0.2", "metadata":{}},
  {"name":"instanceN", "ip":"127.0.0.3", "metadata":{}}
]

在此模式之下,能够看到注册信息将会大幅度缩小,集群规模只与实例数量相干。

与此同时,在实现这一个性能的时候,Dubbo-go 还心愿放弃两个指标:

  1. 对用户齐全兼容,用户迁徙无感知;
  2. 放弃住本来服务粒度上精密管制的能力——即保留现有的服务维度的元数据;

因而 Dubbo-go 要着力解决以下几点:

  1. 目前 Consumer 的配置是以接口为准的,如何依据接口找到该接口对应的利用?例如,用户配置了 com.xxx.User 服务,那么,Dubbo-go 怎么晓得这个服务是由哪个利用来提供的呢?
  2. 在晓得了是哪个利用之后,能够从注册核心拿到利用的注册信息,如实例信息等;那怎么晓得 com.xxx.User 服务本身的元数据呢?

为了解决这两个问题,在已有的注册模型的根底上,Dubbo-go 引入两个额定的组件:ServiceNameMapping 和 MetadataService。

前者用于解决服务 - 利用之间的映射,后者用于获取服务的元数据。

由此,Dubbo-go 的利用维度注册模型就变为:

2.1 ServiceNameMapping

ServiceNameMapping 并不简单。思考到个别人在 Consumer 侧想要调用一个服务,其十有八九是晓得这个服务是哪个利用提供的,于是 Dubbo-go 引入了新的配置项 provideBy

当然,所谓“十有八九”就是说有些时候的确不晓得是服务是谁提供的,所以 Dubbo-go 还反对了基于配置核心的 ServiceNameMapping 实现。Dubbo-go 会用服务名作为 Key 从配置核心外面读出对应的利用名。这意味着, Provider 启动的时候,也会在配置核心将本身的 服务 - 利用名映射 写入配置核心。

2.2 MetadataService

MetadataService 略微要简单一点,有 remotelocal 两种模式。

相似于后面的 ServiceNameMapping,Dubbo-go 提供了基于配置核心的 MetadataService 的实现,即 remote 模式。Provider 启动的时候,就会将服务的元数据写进去。

另外一种模式是 local 模式。Dubbo-go 能够间接将 MetadataService 看做是一个一般的微服务,而后由 Provider 所提供。相似于:

由此带来一个问题:

既然 Dubbo-go 将 MetadataService 看做是一个一般的服务,那么 MetadataService 的元数据,Consumer 该怎么取得呢?这是一个典型的鸡生蛋蛋生鸡的问题。

Dubbo-go 的计划非常简单粗犷,Provider 启动的时候,不仅仅往注册核心外面写入利用自身的信息,还要把它的 MetadataService 信息写入。

这是一个利用的注册信息:

实质上来说,利用维度注册信息 + 服务元数据 = 服务维度注册信息。或者说,利用维度注册,只是一种从新组织这些信息的形式。

3 差别与改良

Dubbo-go v1.5.x 对标 Dubbo 2.7.5,能够认为是参照 Dubbo 2.7.5 间接实现其 Go 源码,然而思考到 Java 和 Go 之间的语言差别,导致二者之间的实现不可能齐全对等。

3.1 订正版本号 revision 比对

Dubbo v2.7.x 在 MetadataService 注册时,会对其 provider 利用的所有服务接口的 hash 值做为订正版本号写入元数据中心,此 revision 是对所有接口的办法以及其参数总体的计算结果。其目标是缩小 consumer 端到注册核心的拉取次数。

在 Go 中用的计算 revision 的 hash 算法与 Java 是不统一的,而且 Go 与 Java 的办法签名信息是不雷同的,所以计算出来的 hash 值肯定是不一样的。

此不统一会导致如果 Go 利用和 Java 利用同时公布同一个服务的时候,Go 服务和 Java 服务的订正版本号必然是不雷同的,Consumer 须要别离缓存这两个订正版本的元数据。

3.2 利用注册机会

Dubbo-go v1.5.0 实现时,其中一个考量是全面向后兼容 v1.4.x。Dubbo-go v1.5.x 利用 consumer 既能够调用 Dubbo-go v1.4.x 利用的服务,也能够调用 Dubbo v2.6.x 利用的服务,当然也能够调用其对标的 v2.7.x 利用的服务。

为了达到兼容性,Dubbo-go v1.5.x 实现时面临一个问题:Dubbo-go provider 利用启动时有一个服务启动胜利,把利用信息注册到元数据中心之后,就会把实例注册到注册核心,而 Dubbo 2.7.x 的 provider 利用则是在其所有服务接口的信息注册到元数据中心后才会注册实例!

这个问题的结果就是:Dubbo-go v1.5.0 的 provider 每次公布接口到元数据中心的同时,都会触发 Dubbo-go v1.5.0 / Dubbo v2.7.x 的 consumer 利用拉取 Dubbo-go v1.5.0 利用信息,当 provider 公布的服务过多时 consumer 侧性能损耗非常明显!

Dubbo-go 在 v1.5.1 中曾经修复了这个问题,provider 在启动时先将其全副服务接口公布到元数据中心,而后注册实例到注册核心,缩小了 consumer 拉取元数据的次数。

正文完
 0