当前位置: 首页 > news >正文

中山网站建设熊掌号桂林象鼻山景区官网

中山网站建设熊掌号,桂林象鼻山景区官网,怎么实现网站注册页面,网站常见错误代码简介#xff1a; 随着云原生时代的到来#xff0c;Dubbo 3.0 的一个很重要的目标就是全面拥抱云原生。正因如此#xff0c;Dubbo 3.0 为了能够更好的适配云原生#xff0c;将原来的接口级服务发现机制演进为应用级服务发现机制。 作者介绍 熊聘#xff0c;Github账号pin…简介 随着云原生时代的到来Dubbo 3.0 的一个很重要的目标就是全面拥抱云原生。正因如此Dubbo 3.0 为了能够更好的适配云原生将原来的接口级服务发现机制演进为应用级服务发现机制。 作者介绍 熊聘Github账号pinxiongApache Dubbo贡献者关注RPC、Service Mesh和云原生等领域。现任职于携程国际事业部研发团队负责市场营销、云原生等相关工作。 背景 随着云原生时代的到来Dubbo 3.0 的一个很重要的目标就是全面拥抱云原生。正因如此Dubbo 3.0 为了能够更好的适配云原生将原来的接口级服务发现机制演进为应用级服务发现机制。 基于应用级服务发现机制Dubbo 3.0 能大幅降低框架带来的额外资源消耗大幅提升资源利用率主要体现在 单机常驻内存下降 75%能支持的集群实例规模以百万计的集群注册中心总体数据量下降超 90% 目前关于 Dubbo 服务端暴露流程的技术文章很多但是都是基于 Dubbo 接口级服务发现机制来解读的。在 Dubbo 3.0 的应用级服务发现机制下服务端暴露流程与之前有很大的变化本文希望可以通过 对Dubbo 3.0 源码理解来解析服务端暴露全流程。 什么是应用级服务发现 简单来说以前 Dubbo 是将接口的信息全部注册到注册中心而一个应用实例一般会存在多个接口这样一来注册的数据量就要大很多而且有冗余。应用级服务发现的机制是同一个应用实例仅在注册中心注册一条数据这种机制主要解决以下几个问题 对齐主流微服务模型如Spring Cloud支持 Kubernetes native serviceKubernetes 中维护调度的服务都是基于应用实例级不支持接口级减少注册中心数据存储能力降低了地址变更推送的压力 假设应用 dubbo-application 部署了 3 个实例instance1, instance2, instance3并且对外提供了 3 个接口sayHello, echo, getVersion分别设置了不同的超时时间。在接口级和应用级服务发现机制下注册到注册中心的数据是截然不同的。如下图所示 接口级服务发现机制下注册中心中的数据 sayHello: [{application:dubbo-application,name:instance1, ip:127.0.0.1, metadata:{timeout:1000}},{application:dubbo-application,name:instance2, ip:127.0.0.2, metadata:{timeout:2000}},{application:dubbo-application,name:instance3, ip:127.0.0.3, metadata:{timeout:3000}}, ], echo: [{application:dubbo-application,name:instance1, ip:127.0.0.1, metadata:{timeout:1000}},{application:dubbo-application,name:instance2, ip:127.0.0.2, metadata:{timeout:2000}},{application:dubbo-application,name:instance3, ip:127.0.0.3, metadata:{timeout:3000}}, ], getVersion: [{application:dubbo-application,name:instance1, ip:127.0.0.1, metadata:{timeout:1000}},{application:dubbo-application,name:instance2, ip:127.0.0.2, metadata:{timeout:2000}},{application:dubbo-application,name:instance3, ip:127.0.0.3, metadata:{timeout:3000}} ]应用级服务发现机制下注册中心中的数据 dubbo-application: [{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}} ]通过对比我们可以发现采用应用级服务发现机制确实使注册中心中的数据量减少了很多那些原有的接口级的数据存储在元数据中心中。 服务端暴露全流程 引入应用级服务发现机制以后Dubbo 3.0 服务端暴露全流程和之前有很大的区别。暴露服务端全流程的核心代码在 DubboBootstrap#doStart 中具体如下 private void doStart() {// 1. 暴露Dubbo服务exportServices();// If register consumer instance or has exported servicesif (isRegisterConsumerInstance() || hasExportedServices()) {// 2. 暴露元数据服务exportMetadataService();// 3. 定时更新和上报元数据registerServiceInstance();....}...... }假设以 Zookeeper 作为注册中对外暴露 Triple 协议的服务为例服务端暴露全流程时序图如下 我们可以看到整个的暴露流程还是挺复杂的一共可以分为四个部分 暴露 injvm 协议的服务注册 service-discovery-registry 协议暴露 Triple 协议的服务并注册 registry 协议暴露 MetadataService 服务 下面会分别从这四个部分对服务暴露全流程进行详细讲解。 1、暴露 injvm 协议的服务 injvm 协议的服务是暴露在本地的主要原因是在一个应用上往往既有 Service暴露服务又有 Reference服务引用的情况存在并且 Reference 引用的服务就是在该应用上暴露的 Service。为了支持这种使用场景Dubbo 提供了 injvm 协议将 Service 暴露在本地Reference 就可以不需要走网络直接在本地调用 Service。 整体时序图 由于这部分内容在之前的接口级服务发现机制中是类似的所以相关的核心代码就不在这里展开讨论了。 2、注册 service-discovery-registry 协议 注册 service-discovery-registry 协议的核心目的是为了注册与服务相关的元数据默认情况下元数据通过 InMemoryWritableMetadataService 将数据存储在本地内存和本地文件。 整体时序图 核心代码在 ServiceConfig#exportRemote 中具体如下 注册 service-discovery-registry 协议的入口 private URL exportRemote(URL url, ListURL registryURLs) {if (CollectionUtils.isNotEmpty(registryURLs)) {// 如果是多个注册中心通过循环对每个注册中心进行注册for (URL registryURL : registryURLs) {// 判断是否是service-discovery-registry协议// 将service-name-mapping参数的值设置为trueif (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {url url.addParameterIfAbsent(SERVICE_NAME_MAPPING_KEY, true);}......// 注册service-discovery-registry协议复用服务暴露流程doExportUrl(registryURL.putAttribute(EXPORT_KEY, url), true);}......return url; }invoker 中包装 Metadata 核心代码在 ServiceConfig#doExportUrl 中具体如下 private void doExportUrl(URL url, boolean withMetaData) {Invoker? invoker PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);// 此时的withMetaData的值为true// 将invoker包装成DelegateProviderMetaDataInvokerif (withMetaData) {invoker new DelegateProviderMetaDataInvoker(invoker, this);}Exporter? exporter PROTOCOL.export(invoker);exporters.add(exporter); }通过 RegistryProtocol 将 Invoker 转化成 Exporter 核心代码在 ProtocolListenerWrapper#export 中具体如下 public T ExporterT export(InvokerT invoker) throws RpcException {// 此时的protocol为RegistryProtocol类型if (UrlUtils.isRegistry(invoker.getUrl())) {return protocol.export(invoker);}...... }RegistryProtocol 将 Invoker 转化成 Exporter 的核心流程 核心代码在 RegistryProtocol#export 中具体如下 public T ExporterT export(final InvokerT originInvoker) throws RpcException {URL registryUrl getRegistryUrl(originInvoker);URL providerUrl getProviderUrl(originInvoker);......// 再次暴露Triple协议的服务final ExporterChangeableWrapperT exporter doLocalExport(originInvoker, providerUrl);// registryUrl中包含service-discovery-registry协议// 通过该协议创建ServiceDiscoveryRegistry对象// 然后组合RegistryServiceListener监听器// 最后包装成ListenerRegistryWrapper对象final Registry registry getRegistry(registryUrl);final URL registeredProviderUrl getUrlToRegistry(providerUrl, registryUrl);boolean register providerUrl.getParameter(REGISTER_KEY, true);if (register) {// 注册service-discovery-registry协议// 触发RegistryServiceListener的onRegister事件register(registry, registeredProviderUrl);}......// 触发RegistryServiceListener的onRegister事件notifyExport(exporter);return new DestroyableExporter(exporter); }暴露 Triple 协议的服务 核心代码在 RegistryProtocol#doLocalExport 中具体如下 private T ExporterChangeableWrapperT doLocalExport(final InvokerT originInvoker, URL providerUrl) {String key getCacheKey(originInvoker);// 此时的protocol为Triple协议的代理类// 和暴露injvm协议的PROTOCOL相同return (ExporterChangeableWrapperT) bounds.computeIfAbsent(key, s - {Invoker? invokerDelegate new InvokerDelegate(originInvoker, providerUrl);return new ExporterChangeableWrapper((ExporterT) protocol.export(invokerDelegate), originInvoker);}); }注册service-discovery-registry协议 核心代码在 ServiceDiscoveryRegistry#register和ServiceDiscoveryRegistry#doRegister 中具体如下 1、ServiceDiscoveryRegistry#register public final void register(URL url) {// 只有服务端Provider才需要注册if (!shouldRegister(url)) {return;}// 注册service-discovery-registry协议doRegister(url); }2、ServiceDiscoveryRegistry#doRegister public void doRegister(URL url) {url addRegistryClusterKey(url);// 注册元数据if (writableMetadataService.exportURL(url)) {if (logger.isInfoEnabled()) {logger.info(format(The URL[%s] registered successfully., url.toString()));}} else {if (logger.isWarnEnabled()) {logger.warn(format(The URL[%s] has been registered., url.toString()));}} }注册元数据 核心代码在 InMemoryWritableMetadataService#exportURL 中具体如下 public boolean exportURL(URL url) {// 如果是MetadataService则不注册元数据if (MetadataService.class.getName().equals(url.getServiceInterface())) {this.metadataServiceURL url;return true;}updateLock.readLock().lock();try {String[] clusters getRegistryCluster(url).split(,);for (String cluster : clusters) {MetadataInfo metadataInfo metadataInfos.computeIfAbsent(cluster, k - new MetadataInfo(ApplicationModel.getName()));// 将Triple协议的服务中接口相关的数据生成ServiceInfo// 将ServiceInfo注册到MetadataInfo中metadataInfo.addService(new ServiceInfo(url));}metadataSemaphore.release();return addURL(exportedServiceURLs, url);} finally {updateLock.readLock().unlock();} }发布 onRegister 事件 核心代码在 ListenerRegistryWrapper#register 中具体如下 public void register(URL url) {try {// registry为ServiceDiscoveryRegistry对象// 此时已经调用完ServiceDiscoveryRegistry#registry方法registry.register(url);} finally {if (CollectionUtils.isNotEmpty(listeners) !UrlUtils.isConsumer(url)) {RuntimeException exception null;for (RegistryServiceListener listener : listeners) {if (listener ! null) {try {// 注册完service-discovery-registry协议后发布onRegister事件listener.onRegister(url, registry);} catch (RuntimeException t) {logger.error(t.getMessage(), t);exception t;}}}if (exception ! null) {throw exception;}}} }发布服务注册事件 核心代码在 RegistryProtocol#notifyExport 中具体如下 private T void notifyExport(ExporterChangeableWrapperT exporter) {ListRegistryProtocolListener listeners ExtensionLoader.getExtensionLoader(RegistryProtocolListener.class).getActivateExtension(exporter.getOriginInvoker().getUrl(), registry.protocol.listener);if (CollectionUtils.isNotEmpty(listeners)) {for (RegistryProtocolListener listener : listeners) {// 发布RegistryProtocolListener的onExport事件listener.onExport(this, exporter);}} }我们可以看出注册 service-discovery-registry 协议的核心目的是为了将服务的接口相关的信息存储在内存中。从兼容性和平滑迁移两方面来考虑社区在实现的时候采取复用 ServiceConfig 的暴露流程的方式。 3、暴露Triple协议服务并注册registry协议 暴露 Triple 协议的服务并注册 registry 协议是 Dubbo 3.0 服务暴露的核心流程一共分为两部分 暴露 Triple 协议的服务注册 registry 协议 由于暴露 Triple 协议服务的流程和暴露 Injvm 协议服务的流程是一致的所以不再赘述。注册 registry 协议的过程仅仅注册了应用实例相关的信息也就是之前提到的应用级服务发现机制。 整体时序图 通过 InterfaceCompatibleRegistryProtocol 将 Invoker 转化成 Exporter 核心代码在 ProtocolListenerWrapper#export 中具体如下 public T ExporterT export(InvokerT invoker) throws RpcException {// 此时的protocol为InterfaceCompatibleRegistryProtocol类型继承了RegistryProtocol// 注意在注册service-discovery-registry协议的时候protocol为RegistryProtocol类型if (UrlUtils.isRegistry(invoker.getUrl())) {return protocol.export(invoker);}...... }RegistryProtocol 将 Invoker 转化成 Exporter 的核心流程 核心代码在 RegistryProtocol#export 中具体如下 public T ExporterT export(final InvokerT originInvoker) throws RpcException {URL registryUrl getRegistryUrl(originInvoker);URL providerUrl getProviderUrl(originInvoker);......// 再次暴露Triple协议的服务final ExporterChangeableWrapperT exporter doLocalExport(originInvoker, providerUrl);// registryUrl中包含registry协议// 通过该协议创建ZookeeperRegistry对象// 然后组合RegistryServiceListener监听器// 最后包装成ListenerRegistryWrapper对象// 注意// 1. service-discovery-registry协议对应的是ServiceDiscoveryRegistry// 2. registry协议对应的是ZookeeperRegistryfinal Registry registry getRegistry(registryUrl);final URL registeredProviderUrl getUrlToRegistry(providerUrl, registryUrl);boolean register providerUrl.getParameter(REGISTER_KEY, true);if (register) {// 注册registry协议// 触发RegistryServiceListener的onRegister事件register(registry, registeredProviderUrl);}......// 发布RegistryProtocolListener的onExport事件notifyExport(exporter);return new DestroyableExporter(exporter); }注册 registry 协议 核心代码在 FailbackRegistry#register 和 ServiceDiscoveryRegistry#doRegister 中ZookeeperRegistry 继承 FailbackRegistry中具体如下 1、FailbackRegistry#register public void register(URL url) {if (!acceptable(url)) {......try {// 注册registry协议doRegister(url);} catch (Exception e) {......}} }2、ServiceDiscoveryRegistry#doRegister public void doRegister(URL url) {try {// 在zookeeper上注册Provider// 目录/dubbo/xxxService/providers/***// 数据dubbo://192.168.31.167:20800/xxxService?anyhosttrue// applicationapplication-nameasyncfalsedeprecatedfalsedubbo2.0.2// dynamictruefile.cachefalsegenericfalseinterfacexxxService// metadata-typeremotemethodshellopid82470release// service-name-mappingtruesideprovidertimestamp1629588251493zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true));} catch (Throwable e) {throw new RpcException(Failed to register url to zookeeper getUrl() , cause: e.getMessage(), e);} }订阅地址变更 核心代码在 FailbackRegistry#subscribe 和 ZookeeperRegistry#doSubscribe 中具体如下 1、FailbackRegistry#subscribe public void subscribe(URL url, NotifyListener listener) {......try {// 调用ZookeeperRegistry#doSubscribedoSubscribe(url, listener);} catch (Exception e) {...... }2、ZookeeperRegistry#doSubscribe public void doSubscribe(final URL url, final NotifyListener listener) {try {if (ANY_VALUE.equals(url.getServiceInterface())) {......} else {......for (String path : toCategoriesPath(url)) {ConcurrentMapNotifyListener, ChildListener listeners zkListeners.computeIfAbsent(url, k - new ConcurrentHashMap());ChildListener zkListener listeners.computeIfAbsent(listener, k - new RegistryChildListenerImpl(url, path, k, latch));if (zkListener instanceof RegistryChildListenerImpl) {((RegistryChildListenerImpl) zkListener).setLatch(latch);}// 创建临时节点用来存储configurators数据// 目录/dubbo/xxxService/configurators// 数据应用的配置信息可以在dubbo-admin中进行修改默认为空zkClient.create(path, false);// 添加监听器用来监听configurators中的变化ListString children zkClient.addChildListener(path, zkListener);if (children ! null) {urls.addAll(toUrlsWithEmpty(url, path, children));}}......}} catch (Throwable e) {......} }建立暴露的 Triple 协议服务与 Metadata 之间的联系 核心代码在 ServiceConfig#exportUrl、MetadataUtils#publishServiceDefinition、InMemoryWritableMetadataService#publishServiceDefinition、RemoteMetadataServiceImpl#publishServiceDefinition 和 MetadataReport#storeProviderMetadata 中具体如下 1、ServiceConfig#exportUrl private void exportUrl(URL url, ListURL registryURLs) {......if (!SCOPE_NONE.equalsIgnoreCase(scope)) {......if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {url exportRemote(url, registryURLs);// 发布事件更新服务接口相关的数据MetadataUtils.publishServiceDefinition(url);}}...... }2、MetadataUtils#publishServiceDefinition public static void publishServiceDefinition(URL url) {// 将服务接口相关的数据存在到InMemoryWritableMetadataService中WritableMetadataService.getDefaultExtension().publishServiceDefinition(url);// 将服务接口相关的数据存在到远端的元数据中心if (REMOTE_METADATA_STORAGE_TYPE.equalsIgnoreCase(url.getParameter(METADATA_KEY))) {getRemoteMetadataService().publishServiceDefinition(url);} }3、InMemoryWritableMetadataService#publishServiceDefinition public void publishServiceDefinition(URL url) {try {String interfaceName url.getServiceInterface();if (StringUtils.isNotEmpty(interfaceName) !ProtocolUtils.isGeneric(url.getParameter(GENERIC_KEY))) {Class interfaceClass Class.forName(interfaceName);ServiceDefinition serviceDefinition ServiceDefinitionBuilder.build(interfaceClass);Gson gson new Gson();String data gson.toJson(serviceDefinition);// 存储服务接口相关数据// 数据格式// {// canonicalName: xxxService,// codeSource: file:/Users/xxxx,// methods: [{// name: hello,// parameterTypes: [java.lang.String],// returnType: java.lang.String,// annotations: []// }],// types: [{// type: java.lang.String// }],// annotations: []// } serviceDefinitions.put(url.getServiceKey(), data);return;} else if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {......}......} catch (Throwable e) {......} }4、RemoteMetadataServiceImpl#publishServiceDefinition public void publishServiceDefinition(URL url) {checkRemoteConfigured();String side url.getSide();if (PROVIDER_SIDE.equalsIgnoreCase(side)) {// 发布服务端Provider的服务接口信息到元数据中心publishProvider(url);} else {......} }RemoteMetadataServiceImpl#publishProviderprivate void publishProvider(URL providerUrl) throws RpcException {......try {String interfaceName providerUrl.getServiceInterface();if (StringUtils.isNotEmpty(interfaceName)) {......for (Map.EntryString, MetadataReport entry : getMetadataReports().entrySet()) {// 获取MetadataReport服务该服务用来访问元数据中心MetadataReport metadataReport entry.getValue();// 将服务接口信息存储到元数据中心metadataReport.storeProviderMetadata(new MetadataIdentifier(providerUrl.getServiceInterface(),providerUrl.getVersion(), providerUrl.getGroup(),PROVIDER_SIDE, providerUrl.getApplication()), fullServiceDefinition);}return;}......} catch (ClassNotFoundException e) {......} }5、AbstractMetadataReport#storeProviderMetadata public void storeProviderMetadata(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition){if (syncReport) {storeProviderMetadataTask(providerMetadataIdentifier, serviceDefinition);} else {// 异步存储到元数据中心reportCacheExecutor.execute(() - storeProviderMetadataTask(providerMetadataIdentifier, serviceDefinition));} }private void storeProviderMetadataTask(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) {try {......allMetadataReports.put(providerMetadataIdentifier, serviceDefinition);failedReports.remove(providerMetadataIdentifier);Gson gson new Gson();// data的数据格式// {// parameters: {// side: provider, // interface: xxxService,// metadata-type: remote,// service-name-mapping: true,// },// canonicalName: xxxService,// codeSource: file:/Users/xxxx,// methods: [{// name: hello,// parameterTypes: [java.lang.String],// returnType: java.lang.String,// annotations: []// }],// types: [{// type: java.lang.String// }],// annotations: []// } String data gson.toJson(serviceDefinition);// 存储到元数据中心实例中的元数据中心是ZookeeperMetadataReport// 目录元数据中心Metadata-report的/dubbo/metadata/xxxService/provider/${application-name}节点下doStoreProviderMetadata(providerMetadataIdentifier, data);// 存储到本地文件// 路径xxxService:::provider:${application-name} saveProperties(providerMetadataIdentifier, data, true, !syncReport);} catch (Exception e) {......} }建立 Triple 协议服务与 MetadataReport 服务之间的关系 核心代码在 ServiceConfig#exported、MetadataServiceNameMapping#map 和 ZookeeperMetadataReport#registerServiceAppMapping 中具体如下 1、ServiceConfig#exported protected void exported() {exported true;ListURL exportedURLs this.getExportedUrls();exportedURLs.forEach(url - {// 判断URL中是否标记有service-name-mapping的字段// 标记有该字段的服务是需要将暴露的服务与元数据中心关联起来// Consumer可以通过元数据中心的消息变更感知到Provider端元数据的变更if (url.getParameters().containsKey(SERVICE_NAME_MAPPING_KEY)) {ServiceNameMapping serviceNameMapping ServiceNameMapping.getDefaultExtension();// 建立关系serviceNameMapping.map(url);}});onExported(); }2、MetadataServiceNameMapping#map public void map(URL url) {execute(() - {String registryCluster getRegistryCluster(url);// 获取MetadataReport也就是元数据中心的访问路径MetadataReport metadataReport MetadataReportInstance.getMetadataReport(registryCluster);......int currentRetryTimes 1;boolean success;String newConfigContent getName();do {// 获取元数据中心中存储的应用的版本信息ConfigItem configItem metadataReport.getConfigItem(serviceInterface, DEFAULT_MAPPING_GROUP);String oldConfigContent configItem.getContent();if (StringUtils.isNotEmpty(oldConfigContent)) {boolean contains StringUtils.isContains(oldConfigContent, getName());if (contains) {break;}newConfigContent oldConfigContent COMMA_SEPARATOR getName();}// 在元数据中心创建mapping节点并将暴露的服务数据存到元数据中心这里的元数据中心用zookeeper实现的// 目录/dubbo/mapping/xxxService// 数据configItem.content为${application-name}configItem.ticket为版本好success metadataReport.registerServiceAppMapping(serviceInterface, DEFAULT_MAPPING_GROUP, newConfigContent, configItem.getTicket());} while (!success currentRetryTimes CAS_RETRY_TIMES);}); }3、ZookeeperMetadataReport#registerServiceAppMapping public boolean registerServiceAppMapping(String key, String group, String content, Object ticket) {try {if (ticket ! null !(ticket instanceof Stat)) {throw new IllegalArgumentException(zookeeper publishConfigCas requires stat type ticket);}String pathKey buildPathKey(group, key);// 1. 创建/dubbo/mapping/xxxService目录存储的数据为configItem// 2. 生成版本号zkClient.createOrUpdate(pathKey, content, false, ticket null ? 0 : ((Stat) ticket).getVersion());return true;} catch (Exception e) {logger.warn(zookeeper publishConfigCas failed., e);return false;} }到这里暴露Triple协议的服务并注册 registry 协议的流程就结束了。主要是将以前接口级服务发现机制中注册到注册中心中的数据应用实例数据服务接口数据拆分出来了。注册 registry 协议部分将应用实例数据注册到注册中心在 Exporter 暴露完以后通过调用 MetadataUtils#publishServiceDefinition 将服务接口数据注册到元数据中心。 4、暴露MetadataService服务 MetadataService 主要是对 Consumer 侧提供一个可以获取元数据的 API暴露流程是复用了 Triple 协议的服务暴露流程 整体时序图 暴露 MetadataService 的入口 核心代码在 DubboBootstrap#exportMetadataService 中具体如下 private void exportMetadataService() {// 暴露MetadataServermetadataServiceExporter.export(); }暴露 MetadataService 核心代码在 ConfigurableMetadataServiceExporter#export 中具体如下 public ConfigurableMetadataServiceExporter export() {if (!isExported()) {// 定义MetadataService的ServiceConfigServiceConfigMetadataService serviceConfig new ServiceConfig();serviceConfig.setApplication(getApplicationConfig());// 不会注册到注册中心serviceConfig.setRegistry(new RegistryConfig(N/A));serviceConfig.setProtocol(generateMetadataProtocol());serviceConfig.setInterface(MetadataService.class);serviceConfig.setDelay(0);serviceConfig.setRef(metadataService);serviceConfig.setGroup(getApplicationConfig().getName());serviceConfig.setVersion(metadataService.version());serviceConfig.setMethods(generateMethodConfig());// 用暴露Triple协议服务的流程来暴露MetadataService// 采用的是Dubbo协议serviceConfig.export();this.serviceConfig serviceConfig;}return this; }由于暴露 MetadataService 的流程是复用前面提到的暴露 Triple 协议服务的流程整个过程有少许地方会不同这些不同之处在上面的代码中都已经标明所以就不再赘述了。 注册 ServiceInstance 实例 注册 ServiceInstance 的目的是为了定时更新 Metadata当有更新的时候就会通过 MetadataReport 来更新版本号让 Consumer 端感知到。 核心代码在 DubboBootstrap#registerServiceInstance 和 DubboBootstrap#doRegisterServiceInstance 中具体如下 private void registerServiceInstance() {....// 创建ServiceInstance// ServiceInstance中包含以下字段// 1. serviceName${application-name}// 2. host: 192.168.31.167// 3. port: 2080// 4. metadata: 服务接口级相关的数据比如methods等数据// 同时还会对ServiceInstance数据中的字段进行补充分别调用下面4个ServiceInstanceCustomizer实例// 1ServiceInstanceMetadataCustomizer// 2MetadataServiceURLParamsMetadataCustomizer// 3ProtocolPortsMetadataCustomizer// 4ServiceInstanceHostPortCustomizerServiceInstance serviceInstance createServiceInstance(serviceName);boolean registered true;try {// 注册ServiceInstancedoRegisterServiceInstance(serviceInstance);} catch (Exception e) {registered false;logger.error(Register instance error, e);}// 如果注册成功定时更新Metadata没10s更新一次if(registered){executorRepository.nextScheduledExecutor().scheduleAtFixedRate(() - {......try {// 刷新Metadata和ServiceInstanceServiceInstanceMetadataUtils.refreshMetadataAndInstance(serviceInstance);} catch (Exception e) {......} finally {......}}, 0, ConfigurationUtils.get(METADATA_PUBLISH_DELAY_KEY, DEFAULT_METADATA_PUBLISH_DELAY), TimeUnit.MILLISECONDS);} }DubboBootstrap#doRegisterServiceInstance private void doRegisterServiceInstance(ServiceInstance serviceInstance) {if (serviceInstance.getPort() 0) {// 发布Metadata数据到远端存储元数据中心// 调用RemoteMetadataServiceImpl#publishMetadata// 内部会调用metadataReport#publishAppMetadatapublishMetadataToRemote(serviceInstance);logger.info(Start registering instance address to registry.);getServiceDiscoveries().forEach(serviceDiscovery -{ServiceInstance serviceInstanceForRegistry new DefaultServiceInstance((DefaultServiceInstance) serviceInstance);calInstanceRevision(serviceDiscovery, serviceInstanceForRegistry);......// 调用ZookeeperServiceDiscovery#doRegister注册serviceInstance实例// 将应用服务信息注册到注册中心中// 目录/services/${application-name}/192.168.31.167:20800// 数据serviceInstance序列化后的byte数组serviceDiscovery.register(serviceInstanceForRegistry);});} }通过上面的分析我们可以很容易知道 ServiceInstance 是中包含 MetadataMetadata 是存储在 InMemoryWritableMetadataService 中的元数据占用的是本地内存空间InMemoryWritableMetadataService 用来更新 MetadataServiceInstance 是存储在远端元数据注册中心中的数据结构RemoteMetadataServiceImpl 会调用 metadataReport 将 ServiceInstance 数据更新到远端元数据注册中心 总结 通过对 Dubbo 3.0 服务端暴露全流程的解析可以看出尽管应用级服务发现机制的实现要复杂很多但是 Dubbo 3.0 为了能够让使用者平滑迁移兼容了 2.7.x 的版本所以在设计的时候很多地方都尽可能复用之前的流程。 从最近 Dubbo 3.0 发布的 Benchmark 数据来看Dubbo 3.0 的性能和资源利用上确实提升了不少。Dubbo 3.0 在拥抱云原生的道路上还有很长的一段路要走社区正在对 Dubbo 3.0 中核心流程进行梳理和优化后续计划支持多实例应用部署希望有兴趣见证 Dubbo 云原生之路的同学可以积极参与社区贡献 原文链接 本文为阿里云原创内容未经允许不得转载。
http://www.pierceye.com/news/288648/

