In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
How to set @ DubboReference.version to * in Dubbo, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible way.
Dubbo provides a feature on the consumer side, that is, the consumer's version number is specified as *, so that no matter what the version of the server's interface is, it can be called successfully.
1 preliminary guess
Dubbo interface location logic: interface (full path) + service packet (group field) + version number (version field).
Zookeeper stores data in a tree. In Zookeeper, the Dubbo interface (full path) can be used as the parent node, and then the child nodes can be written according to group and version information.
And Nacos, in the console of Nacos, we see that the service list can be vaguely queried by service name or service grouping, so when consumers subscribe, they can be queried according to these two fuzzy queries, and all the health providers found are consistent.
Let's dig into the source code to see if the actual logic is similar to our guess.
2 Source Code Analysis 2.1 Zookeeper as a registry
2.1.1 preparation
Get a service provider and a service consumer. The service provider provides an external dubbo interface with versions 1.0.0 and 2.0.0; the service consumer introduces the dubbo interface provided by the service provider, and the version is set to *.
Start the service provider, then start the consumer, and watch the background log print:
We can see that when we set the version of @ DubboReference to *, he will find out which service providers are available according to the registered url (with *), and then return multiple urls, including url with version numbers 1.0.0 and 2.0.0.
2021-05-01 10 o.a.d.r.z.ZookeeperRegistry 24V 08.561 [main] [INFO] [o.a.d.r.z.ZookeeperRegistry] []-[DUBBO] Subscribe: consumer://127.0.0.1/com.winfun.service.DubboServiceOne?application=dubbo-service&category=providers,configurators,routers&dubbo=2.0.2&init=false&interface=com.winfun.service.DubboServiceOne&methods=sayHello&pid=14021&qos.enable=false&reference.filter=default,dubboLogFilter Sentinel.dubbo.consumer.filter&release=2.7.7&revision=*&side=consumer&sticky=false×tamp=1619835848549&version=*, dubbo version: 2.7.7, current host: 127.0.0.1 2021-05-01 10 main 24 main [INFO] [o.a.d.r.z.ZookeeperRegistry] []-[DUBBO] Notify urls for subscribe url consumer://127.0.0.1/com.winfun.service.DubboServiceOne?application=dubbo-service&category=providers,configurators Routers&dubbo=2.0.2&init=false&interface=com.winfun.service.DubboServiceOne&methods=sayHello&pid=14021&qos.enable=false&reference.filter=default,dubboLogFilter,sentinel.dubbo.consumer.filter&release=2.7.7&revision=*&side=consumer&sticky=false×tamp=1619835848549&version=* Urls: [dubbo://192.168.2.10:20880/com.winfun.service.DubboServiceOne?anyhost=true&application=dubbo-provider-one&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.winfun.service.DubboServiceOne&metadata-type=remote&methods=sayHello&pid=13996&release=2.7.8&revision=1.0.0&service.filter=default,dubboLogFilter&side=provider×tamp=1619835820516&version=1.0.0 Dubbo://192.168.2.10:20880/com.winfun.service.DubboServiceOne?anyhost=true&application=dubbo-provider-one&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.winfun.service.DubboServiceOne&metadata-type=remote&methods=sayHello&pid=13996&release=2.7.8&revision=2.0.0&service.filter=default,dubboLogFilter&side=provider×tamp=1619835820187&version=2.0.0 Empty://127.0.0.1/com.winfun.service.DubboServiceOne?application=dubbo-service&category=configurators&dubbo=2.0.2&init=false&interface=com.winfun.service.DubboServiceOne&methods=sayHello&pid=14021&qos.enable=false&reference.filter=default,dubboLogFilter,sentinel.dubbo.consumer.filter&release=2.7.7&revision=*&side=consumer&sticky=false×tamp=1619835848549&version=* Empty://127.0.0.1/com.winfun.service.DubboServiceOne?application=dubbo-service&category=routers&dubbo=2.0.2&init=false&interface=com.winfun.service.DubboServiceOne&methods=sayHello&pid=14021&qos.enable=false&reference.filter=default,dubboLogFilter,sentinel.dubbo.consumer.filter&release=2.7.7&revision=*&side=consumer&sticky=false×tamp=1619835848549&version=*], dubbo version: 2.7.7, current host: 127.0.0.1
2.1.2 Source Code Analysis
As we can see above, version=* can subscribe successfully, and there are two service providers, version=1.0.0 and version=2.0.0.
The result is obvious, but we still need to see how Zookeeper makes the judgment logic.
2.1.2.1 Service Consumer subscription process
As we all know, consumers who normally publish Dubbo need to configure ReferenceConfig and then call the export method; of course, we won't go too deep here, starting directly with the entry to the log: org.apache.dubbo.registry.zookeeper.ZookeeperRegistry#doSubscribe
Our service consumer subscription url:
Consumer://127.0.0.1/com.winfun.service.DubboServiceOne?application=dubbo-service&category=providers,configurators,routers&dubbo=2.0.2&init=false&interface=com.winfun.service.DubboServiceOne&methods=sayHello&pid=16215&qos.enable=false&reference.filter=default,dubboLogFilter,sentinel.dubbo.consumer.filter&release=2.7.7&revision=*&side=consumer&sticky=false×tamp=1619842106726&version=*
Step 1: get the full path of dubbo interface
Url.getServiceInterface ()-> com.winfun.service.DubboServiceOne
And then determine if it's equal to "*", obviously not, jump to the else branch.
Step 2: obtain path according to url
Get the root node:
ToCategoriesPath (url)-> / dubbo/com.winfun.service.DubboServiceOne/providers, / dubbo/com.winfun.service.DubboServiceOne/configurators, / dubbo/com.winfun.service.DubboServiceOne/consumers
Step 3: traverse the path of step 2 and create the parent node
Focus on path=/dubbo/com.winfun.service.DubboServiceOne/providers, and ignore others.
Create nodes based on path (non-persistent): zkClient.create (root, false)
Add a child node listener to path: zkClient.addChildListener (path, zkListener) and return a list of child nodes
Dubbo://192.168.2.10:20880/com.winfun.service.DubboServiceOne?anyhost=true&application=dubbo-provider-one&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.winfun.service.DubboServiceOne&metadata-type=remote&methods=sayHello&pid=13996&release=2.7.8&revision=1.0.0&service.filter=default,dubboLogFilter&side=provider × tamp=1619835820516&version=1.0.0
Dubbo://192.168.2.10:20880/com.winfun.service.DubboServiceOne?anyhost=true&application=dubbo-provider-one&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.winfun.service.DubboServiceOne&metadata-type=remote&methods=sayHello&pid=13996&release=2.7.8&revision=2.0.0&service.filter=default,dubboLogFilter&side=provider × tamp=1619835820187&version=2.0.0
There are no child nodes in configurators and consumers, so the child nodes are url generated according to the rules, prefixed with empty
Step 4: monitor the urls obtained above
Call the org.apache.dubbo.registry.support.FailbackRegistry#notify method.
Finally I will go to org.apache.dubbo.registry.support.AbstractRegistry#notify (org.apache.dubbo.common.URL, org.apache.dubbo.registry.NotifyListener, java.util.List)
Important: before listening, it will match all the child nodes queried by path and match the child nodes that match the current consumer (judged by group and version), and use org.apache.dubbo.common.utils.UrlUtils#isMatch to judge.
The most important logic in judgment:
String ANY_VALUE = "*"; String consumerGroup = consumerUrl.getParameter (GROUP_KEY); String consumerVersion = consumerUrl.getParameter (VERSION_KEY); String consumerClassifier = consumerUrl.getParameter (CLASSIFIER_KEY, ANY_VALUE); String providerGroup = providerUrl.getParameter (GROUP_KEY); String providerVersion = providerUrl.getParameter (VERSION_KEY); String providerClassifier = providerUrl.getParameter (CLASSIFIER_KEY, ANY_VALUE) Return (ANY_VALUE.equals (consumerGroup) | | StringUtils.isEquals (consumerGroup, providerGroup) | | StringUtils.isContains (consumerGroup, providerGroup) & & (ANY_VALUE.equals (consumerVersion) | | StringUtils.isEquals (consumerVersion, providerVersion)) & & (consumerClassifier = = null | | ANY_VALUE.equals (consumerClassifier) | | StringUtils.isEquals (consumerClassifier, providerClassifier)
The above fully shows that when the version number is equal to the * sign, the service under the root node of the dubbo interface will serve as the service provider for the current consumer.
OK, at this point, we can know how Zookeeper subscribes to the service for version=* consumers, directly gets all the child nodes in the Zookeeper according to the full path name of the interface, and can act as a service provider.
In fact, there will be an extension point: how multiple service providers are loaded when calling. In fact, as you can see in the loadbance attribute in @ DubboReference, the default load policy is random.
/ * * Load balance strategy, legal values include: random, roundrobin, leastactive *
* see Constants#DEFAULT_LOADBALANCE * / String loadbalance () default ""; org.apache.dubbo.common.constants.CommonConstants#DEFAULT_LOADBALANCE= "random"
2.1.2.2 Service Consumer execution process
Proxy execution Portal:
Through debug mode, we can enter the entrance to the execution of the Dubbo method: org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke
Step 1: preliminary judgment
If it is an Object class or methods such as toString, destory, hashCode, etc., execute
Step 2: create a RpcInvocation
Create RpcInvocation based on execution method, parameters and other information
Get serviceKey:- > serviceKey = dubbo-api-path/group:version
RpcInvocation sets TargetServiceUniqueName
Step 3: call the invoke method of invoker
Come to org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke
Determine if mock or force is set
If you are calling the org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#doMockInvoke method
Otherwise, come to org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster.InterceptorInvokerNode#invoke.
Step 4: AbstractClusterInvoker#invoke
Call AbstractClusterInvoker#list to get the invoker list, and you can see that what you get is the 1.0.0 and 2.0.0 service providers.
Then call the initLoadBalance method to initialize the load balancing policy, get the value of loadbalance from the subscription url, and return the default value "random" if it is not set.
/ * Init LoadBalance. *
* if invokers is not empty, init from the first invoke's url and invocation * if invokes is empty, init a default LoadBalance (RandomLoadBalance) *
* * @ param invokers invokers * @ param invocation invocation * @ return LoadBalance instance. If not need init, return null. * / protected LoadBalance initLoadBalance (List invokers, Invocation invocation) {if (CollectionUtils.isNotEmpty (invokers)) {return ExtensionLoader.getExtensionLoader (LoadBalance.class) .getExtension (invokers.get (0). GetUrl () .getMethodParameter (RpcUtils.getMethodName (invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE);} else {return ExtensionLoader.getExtensionLoader (LoadBalance.class) .getExtension (DEFAULT_LOADBALANCE);}}
Step 5: execute the method according to the cluster policy
Since the default cluster policy of Dubbo is failover, it will come to: org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoker
First of all, the number of retries is obtained from the retries field in the registration url (if it is empty, the default number of retries is 2). This time, the default value is taken, so the final maximum number of calls is 3.
Cycle retries+1 times
Come to: org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#select choose Invoker
In RandomLoadBalance#doSelect, the first decision is based on the weight of the service provider, and if the weight is not assigned, an invoker is randomly selected using ThreadLocalRandom.current (). NextInt (invokers.size ()).
Next step: org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#doSelect
Next step: since org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance#select defaults to random's load balancing strategy, it finally comes to: org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance#doSelect
Execute the invoke method and return the result
If there is an error, record it and print the warn log in a loop next time
If more than retries+1 calls fail, throw a RpcException exception
At this point, we know very well how Zookeeper enables consumers to set version to * and how to select a service provider when the method is called.
2.2 Nacos as a registry
2.2.1 preparation
Get a service provider, a service consumer, this time not Zookeeper as the registry, but Nacos as the registry. The service provider provides an external dubbo interface with versions 1.0.0 and 2.0.0; the service consumer introduces the dubbo interface provided by the service provider, and the version is set to *.
Start the service provider, then start the consumer, and watch the background log print:
2.2.2 Source code analysis
2.2.2.1 Service Consumer subscription process
Nacos source code analysis also starts directly from the NacosRegistry#doSubscribe entry:
Org.apache.dubbo.registry.nacos.NacosRegistry#doSubscribe (org.apache.dubbo.common.URL, org.apache.dubbo.registry.NotifyListener)
Consumer's registered url:
Consumer://192.168.3.3/com.winfun.service.DubboServiceOne?application=dubbo-consumer-nacos&category=providers,configurators,routers&dubbo=2.0.2&init=false&interface=com.winfun.service.DubboServiceOne&metadata-type=remote&methods=sayHello&pid=39203&qos.enable=false&reference.filter=default,dubboLogFilter&release=2.7.8&revision=*&side=consumer&sticky=false×tamp=1620177626113&version=*
The first step is to obtain the serviceName collection according to url:
Org.apache.dubbo.registry.nacos.NacosRegistry#getServiceNames0
1. Create a NacosServiceName:
Providers:com.winfun.service.DubboServiceOne:*:
2. Then go to: org.apache.dubbo.registry.nacos.NacosRegistry#filterServiceNames (org.apache.dubbo.registry.nacos.NacosServiceName)
Filter out all serviceName based on the servicename above
2.1. first use NamingProxy to query:
Com.alibaba.nacos.client.naming.net.NamingProxy#getServiceList (int, int, java.lang.String, com.alibaba.nacos.api.selector.AbstractSelector)
Use API full path name + group query without version number
2.2. Finally:
Com.alibaba.nacos.common.http.client.NacosRestTemplate#exchangeForm
Http request:
Url:
Http://127.0.0.1:8848/nacos/v1/ns/service/list params: {app=unknown, pageSize=2147483647, groupName=DEFAULT_GROUP, namespaceId=public, pageNo=1}
Return the result:
RestResult {code=200, message='null', data= {"doms": ["providers:com.winfun.service.DubboServiceOne:1.0.0:", "providers:com.winfun.service.DubboServiceOne:2.0.0:"], "count": 2}}
Obviously contains two versions of service
Second, filter the appropriate service according to the conditions.
Public boolean isCompatible (NacosServiceName concreteServiceName) {if (! concreteServiceName.isConcrete ()) {/ / The argument must be the concrete NacosServiceName return false;} / / Not match comparison if (! StringUtils.isEquals (this.category, concreteServiceName.category) & &! matchRange (this.category, concreteServiceName.category)) {return false;} if (! StringUtils.isEquals (this.serviceInterface, concreteServiceName.serviceInterface)) {return false } / / wildcard condition / / focus on if (isWildcard (this.version)) {return true;} if (isWildcard (this.group)) {return true;} / / range condition if (! StringUtils.isEquals (this.version, concreteServiceName.version) & &! matchRange (this.version, concreteServiceName.version)) {return false } if (! StringUtils.isEquals (this.group, concreteServiceName.group) & &! matchRange (this.group, concreteServiceName.group)) {return false;} return true;} private boolean isWildcard (String value) {return WILDCARD.equals (value);} public static final String WILDCARD = "*"
There are two filtered service, which are 1.0.0 and 2.0.0 respectively
So go ahead with the subscription process: org.apache.dubbo.registry.nacos.NacosRegistry#doSubscribe (org.apache.dubbo.common.URL, org.apache.dubbo.registry.NotifyListener, java.util.Set)
The third step is to traverse serviceNames, query all instance lists according to serviceName+group and listen for instances.
List instances = new LinkedList (); for (String serviceName: serviceNames) {instances.addAll (namingService.getAllInstances (serviceName, getUrl (). GetParameter (GROUP_KEY, Constants.DEFAULT_GROUP)); notifySubscriber (url, listener, instances); subscribeEventListener (serviceName, url, listener);}
At this point, the whole subscription process is over, mainly to see how version=* determines which service instances can provide services, and no more in-depth.
Nacos as a registry, query service instances mainly according to serviceName (interface full path name) and group (grouping), this is because the data structure of Nacos itself is mainly service name + grouping name.
2.2.2.2 Service consumer invocation process
This will not be explained in depth, and the calling process is basically the same as on Zookeeper.
This is the answer to the question about how to set @ DubboReference.version to * in Dubbo. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.