Talking about the concurrency of the technical component client, talking about the concurrency

Source: Internet
Author: User

Talking about the concurrency of the technical component client, talking about the concurrency

Recently, a message Bus Based on RabbitMQ is implemented. Because it provides a Client, it involves the concurrency issues that clients of all technical components cannot avoid. This article uses the client that implements the message bus to talk about the ideas in the implementation process and the final processing method. Of course, these are not only applicable to the client of the message bus, but also to clients of other general components.

Classification of concurrency Problems

In fact, the concurrency problems mentioned above can be divided into two types in a large scale:

  • Inherent concurrency problems: the premise of this existence is that the client itself uses the multi-thread technology internally, and there is a thread security defect.
  • Concurrency of passive calls: it refers to the thread security issues generated by the client in a multi-threaded call environment.
If you want to simply look at the concurrency issue as an inherent concurrency issue, you can assume a premise: if your client is in a single-threaded called environment, in this case, your client uses multiple threads and has thread security issues. This can be seen as a purely inherent concurrency issue. To put it bluntly, if you do not adopt multithreading internally, you can think that this client does not have its own inherent concurrency problems. But sometimes the multi-threaded environment of external calls can also trigger the internal concurrency problem of your client. In this case, we classify the concurrency problem as the concurrency problem of passive calls. It may sound abstract. We can use an instance to make it more intuitive. Let's look at the redis client jedis. Jedis does not use multithreading technology to call redis Data Structure commands. Therefore, we can think that it does not have its own inherent concurrency problems, but once you share the Jedis object (main object) in a multi-threaded environment, all sorts of inexplicable errors will come out. We can consider this as a concurrency issue of passive calls. Therefore, it is not easy to implement an absolutely thread-safe class. It can be said that the cost is also very high-because you must consider these two different concurrency problems at the same time. In other words, when your client may have a multi-threaded environment, you must consider both the call and the thread security to be called.
In order not to let the questions discussed become too large and empty, we will focus on the concurrency issue of passive calls in this article.
A Brief Introduction to RabbitMQ communication: two key objects related to communication: Connection and Channel. To communicate, you must first establish a TCP Connection. This process is primarily the responsibility of the Connection. RabbitMQ allows you to create multiple channels from a Connection, define channels, and implement various APIs for communication. Therefore, Connection is mainly responsible for establishing links, while Channel is mainly responsible for communication logic. RabbitMQ is designed to avoid creating too many connections (each Connection is a TCP Connection with the RabbitMQ Server ). Channel Design is a commonly used "multiplexing" Technology in networks.
Shared instances are my first thought: to build a fully thread-safe class, no matter how the called environment is, only one single Messagebus object is used. This is the most user-friendly method for the called environment, but in this case, you must design the implementation model of the client based on the multi-threaded environment of the called environment.
Therefore, my previous idea was to create a Channel Object pool in the client. All ticket (one-way) communications directly obtain a Channel object from the object pool, and return the Channel to the object pool after the communication ends. Because the Pool here is built on the basis of Apache Common Pool, it is still thread-safe to obtain and return Channel objects, channel objects are explicitly marked as thread security in the official Java client of RabbitMQ, so there is no thread security problem in the entire communication logic. However, a fully shared instance means that key internal objects are shared. Two key objects inside the client are involved:
  • Pubsuber: used to obtain real-time configuration change data from a pubsuberCenter
  • ConfigManager: Used to parse the data pushed by pubsuberManager and adjust the control logic of the client in a timely manner.
In the implementation mode of shared instances, the APIS provided by these two objects must be thread-safe. At the same time, the APIs of all client master objects must be synchronized (the simplest and worst-performing API synchronization implementation method is to directly mark the entire method with synchronized, if the entire method is not synchronized, you must handle the synchronization problem carefully within the method ).
The main cause of the transition from a shared instance to a thread exclusive is data sharing. Therefore, the implementation of shared instances is very promising, and this is a test of the real-world concurrency, as a newbie to concurrency, it would be nice if I had a way to stay away from it. Therefore, my thinking gradually transits from shared variables to exclusive ones.
We mentioned that a Connection can create multiple channels. The official RabbitMQ client has directly stated in its doc that the Channel is thread-safe and supports communication in a multi-threaded environment.
Therefore, my idea quickly becomes like the following:

In this mode, the Connection is implemented as a singleton mode, and only one Connection object exists in a JVM process (regardless of whether the called environment is in the multi-thread state. A Client primary object (the Messagebus object in it) is associated with only one independent Channel and agrees that a Client primary object can only be applied to one independent thread and cannot be used across threads. In this way, the entire client's communication logic does not need to pay attention to concurrency issues. In this mode, Pubsuber and ConfigManager are still single instances (that is, shared instances). Therefore, their APIs must be thread-safe.
This seems to be a good method, but when I started to implement it, I found a problem: If the Messagebus object is exclusive in each thread, who will close the Connection? If it is disabled by the Messagebus object on a thread, Messagebus working on other threads will be a disaster-they will throw an exception in an extremely inelegant way. In shared instance mode, the master object of the client does not exist because the control of the master object of the client is completely owned by the master thread.
The client master object and all associated objects are exclusively occupied by threads (Connection objects are different instances in different threads ). This is also the implementation method of jedis. Before thinking about the above two methods, I learned about this implementation method. However, I have been trying to see if there are other methods, because it is a waste of resources after all-how many communication threads are created on the client, there are at least many sets of object clusters (including so many Connection objects ). But this is also the simplest way to achieve the best communication performance-because it does not need to deal with the security of the called thread, in addition, it is not like the above ideas that need to be entangled in who is in charge of the control of the Connection. The memory model of a single thread is as follows:

That is to say, when you create a Messagebus client object, the associated object clusters in the dotted box above will be created (they have the same lifecycle as the main client object ).
How does this implementation solve the problem of concurrent calls by multiple threads? Two steps:
  • Based on Conventions: it is not allowed to share the main client object among multiple threads. Otherwise, the consequences will be borne by you.
  • The Client master object and dependent object are completely exclusive, and the object pool of the Client master object is created.
Now, no objects are shared in a multi-threaded environment:

You can take a look at it. Example.
In this mode, all the implementation code of the client does not need to lock any performance damage for thread security issues, and the object ownership is also very clear. But there is no doubt that it also has some disadvantages:
In fact, in the final analysis, everything is a balance-depending on what you care about and what you are willing to give up.
To sum up, many APIs cannot be completely perfect. The concurrency problem in this article is only a common phenomenon, and other problems include misuse and misuse. For example, in the second model mentioned above, if we don't talk about the message bus and only use the java client native of RabbitMQ, you can create a Connection object on the main thread during multi-thread communication, assign independent Channel objects to each thread, and close the Connection object on the main thread. However, the Channel object opens the API for obtaining the Connection object, so it gives each thread control over the Connection. You can only say that the technical component can only take care of itself, and it does not speculate on any use cases and intentions.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.