相关文章:

  • 做博客网站的空间容量需要多少北京简盟产品设计有限公司
  • 哪些网站怎么进定制开发平台
  • 【郑州网站建设】wordpress自定义后台单页模板
  • 铭誉摄影网站北京网站建设开发
  • 单位还能建设网站吗做网站的程序员留备份
  • 松江团购做网站产品开发的基本流程
  • 织梦后台网站栏目空白小广告制作
  • 钦州建设局网站云南网站建设招商
  • 韩国风格网站php源码网站怎么放到服务器上
  • 网站调优yandex搜索引擎入口
  • 医院网站建设具体内容商丘网站制作电话
  • 别人做的网站直播网站
  • 足球梦网站建设的基本思路沧州做企业网站
  • 招标建设网站什么是微信wordpress
  • 建设银行网站连不上成都网站快照优化公司
  • 网站 永久关停 请示广州网站建设骏域网站
  • 个人建站模板外国网站翻墙怎么做
  • 保定网站设计制作公司有经验的中山网站建设
  • 免费网站建设那个好wordpress本地怎么上传服务器
  • 自己做的网站加载慢WordPress模板首页文件是啥
  • 教学网站建设网站建设岗位有哪些
  • 网站建设合同的验收表网页网站的区别是什么
  • 开福区网站建设中wordpress调用所有栏目
  • 网站建设的流程是什么意思青岛做网站公司
  • 什么网站有项目做中铁建设企业门户网
  • 网站域名商代理商安卓商店
  • 深圳中英文网站建设广州知名设计公司排名
  • 一个公司设计网站怎么做的蜜桃传奇免费网页版
  • 网络推广网站培训班有人用wordpress默认主题
  • 网站建设 后台南宁做网站方案