dubbo · 2022-10-31 0

dubbo 在 zookeeper 上的数据结构

一、配置

1.公共包

pom 文件:

<groupId>org.example</groupId>1
<artifactId>dubbo-common</artifactId>
<version>1.0.0</version>

接口:

public interface Service1 {

    String say1(Integer id);

    String walk1(Integer id);
}
public interface Service2 {

    String say2(Integer id);

    String walk2(Integer id);
}

2.provider1

pom 文件:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
    <relativePath/>
</parent>

<groupId>org.example</groupId>
<artifactId>spring-boot-dubbo-provider1</artifactId>
<version>1.0.0</version>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-dependencies-zookeeper-curator5</artifactId>
        <version>3.2.0</version>
        <type>pom</type>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.2.0</version>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>dubbo-common</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

配置:

# dubbo 配置
dubbo:
  # 应用
  application:
    name: provider1
    qos-enable: false
    # register-mode: all # 接口级+应用级均注册,接口级注册与应用级注册并存(/dubbo && /service),应用升级到 dubbo 3.0 后,服务端自动开启接口级 + 应用级双注册功能,默认无需开发者修改任何配置
    register-mode: interface # 只接口级注册(/dubbo)
    # register-mode: instance # 只应用级注册(/service)
  # 注册中心地址
  registry:
    address: zookeeper://127.0.0.1:2181
    # group: group_1
    timeout: 30000 # 连接超时时间,默认 30s
    session: 60000 # 会话超时时间,默认 60s
  # 协议
  protocol:
    name: dubbo
    port: 20881 # 默认 20880

java 类:

@SpringBootApplication
@EnableDubbo
public class Provider1Boot {

    public static void main(String[] args) {
        SpringApplication.run(Provider1Boot.class, args);
    }
}
@DubboService
public class Service1Impl implements Service1 {

    @Override
    public String say1(Integer id) {
        return "this is provider1 Service1#say1(Integer id)";
    }

    @Override
    public String walk1(Integer id) {
        return "this is provider1 Service1#walk1(Integer id)";
    }
}
@DubboService
public class Service2Impl implements Service2 {

    @Override
    public String say2(Integer id) {
        return "this is provider1 Service2#say2(Integer id)";
    }

    @Override
    public String walk2(Integer id) {
        return "this is provider1 Service2#say2(Integer id)";
    }
}

3.provider2

与 provider1 类似

4.consumer1

pom 文件:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
    <relativePath/>
</parent>

<groupId>org.example</groupId>
<artifactId>spring-boot-dubbo-consumer1</artifactId>
<version>1.0.0</version>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-dependencies-zookeeper-curator5</artifactId>
        <version>3.2.0</version>
        <type>pom</type>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.2.0</version>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>dubbo-common</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

配置:

# 服务端口
server:
  port: 9001

# dubbo 配置
dubbo:
  # 应用
  application:
    name: consumer1
    qos-enable: false
    # register-mode: all # 接口级+应用级均注册,接口级注册与应用级注册并存(/dubbo && /service),应用升级到 dubbo 3.0 后,服务端自动开启接口级 + 应用级双注册功能,默认无需开发者修改任何配置
    register-mode: interface # 只接口级注册(/dubbo)
    # register-mode: instance # 只应用级注册(/service)
  # 注册中心地址
  registry:
    address: zookeeper://127.0.0.1:2181
    # group: group_1
    timeout: 30000 # 连接超时时间,默认 30s
    session: 60000 # 会话超时时间,默认 60s
  # 协议
  protocol:
    name: dubbo
    port: 20883

java 类:

@SpringBootApplication
public class Consumer1Boot {

    public static void main(String[] args) {
        SpringApplication.run(Consumer1Boot.class, args);
    }
}
@RestController
public class IndexController {

    @DubboReference
    private Service1 service1;

    @RequestMapping("/")
    public String index(){
        return "this is consumer1 index";
    }

    @RequestMapping("/say")
    public String say(){
        return service1.say1(1);
    }
}

二、数据结构

1.接口级注册

(register-mode: interface 只接口级注册,数据结构在 /dubbo)
(dubbo providers 中有 register-mode=interface)
(dubbo consumers 中有 register-mode=interface)

