
Dubbo3 架构服务注册Zookeeper注册数据基本结构我们可以用zkCli.cmd来链接服务查看对应的节点 我们可以想象成一个一个的文件夹使用ZooInspector来查看对应的节点接口级注册在这个过程中每个 Provider 通过特定的 key 向注册中心注册本机可访问地址注册中心通过这个 key 对 provider 实例地址进行聚合Consumer 通过同样的 key 从注册中心订阅以便及时收到聚合后的地址列表数据结构接口易用性代价一个事物总是有其两面性Dubbo2 地址模型带来易用性和强大功能的同时也给整个架构的水平可扩展性带来了一些限制。这个问题在普通规模的微服务集群下是完全感知不到的而随着集群规模的增长当整个集群内应用、机器达到一定数量时整个集群内的各个组件才开始遇到规模瓶颈。在总结包括阿里巴巴、工商银行等多个典型的用户在生产环境特点后我们总结出以下两点突出问题如图中红色所示首先注册中心集群容量达到上限阈值。由于所有的 URL 地址数据都被发送到注册中心注册中心的存储容量达到上限推送效率也随之下降。而在消费端这一侧Dubbo2 框架常驻内存已超 40%每次地址推送带来的 cpu 等资源消耗率也非常高影响正常的业务调用。为什么会出现这个问题我们以一个具体 provider 示例进行展开来尝试说明为何应用在接口级地址模型下容易遇到容量问题。 青蓝色部分假设这里有一个普通的 Dubbo Provider 应用该应用内部定义有 10 个 RPC Service应用被部署在 100 个机器实例上。这个应用在集群中产生的数据量将会是 “Service 数 * 机器实例数”也就是 10 * 100 1000 条。数据被从两个维度放大从地址角度。100 条唯一的实例地址被放大 10 倍从服务角度。10 条唯一的服务元数据被放大 100 倍应用级注册那这样 1个服务有10个服务接口 100个实例对应数据应该mapping里面有 10条 services 里面就100 条 总共是110条这里元数据可以放到元数据中心可以和注册中心一样也可以放到本地消费者获取需要发送rpc调用默认发送本地 对应配置Provider和Consumer双版本支持参数讲解Provicer提供方dubbo.application.register-mode参数参数含义interface只有接口级注册instance只有应用级注册all默认接口级注册和应用级注册并存Consumer消费方dubbo.application.service-discovery.migration:FORCE_INTERFACE参数参数含义FORCE_INTERFACE只消费接口级地址如无地址则报错单订阅2.x地址APPLICATION_FIRST(默认)智能决策接口级/应用级地址双订阅FORCE_APPLICATION只消费应用级地址如无地址则报错单订阅3.x地址为什么Dubbo3支持双版本注册为了方便迁移 Dubbo3.0之前都是接口级别注册Dubbo3之后都是应用级注册服务注册源码分析服务启动找入口 是EnableDubbo注册DubboDeployApplicationListener这里监听器是监听Spring容器启动之后我们再进行服务注册不符订阅应用注册启动本地服务扫描我们DubboService 注册BeanDefinitionDubboComponentScanRegistrar 执行的时候会调用registerBeanDefinitions注册后置处理器ServiceAnnotationPostProcessorServiceAnnotationPostProcessor 实现BeanDefinitionRegistryPostProcessor则进行BeanDefintion的注册注册userServiceImpl注册ServieBean的BeanDefinition加载配置文件配置的加载服务导出面试题Dubbo3是什么时候进行服务导出的Dubbo3通过DubboDeployApplicationListener监听Spring的启动当Spring启动会发送ContextRefreshedEvent事件DubboDeployApplicationListener监听这个事件进行服务导出会把我们服务注册到注册中心并且启动本地服务。问题 服务导出 获取服务配置 服务注册服务 启动服务Netty/Tomcat那先注册再启动还是先启动再注册先启动再注册如果先注册再启动那么注册完还没有启动的时候别的服务就调用进来这就会出现调用失败这里注意有接口级的注册和应用的注册入口分析我们通过DubboDeployApplicationListener如下图这里就是核心内容接口级注册判断注册方式exportServices是进行接口级注册由于他的调用链路比较长我们直接来到 ServiceConfig#doExportUrls通过配置的模式获取对应注册地址可以看到这里简化的配置比较容易理解了双注册模式配置查询 对应参数为dubbo.application.register-mode 默认值为all如果用户配置了接口注册模式配置则只走接口级配置 这里默认值为interface满足应用级注册就添加一个应用级注册的地址满足接口级注册配置就添加一个接口级注册地址这个方法是根据服务注册模式来判断使用接口级注册地址还是应用级注册地址分别如下所示 配置信息 dubbo.application.register-mode 配置值interface接口级注册instance应用级注册all接口级别和应用级都注册最终的注册地址配置如下 接口级注册地址registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?applicationdubbo-demo-api-providerdubbo2.0.2pid9008registryzookeeperrelease3.0.8timestamp1653703292768应用级注册地址service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?applicationdubbo-demo-api-providerdubbo2.0.2pid10275registryzookeeperrelease3.0.8timestamp1653704425920前面说了这个注册服务的配置地址会由Dubbo内部进行判断如果判断是all的话会自动将一个配置的注册地址转变为两个一个是传统的接口级注册一个是应用级注册使用的配置地址生成invoke我们来看key1:获取对应的invoke然后我们再看注册中心注册服务数据的源码 如果想要查看源码细节可以在RegistryProtocol类型的export(final Invoker originInvoker) 方法的如下代码位置打断点RegistryProtocol的export方法的注册中心注册数据代码如下:1、暴露本地服务就是提供给调用方一个调用的接口服务这个我们后面来说2、获取注册Registry 这里如果是接口级注册则是ZookeeperRegistry如果应用级注册ServiceDiscoveryRegistry3、我们看一下registry接口级注册我们再ZookeeperRegistry#doRegistry打上端点堆栈信息中我们可以看到调用它的方法是应用级注册将服务提供者数据转换到本地内存的元数据信息中映射数据注册应用应用级注册应用元数据信息注册实例信息这里最终会调用到ZookeeperServiceDiscovery#doRegister