Talking about the concurrency problem of the technical component client

Source: Internet
Author: User
Tags rabbitmq

A RABBITMQ-based message bus was recently implemented. Because it provides the client, it is involved in concurrency problems that are unavoidable by the client of any technical component. In this paper, the realization of the message bus client to talk about the implementation process of the idea and the final processing, of course, these are not only applicable to the message bus client, the other common components of the client also applies.

Classification of concurrency problems

In fact, the above mentioned concurrency problem, from a large level can be divided into two types of problems:

    • Inherent concurrency problems: The premise of this existence is that the client itself uses multithreading technology, and itself has a thread-safe flaw.
    • Concurrency problem with passive invocation: This is a thread-safety issue that occurs when the client is in a multithreaded call environment.
If you want to simply look at what concurrency problems are inherently concurrency problems, then you can assume that if your client is in a single threaded environment, then your client is using multiple threads internally, and there is a thread-safety problem. Can be seen as a purely intrinsic concurrency problem. To be more straightforward, if you are not using multi-threading internally, you can assume that the client has no inherent concurrency problems. But sometimes a multithreaded environment called externally can trigger concurrency problems in your client, which we classify as a concurrency problem for passive calls. It may sound a bit abstract, let's make it more intuitive with an example. We look at Redis's client Jedis. Jedis internal calls to the REDIS data Structure command are not multithreaded, so we can assume that it has no inherent concurrency problems, but once you share its Jedis object (the main object) in a multithreaded environment, all sorts of inexplicable errors come out. We can think of this as a concurrency problem with passive invocation. So it is not easy to implement an absolutely thread-safe class, and it can be said that the cost is very large-because you have to consider both of these different concurrency problems at the same time. In other words, when you have a multithreaded environment inside and outside your client, you must consider both the invocation and the thread security being invoked.
To keep the discussion from getting big and empty, this article will focus on the concurrency of the passive calls.
RabbitMQ Brief Introduction to the communication of RabbitMQ two key objects related to communication: Connection, Channel. To communicate, you must first establish a TCP connection, the process is mainly responsible for connection. RABBITMQ supports a variety of APIs that create multiple Channel,channel definitions and implement communication from a single connection. Thus connection is primarily responsible for the establishment of links, while the channel is primarily responsible for communication logic. RABBITMQ is designed to avoid creating too many connection (each connection is a TCP connection to RABBITMQ server). The channel design is commonly used in the network "multiplexing" technology.
Shared instances This is my initial idea: to build a fully thread-safe class that uses only a single Messagebus object, regardless of the calling environment. This is the most friendly way to tune the environment, but in this case you have to design the client implementation model based on the environment being tuned as a multi-threaded environment.
So my previous idea was to create a pool of channel objects within the client. All simplex (unidirectional) communication takes a channel object directly from the object pool and returns the channel to the object pool after the communication is over. Because the pool here is built on Apache Common Pool, getting and returning the channel object is thread-safe, and the channel object is explicitly labeled thread-safe in the RABBITMQ official Java client. Therefore, there is no thread safety problem throughout the communication logic. But a fully shared instance means that the internal key objects are also shared, which involves two more critical objects inside the client:
    • Pubsuber: Used to get real-time configuration change data from a Pubsubercenter
    • ConfigManager: Used to parse Pubsubermanager push data and adjust client control logic in a timely manner.
In the implementation of shared instances, the APIs provided by these two objects must be thread-safe. At the same time, the APIs for all client Master objects must be synchronous (the simplest and worst-performing API synchronous implementation is to tag the entire method directly with the synchronized, and if the entire method is not implemented as synchronous, the synchronization problem must be handled carefully inside the method).
Exclusive transition from shared instance to thread because the main source of multithreading problems is the problem of data sharing, so the implementation of shared instances is just kind, and this is a very test of the implementation of concurrency, I as a novice, if there is a way to distance, then it is better. So my train of thought gradually transitions from shared variables to exclusivity.
Before talking about a connection can create multiple channel. The official client of RabbitMQ has directly stated on its doc that the channel is thread-safe and that it directly supports communication in a multithreaded environment.
So my train of thought soon became like this:

In this mode, connection is implemented as a singleton pattern, where only one connection object exists in a JVM process (regardless of whether the environment is in a multithreaded state). A client main object (that is, the Messagebus object in) only associates a separate channel and contracts that a client Master object can only be applied to a separate thread, not across threads. In this way, the entire client communication logic does not have to focus on concurrency issues. But in this mode, Pubsuber and ConfigManager are still singleton (that is, the pattern of shared instances), so their APIs must also be implemented as thread-safe.
This may seem like a good way to do this, but when I've started to implement it, I find a problem: If the Messagebus object is exclusive in each thread, who is driving the connection off action? If it is shut down by a Messagebus object on a thread, the messagebus that are working on other threads will be a disaster-they will throw an exception in an extremely elegant way. In shared instance mode, the client Master object does not have this problem, because its client Master object control is completely owned by the main thread.
The implementation of the full-thread exclusive client Master object and all associated objects are exclusive by the thread (the connection object is also a different instance in different threads). This is also the way of Jedis implementation, in fact, before thinking about the above two ways, I understand this way of implementation. But I've been trying to see if there are other ways, because it's a waste of resources--how many communication threads a client creates, and at least how many sets of object clusters (including so many connection objects). But this is also the simplest and best way to communicate-because it doesn't have to deal with thread-safety issues at all, and it's not as if one of the above ideas needs to be in charge of the control over connection. The memory model for a single thread is as follows:

That is, when you create a Messagebus client object, the associated object clusters within the dashed box above are created (they have the same life cycle as the client Master object).
This implementation is how to solve the problem of multi-threaded multithreading concurrency? Two steps:
    • Based on conventions: The client Master object must not be shared between multiple threads, otherwise the consequences are self-imposed
    • The client Master object and the dependent object are fully exclusive and the object pool of the client Master object is created
Now, there is no object sharing in a multithreaded environment:

You can check it out. using the example
In this mode, all the implementation code of the client no longer has to do any damage performance lock operation for the thread security problem and the object's attribution is also very clear. But there is no doubt that it has some drawbacks:
    1. It wastes a lot of resources: not just the memory space of the client's JVM, but also the connection resources of the RABBITMQ server
    2. Security risk: This mode, if the server does not do any processing, the client can even create a DDoS attack by constantly creating Messagebus objects
In fact, everything is a trade-off-see what you care about and what you are willing to abandon.
In fact, a lot of API can not be completely perfect, the concurrency of this article is only a common phenomenon, the other problems are disorderly use, the wrong use of the problem. For example, the second model mentioned above, if we do not talk about the message bus, only using the RABBITMQ native Java client, you can do multithreading communication: Create connection objects on the main thread, and then assign separate channel objects for each thread, Finally, the connection object is closed on the main thread. But the channel object opens the API to get the connection object, so it gives each thread control over the connection. You can only say that technical components only care about themselves, it does not speculate on any use of the scene and the use of intent.

Talking about the concurrency problem of the technical component client

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.