/
  dubbo
    com.foo.Service1
      providers
        /dubbo/com.example.Service1/providers/dubbo://172.29.0.1:20881/com.example.Service1?anyhost=true&application=provider1&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=isolation&file-cache=true&generic=false&interface=com.example.Service1&methods=say1,walk1&pid=49586&prefer.serialization=fastjson2,hessian2&register-mode=interface&release=3.2.0&side=provider&timestamp=1733378044452
        /dubbo/com.example.Service1/providers/dubbo://172.29.0.1:20882/com.example.Service1?anyhost=true&application=provider2&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=isolation&file-cache=true&generic=false&interface=com.example.Service1&methods=say1,walk1&pid=49797&prefer.serialization=fastjson2,hessian2&register-mode=interface&release=3.2.0&side=provider&timestamp=1733378097017
      consumers
        /dubbo/com.example.Service1/consumers/consumer://172.29.0.1/com.example.Service1?application=consumer1&background=false&category=consumers&check=false&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&interface=com.example.Service1&methods=say1,walk1&pid=49989&qos.enable=false&register-mode=interface&release=3.2.0&side=consumer&sticky=false&timestamp=1733378130857&unloadClusterRelated=false
    com.foo.Service2
      providers
        /dubbo/com.example.Service2/providers/dubbo://172.29.0.1:20881/com.example.Service2?anyhost=true&application=provider1&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=isolation&file-cache=true&generic=false&interface=com.example.Service2&methods=say2,walk2&pid=49586&prefer.serialization=fastjson2,hessian2&register-mode=interface&release=3.2.0&side=provider&timestamp=1733378044156
        /dubbo/com.example.Service2/providers/dubbo://172.29.0.1:20882/com.example.Service2?anyhost=true&application=provider2&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=isolation&file-cache=true&generic=false&interface=com.example.Service2&methods=say2,walk2&pid=49797&prefer.serialization=fastjson2,hessian2&register-mode=interface&release=3.2.0&side=provider&timestamp=1733378096739

2.应用级注册

(register-mode: instance 只应用级注册,数据结构在 /service)
(dubbo consumers 中有 register-mode=instance)

/
  dubbo
    com.foo.Service1
      consumers
        /dubbo/com.example.Service1/consumers/consumer://172.29.0.1/com.example.Service1?application=consumer1&background=false&category=consumers&check=false&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&interface=com.example.Service1&methods=say1,walk1&pid=4746&qos.enable=false&register-mode=instance&release=3.2.0&side=consumer&sticky=false&timestamp=1733381260684&unloadClusterRelated=false
  services
    provider1
      172.29.0.1:20881
    provider2
      172.29.0.1:20882
/services/provider1/172.29.0.1:20881 值为:
{"name":"provider1","id":"172.29.0.1:20881","address":"172.29.0.1","port":20881,"sslPort":null,"payload":{"@class":"org.apache.dubbo.registry.zookeeper.ZookeeperInstance","id":"172.29.0.1:20881","name":"provider1","metadata":{"dubbo.endpoints":"[{\"port\":20881,\"protocol\":\"dubbo\"}]","dubbo.metadata-service.url-params":"{\"prefer.serialization\":\"fastjson2,hessian2\",\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"3.2.0\",\"side\":\"provider\",\"port\":\"20881\",\"protocol\":\"dubbo\"}","dubbo.metadata.revision":"e0795da6b2894d26ed0a05d224aa0e2d","dubbo.metadata.storage-type":"local","timestamp":"1733381250031"}},"registrationTimeUTC":1733381250128,"serviceType":"DYNAMIC","uriSpec":null}

三、数据结构

1.注册中心

# application.yml
dubbo:
  registry:
    address: zookeeper://localhost:2181
    # group: group_1
    timeout: 30000 # 连接超时时间,默认 30s
    session: 60000 # 会话超时时间,默认 60s

dubbo-zookeeper-registry

zookeeper 中存储的 dubbo 数据分为三级:

序号 节点 说明
1 根节点 dubbo
2 一级子节点 提供服务的服务名
3 一级子节点 固定的四个子节点:configurators, consumers, providers, routers

查看节点信息:

