At present, the official RABBITMQ to send the message to the client demo is based on a short connection to do, for example:
ConnectionFactory CF = new ConnectionFactory ();
Cf. Uri = serveraddress;
using (iconnection conn = cf. CreateConnection ()) {
using (imodel CH = conn.) Createmodel ()) {
if (Exchange!= "") {
ch. Exchangedeclare (Exchange, ExchangeType);
Ch. Basicpublish (exchange,routingkey,null,encoding.utf8.getbytes (message));
}
We started it in this way, too. But when you do stress testing, found that each new connection and new channel is very time-consuming, in the large concurrency, the general must be about 8 milliseconds, slow, a lot of it is dozens of milliseconds, for this reason, I specialize in the data, come to the following conclusions: 1, Rabbit client provides the connection way introduction:
The RABBITMQ official provided:
Connection object, which is a TCP connection object.
Channels object, virtual connection. The virtual connection is built into the TCP connection of the connection object above. Data flow is carried out in the channel. The virtual connection of each connection object is also limited, and if a single Connnection channel object exceeds the specified range, there is a performance problem, and multiple virtual connections on the other TCP connection are actually transmitted The virtual connection that transmits the data is still exclusive of the TCP connection, and the other virtual connections are waiting in line. 2, the RABBITMQ official recommendation Client connection use way:
Create multiple channel on a Connection object, and then when the program sends the data, share the use of the created channel separately, but with a specific single channel, you need to protect the thread-exclusive use of a single Chanel. Do not allow multiple threads to use a single channel at the same time, which can result in concurrent errors. When using a single channel, add a lock to resolve it, the official documentation and code examples are as follows:
Sharing channels Between Threads
As a rule of the thumb, imodel instances should not to used by more than one thread simultaneously:application code should MA Intain a clear notion of thread ownership for Imodel instances. If more than one thread needs to access a particular Imodel instances, the application should enforce the mutual of its Elf. One way of achieving this are for all users of a imodel to lock the instance itself:
Imodel ch = retrievesomesharedimodelinstance ();
Lock (CH) {
Ch. Basicpublish (...);
}
3, RABBITMQ client clients existing problems. 3.1, Connection object creation, destruction of time-consuming issues, management issues:
The
Connection object creates a TCP connection, and the creation and destruction of TCP connections is inherently time-consuming, and the solution is to create a connection object that is not closed until the data is transferred, and the connection object is shared. MQ officials are also recommending a connection object to create multiple Chnanel to achieve fast data transmission, the implementation of the way to create a static connection object is not done, but the problem is, if I need to connect multiple MQ servers, If my side is divided according to the business, different business data, need to be transferred to different MQ servers, such as order data and chat data, are sent to different MQ servers, if only a static connection object, how can connect 2 servers at the same time, another problem , if the client is now sending a large amount of data, a connection is really transmission, but connection although can give everyone share transmission, but the specific transmission, or a specific transmission channel will monopolize the entire connection TCP connection, Such a large amount of transmission, connection busy, or will lead to congestion occurred.
Workaround: Create connection pool, if different servers, there will be different connection objects, if a connection object transmission, there will be multiple connection objects at the same time transfer data. Connection pool After creating multiple connections, if a connection is idle for a specified amount of time, the connection pool makes a single connection Dispose and remove action, destroys the connection first, removes it from the connection pool, and ensures that the invalid connection is not consumed for long periods. 3.2, channel object creation, time consuming issues of destruction, management issues:
Channel object, that is, the soft connection on the TCP connection on the connection object, our program specifically uses the channel object for data transmission, I have recorded the channel object creation and destruction time consuming, is also very long, Why the creation and destruction of channel objects can be time-consuming, I checked the MQ clinet source and found that when creating and destroying channel, MQ client sent 2 data to the MQ server to notify the MQ server separately, The current channel data protocol, message format, and other communication-related information for subsequent data transfers. When destroyed, the data was sent back to the MQ server, the MQ server was notified, the channel was disconnected, and the resource occupied by the MQ server on the channel was released. In the usual case 2 times TCP data transmission, typically, it takes about 1 milliseconds, but it can be accepted, but in high concurrency, 2 TCP data transfers can be time-consuming, and if the MQ server is too stressful to respond to client requests, the client waits and the whole time takes longer. And MQ officials also recommend sharing using channel, rather than creating and destroying channel each time.
Now the question is, how can I realize the sharing channel, I checked the MQ client source code, connection object does have a collection in all the channel, but actually did not provide a way for me to use and manage the face of the Chanel,
The specific reasons are not known, interested friends can check the MQ client's source code. In addition, if I create more than one channel, if no longer use the channel after a specified time in idle time, how to destroy it, in addition I checked the source code, if we do not set the Connection object channel pool length, The number of channel for a connection object can be infinitely increased because channel is actually exclusive to the TCP connection at the time of transmission, and if channel infinitely increased, this TCP congestion will result if I set the length of the channel pool, Then the number of times I create the channel exceeds the length of the channel pool, the MQ client throws the exception directly, prompting the channel pool length to cross the line (which I found from the MQ client source), so that when I create the channel, To determine the length of the channel pool and to prevent cross-border, based on these issues, I developed a channel pool outside to create and manage channel objects for a single Connection object. If the number of Chnanel pools reaches a specified number, a new connection object is created, a channel is made in the new Connection object, and if the channel's idle time reaches a specified time, the channel object is destroyed in the background. If the channel of a connection object is completely destroyed and the connection object's idle time is reached, the connection object is also destroyed.
The performance test results are as follows: I have 200 threads on my side, sent 200,000 and 600,000 messages, done a stress test, plus a heartbeat function and idle over a specified time, active dispose of the function.
Connection pool Number: 4,channel Pool number: 15 Total time: 218.731 seconds, the average number of sent per second: 913