This is the 28th original article by Why Technologies

Dubbo consistent hash load balancing (Dubbo consistent hash load balancing) [1] wrote that I found a Bug in the Dubbo consistent hash load balancing algorithm.

Here’s what I wrote for the solution:

Get identityHashCode from system.identityHashCode (invokers) to invokers.hashCode(). This scheme is the comment in the issue I mentioned. The connection and difference between System. IdentityHashCode and hashCode will not be elaborated here.

System. IdentityHashCode and hashCode.

But I’ve already spoken to a reader backstage who asked me for details.

Plus thisThe BUG was recently fixed and it took only one line of code“Let me write down the solution and the rationale behind it.

It is a supplement to the previous article, but also an independent knowledge point.

Therefore, this paper mainly answers the following three questions:

1. What is System. IdentityHashCode?

2. What is hashCode?

3. Why did this BUG get fixed in one line of code?

Note: this article Dubbo source code version 2.7.4.1. If you have read Dubbo consistent hash load balancing source code and bugs, see? [2] Can better understand this article. But not having read it doesn’t affect reading.

Antecedents to review

This article is about to be shared through an earlier review.

The Dubbo consistent hash load balancing algorithm should be designed so that if there is no service up and down, subsequent requests will be processed based on the hash ring that has been mapped without remapping.

However, when I looked into the source code, I realized that the consistent hash load balancing algorithm needs to remap the hash ring every time, even when there is no up-down operation on the server.

The actual situation is not consistent with the original design.

So I sent Dubbo an issue with the following address:

https://github.com/apache/dubbo/issues/5429


The following is a detailed description of the issue:

In Dubbo’s source code, only one line of code is required. Then you can determine whether there is a service offline operation:


Here’s the line below:

int identityHashCode = System.identityHashCode(invokers);

Determine whether a service has been brought online or offline by determining whether the invokers(service provider List collection) identityHashCode has changed.

This line of code, however, is invalid after Dubo2.7.0.

The problem is one of the new features introduced in dubo2.7.0: tag routing.

The corresponding source code is as follows:

org.apache.dubbo.rpc.cluster.router.tag.TagRouter#filterInvoker


The stream operation on the TagRouter changes the invokers so that system. identityHashCode(Invokers) returns a different value each time it is called.

Therefore, each call will carry out hash ring mapping operation, and there will be performance problems in the case of many service nodes and virtual nodes.

The corresponding PR link of this problem is as follows:

https://github.com/apache/dubbo/pull/5440

The fix is also fairly simple: change the method for obtaining identityHashCode from System.identityHashCode(invokers) to invokers.hashCode(). As shown below:


Why can one line of code fix it?

Why change the method for obtaining identityHashCode from system.identityHashCode (invokers) to invokers.hashCode()?

To answer this question, we first have to understand what is identityHashCode? What is hashCode?

** What is identityHashCode? ** Let’s look at the comments in the API:


Returns the same hashCode as the given object returned by the default method hashCode(), whether or not the given object’s class overrides hashCode(). The hash code for an empty reference is zero.

There are three more rules for identityHashCode:

1. So if two objects A == B, then A and B’s system.identityHashCode () must be equal;

2. Two objects must not be the same object if their system.identityHashCode () values are not equal;

3. However, if two objects’ system.identityHashcode () are equal, there is no guarantee that A==B, because the underlying implementation of identityHashCode is based on A pseudo-random number.

What is hashCode? You should be familiar with it, but look at the comments on the API:


Combine the following two examples of code to further understand.

Example 1: WhyHashCodeDto does not override the hashCode() method, so identityHashCode and hashCode have the same value:


Example 2: As shown below, String overrides the hashCode() method, so identityHashCode does not equal hashCode in the following example:



Into the scene

With this knowledge in mind, we can return to the scenario of Dubbo’s consistent hash algorithm.

One line of comment in PR reads:

using the hashcode of list to compute the hash only pay attention to the elements in the list

We should just focus on the elements in the list. The elements in this list are service providers.

So, in the case of Dubbo’s consistent hash algorithm, we only care about whether the service provider in the List has operations up and down, not whether the List is new every time.

Let’s go back to the source code, combine the source code, and then simplify it:


Extract the above source code and simplify it as follows:


The filterInvoker method filters invokers based on criteria and returns a List. Filter out invokers where invoker is greater than 0:

filterInvoker(invokers, invoker -> invoker > 0);

The result is as follows:


As you can see, after the filterInvoker method, since all elements in the collection meet the criteria, the elements in the collection do not change before and after filtering, resulting in no change in hashCode. But since the container (collection) that holds the elements is no longer the original container, the identityHashCode has changed.

“Because the elements in the collection have not changed, hashCode has not changed.” What is the reason for this statement?

Because List overrides the hashCode() method, it evaluates hashCode only with the elements in the List:


After the filterInvoker method, the elements are the same [1,2,3] as before filtering, so the hashCode has not changed.

“Since the container (collection) that holds the elements is no longer the original container, the identityHashCode has changed.” What is the reason for this statement?

You can see in the source code that the Collectors. ToList () method will be new List. So it’s all new, so it’s going to be different identityHashCode every time.


The example code above simulates going online without a service.

Next, let’s simulate a service offline scenario:

The filter condition passed in this time is to filter out the data in invokers whose invoker is greater than 1:

filterInvoker(invokers, invoker -> invoker > 1);

The following output is displayed:


As you can see, there is only [2,3] left in the filtered collection, so the hashCode has changed.

The example above is equivalent to server 1 going offline in the Dubbo consistent hash algorithm scenario, the list of services has changed, and the hash ring mapping needs to be redone.


The corresponding source code is as follows (source code submitted by PR) :


Because the invokersHashCode obtained at the mark ① is different from the previous one, the condition is judged to be true at the mark ②, the code at the mark ③ is entered, the Hash ring is mapped again, and a virtual node is selected to execute the request.

Using the two examples simulated above, combine the following source code:


This is why we can fix this Bug by replacing the code labeled ① with the code labeled ②. The core idea is that only the elements in the List change, not whether the List container changes.

One last word

When I first found this BUG, I had a solution of my own. The idea is also to only care about the elements in the List, not the List container, but the implementation is complicated, many changes, also need to write a tool class.

But seeing this comment under the issue,


Then I realized that one line of code could replace the utility class I wrote. This is something I already knew.

I reflected on why I hadn’t thought of this plan.

In fact, it is for the already known knowledge points, not deep enough to master, did not reach the point of mastery. Know why, also know why, but in the case of a slight change in the need to use the scene, can not remember.

It’s quite common to know the knowledge but not remember it when you need to use it.

This article is my solution. Write it down. Just like when I was in high school, I had a copy of the wrong questions. If I did the wrong questions, I would not copy them down. Nothing when the time to turn over, there is always the next time to meet. The next time you do, it’s your chance to make amends.


All right.

If you find something wrong, please leave a message and point it out to me so that I can modify it.

Thank you for reading and for your attention.

The above.

Welcome to pay attention to the public account [WHY Technology], adhere to the output of original. May you and I make progress together.


The resources

[1]

Dubbo consistent hash load balancing source code and bugs, understand? : https://juejin.cn/post/6844904016577560583