[zk: localhost:2181(CONNECTED) 1] ls /
[dubbo, services, zookeeper]
[zk: localhost:2181(CONNECTED) 2] ls /dubbo
[com.foo.BarService, com.foo.BazService, config, mapping, metadata, org.apache.dubbo.metadata.MetadataService]
[zk: localhost:2181(CONNECTED) 3] ls /dubbo/com.foo.BarService
[configurators, consumers, providers, routers]
[zk: localhost:2181(CONNECTED) 4] ls /dubbo/com.foo.BarService/providers
[dubbo%3A%2F%2F172.17.0.1%3A20881%2Fcom.foo.BarService%3Fanyhost%3Dtrue%26application%3Dprovider1%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26executor-management-mode%3Disolation%26file-cache%3Dtrue%26generic%3Dfalse%26interface%3Dcom.foo.BarService%26methods%3Dsay%26pid%3D3755%26prefer.serialization%3Dfastjson2%2Chessian2%26release%3D3.2.0%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1693844361821, dubbo%3A%2F%2F172.17.0.1%3A20882%2Fcom.foo.BarService%3Fanyhost%3Dtrue%26application%3Dprovider2%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26executor-management-mode%3Disolation%26file-cache%3Dtrue%26generic%3Dfalse%26interface%3Dcom.foo.BarService%26methods%3Dsay%26pid%3D3987%26prefer.serialization%3Dfastjson2%2Chessian2%26release%3D3.2.0%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1693844370960]
[zk: localhost:2181(CONNECTED) 5] ls /dubbo/com.foo.BarService/consumers
[consumer%3A%2F%2F172.17.0.1%2Fcom.foo.BarService%3Fapplication%3Dconsumer1%26background%3Dfalse%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26executor-management-mode%3Disolation%26file-cache%3Dtrue%26interface%3Dcom.foo.BarService%26methods%3Dsay%26pid%3D4256%26qos.enable%3Dtrue%26release%3D3.2.0%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1693844399089%26unloadClusterRelated%3Dfalse, consumer%3A%2F%2F172.17.0.1%2Fcom.foo.BarService%3Fapplication%3Dconsumer2%26background%3Dfalse%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26executor-management-mode%3Disolation%26file-cache%3Dtrue%26interface%3Dcom.foo.BarService%26methods%3Dsay%26pid%3D4471%26qos.enable%3Dtrue%26release%3D3.2.0%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1693844406717%26unloadClusterRelated%3Dfalse]

providers 进行 url 解码,如下:

[dubbo://172.17.0.1:20881/com.foo.BarService?anyhost=true&application=provider1&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=isolation&file-cache=true&generic=false&interface=com.foo.BarService&methods=say&pid=3755&prefer.serialization=fastjson2,hessian2&release=3.2.0&service-name-mapping=true&side=provider&timestamp=1693844361821, dubbo://172.17.0.1:20882/com.foo.BarService?anyhost=true&application=provider2&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=isolation&file-cache=true&generic=false&interface=com.foo.BarService&methods=say&pid=3987&prefer.serialization=fastjson2,hessian2&release=3.2.0&service-name-mapping=true&side=provider&timestamp=1693844370960]

提供者属性:

属性 描述
anyhost true
application provider1 应用名称
background false
deprecated false
dubbo 2.0.2 dubbo 版本
dynamic true
executor isolation
file-cache true
generic false
interface com.foo.BarService 接口名称
methods say 接口方法名
pid 3755 进程号
prefer.serialization fastjson2,hessian2
release 3.2.0
service-name-mapping true
side provider 消费端或服务端
timestamp 1693844361821 时间辍

consumer 进行 url 解码,如下:

[consumer://172.17.0.1/com.foo.BarService?application=consumer1&background=false&category=consumers&check=false&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&interface=com.foo.BarService&methods=say&pid=4256&qos.enable=true&release=3.2.0&side=consumer&sticky=false&timestamp=1693844399089&unloadClusterRelated=false, consumer://172.17.0.1/com.foo.BarService?application=consumer2&background=false&category=consumers&check=false&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&interface=com.foo.BarService&methods=say&pid=4471&qos.enable=true&release=3.2.0&side=consumer&sticky=false&timestamp=1693844406717&unloadClusterRelated=false]

消费者属性:

属性 描述
application consumer1 应用名称
background false
category consumers 类型
check false
dubbo 2.0.2 dubbo 版本
executor-management-mode isolation
file-cache true
interface com.foo.BarService 接口名称
methods say 接口方法名
pid 4256 进程号
qos.enable true
release 3.2.0
side consumer 消费端或服务端
sticky false
timestamp 1693844399089 时间辍
unloadClusterRelated false

流程:

  • 服务提供者启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址。
  • 服务消费者启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
  • 监控中心启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址。

支持以下功能:

  • 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息
  • 当注册中心重启时,能自动恢复注册数据,以及订阅请求
  • 当会话过期时,能自动恢复注册数据,以及订阅请求
  • 当设置 <dubbo:registry check="false" /> 时,记录失败注册和订阅请求,后台定时重试
  • 可通过 <dubbo:registry username="admin" password="1234" /> 设置 zookeeper 登录信息
  • 可通过 <dubbo:registry group="dubbo" /> 设置 zookeeper 的根节点,不配置将使用默认的根节点。
  • 支持 * 号通配符 <dubbo:reference group="*" version="*" />,可订阅服务的所有分组和所有版本的提供者

2.元数据中心

元数据

dubbo:
  metadata-report:
    address: zookeeper://127.0.0.1:2181

它的元数据信息位于以下节点:

Provider: /dubbo/metadata/{interface name}/{version}/{group}/provider/{application name}
Consumer: /dubbo/metadata/{interface name}/{version}/{group}/consumer/{application name}

当 version 或者 group 不存在时,version 路径和 group 路径会取消:

Provider: /dubbo/metadata/{interface name}/provider/{application name}
Consumer: /dubbo/metadata/{interface name}/consumer/{application name}

查看节点信息:

[zk: localhost:2181(CONNECTED) 1] ls /dubbo
[com.foo.BarService, com.foo.BazService, config, mapping, metadata, org.apache.dubbo.metadata.MetadataService]
[zk: localhost:2181(CONNECTED) 2] ls /dubbo/metadata
[com.foo.BarService, com.foo.BazService]
[zk: localhost:2181(CONNECTED) 3] ls /dubbo/metadata/com.foo.BarService
[consumer, provider]
[zk: localhost:2181(CONNECTED) 4] ls /dubbo/metadata/com.foo.BarService/provider
[provider1, provider2]
[zk: localhost:2181(CONNECTED) 5] ls /dubbo/metadata/com.foo.BarService/provider/provider1
[]
[zk: localhost:2181(CONNECTED) 6] get /dubbo/metadata/com.foo.BarService/provider/provider1
{"annotations":[],"canonicalName":"com.foo.BarService","codeSource":"file:/home/zxm/IdeaProjects/jdk8-demo/dubbo/dubbo-common/target/classes/","methods":[{"annotations":[],"name":"say","parameterTypes":["java.lang.Integer"],"parameters":[],"returnType":"java.lang.String"}],"parameters":{"dubbo":"2.0.2","side":"provider","interface":"com.foo.BarService","release":"3.2.0","pid":"3755","anyhost":"true","application":"provider1","executor-management-mode":"isolation","file-cache":"true","methods":"say","deprecated":"false","service-name-mapping":"true","qos.enable":"true","generic":"false","bind.port":"20881","bind.ip":"172.17.0.1","prefer.serialization":"fastjson2,hessian2","background":"false","dynamic":"true","timestamp":"1693844361821"},"types":[{"enums":[],"items":[],"properties":{},"type":"java.lang.String"},{"enums":[],"items":[],"properties":{},"type":"java.lang.Integer"}],"uniqueId":"com.foo.BarService@file:/home/zxm/IdeaProjects/jdk8-demo/dubbo/dubbo-common/target/classes/"}
[zk: localhost:2181(CONNECTED) 7] ls /dubbo/metadata/com.foo.BarService/consumer
[consumer1, consumer2]
[zk: localhost:2181(CONNECTED) 8] ls /dubbo/metadata/com.foo.BarService/consumer/consumer1
[]
[zk: localhost:2181(CONNECTED) 9] get /dubbo/metadata/com.foo.BarService/consumer/consumer1
{"release":"3.2.0","side":"consumer","pid":"4256","interface":"com.foo.BarService","application":"consumer1","dubbo":"2.0.2","executor-management-mode":"isolation","file-cache":"true","register.ip":"172.17.0.1","methods":"say","background":"false","sticky":"false","qos.enable":"true","unloadClusterRelated":"false","timestamp":"1693844399089"}

providers 的数据格式化为:

{
    "annotations": [],
    "canonicalName": "com.foo.BarService",
    "codeSource": "file:/home/zxm/IdeaProjects/jdk8-demo/dubbo/dubbo-common/target/classes/",
    "methods": [{
        "annotations": [],
        "name": "say",
        "parameterTypes": ["java.lang.Integer"],
        "parameters": [],
        "returnType": "java.lang.String"
    }],
    "parameters": {
        "dubbo": "2.0.2",
        "side": "provider",
        "interface": "com.foo.BarService",
        "release": "3.2.0",
        "pid": "3755",
        "anyhost": "true",
        "application": "provider1",
        "executor-management-mode": "isolation",
        "file-cache": "true",
        "methods": "say",
        "deprecated": "false",
        "service-name-mapping": "true",
        "qos.enable": "true",
        "generic": "false",
        "bind.port": "20881",
        "bind.ip": "172.17.0.1",
        "prefer.serialization": "fastjson2,hessian2",
        "background": "false",
        "dynamic": "true",
        "timestamp": "1693844361821"
    },
    "types": [{
        "enums": [],
        "items": [],
        "properties": {},
        "type": "java.lang.String"
    }, {
        "enums": [],
        "items": [],
        "properties": {},
        "type": "java.lang.Integer"
    }],
    "uniqueId": "com.foo.BarService@file:/home/zxm/IdeaProjects/jdk8-demo/dubbo/dubbo-common/target/classes/"
}

consumers 的数据格式化为:

{
    "release": "3.2.0",
    "side": "consumer",
    "pid": "4256",
    "interface": "com.foo.BarService",
    "application": "consumer1",
    "dubbo": "2.0.2",
    "executor-management-mode": "isolation",
    "file-cache": "true",
    "register.ip": "172.17.0.1",
    "methods": "say",
    "background": "false",
    "sticky": "false",
    "qos.enable": "true",
    "unloadClusterRelated": "false",
    "timestamp": "1693844399089"
}

地址发现 - 接口-应用名映射

在Dubbo 3.0 中,默认使用了服务自省机制去实现服务发现。

简而言之,服务自省机制需要能够通过 interface name 去找到对应的 application name,这个关系可以是一对多的,即一个 service name 可能会对应多个不同的 application name。在 3.0 中,元数据中心提供此项映射的能力。

在上面提到,service name 和 application name 可能是一对多的,在 zookeeper 中,使用单个 key-value 进行保存,多个 application name 通过英文逗号,隔开。由于是单个 key-value 去保存数据,在多客户端的情况下可能会存在并发覆盖的问题。因此,我们使用 zookeeper 中的版本机制 version 去解决该问题。在 zookeeper 中,每一次对数据进行修改,dataVersion 都会进行增加,我们可以利用 version 这个机制去解决多个客户端同时更新映射的并发问题。不同客户端在更新之前,先去查一次 version,当作本地凭证。在更新时,把凭证 version 传到服务端比对 version, 如果不一致说明在此期间被其他客户端修改过,重新获取凭证再进行重试(CAS)。目前如果重试6次都失败的话,放弃本次更新映射行为。

查看节点信息:

[zk: localhost:2181(CONNECTED) 1] ls /dubbo
[com.foo.BarService, com.foo.BazService, config, mapping, metadata, org.apache.dubbo.metadata.MetadataService]
[zk: localhost:2181(CONNECTED) 2] ls /dubbo/mapping
[com.foo.BarService, com.foo.BazService]
[zk: localhost:2181(CONNECTED) 3] ls /dubbo/mapping/com.foo.BarService
[]
[zk: localhost:2181(CONNECTED) 4] get /dubbo/mapping/com.foo.BarService
provider1,provider2

3. 配置中心

dubbo:
  config-center:
    address: zookeeper://127.0.0.1:2181

dubbo-zookeeper-configcenter

[zk: localhost:2181(CONNECTED) 1] ls /dubbo
[com.foo.BarService, com.foo.BazService, config, mapping, metadata, org.apache.dubbo.metadata.MetadataService]
[zk: localhost:2181(CONNECTED) 2] ls /dubbo/config
[DUBBO_SERVICEDISCOVERY_MIGRATION, dubbo]
[zk: localhost:2181(CONNECTED) 3] ls /dubbo/config/dubbo
[]