简体   繁体   中英

Single vs Multi-threaded JMS Producer

I wanted to see how much time difference would it make to use a multi-threaded producer instead of a single threaded one. I setup an ActiveMQ on my local machine, wrote a producer class that would initialise and start a JMS connection in its constructor. I set the message limit to 3M and it took about 50 seconds to push all the messages over to ActiveMQ. I sent just one string "hello world" 3M times.

Then I used the same producer object (one connection but multiple session) and ran it with an ExecutorService of thread size eight. In the run method, I would divide 3M by 8 just to make sure each thread sends no more than 375000 messages. It took about 60 seconds to push all the messages in this case.

ExecutorService service = Executors.newFixedThreadPool(8);

    for (int i = 0; i < 8; i++) {

        service.execute(producer);
    }

Then I created eight producers with each producing having it's own connection and ran them with ExecutorService or thread size eight. This time it took about 68 seconds to push all 3M messages.

for (int i = 0; i < 8; i++) {
        service.execute(new Producer());
    }

I'm wondering, why would a single threaded producer perform better here? I ran each scenario about 10 times but the results remained the same.

The connection to the Broker is using a single TCP/IP connection to push each message over the wire. In a most cases there would be no advantage to multiple threads writing to the producer on the same connection as all calls will become serial as they pas through the JMS layer into the wire protocol layer. In your case it takes a bit longer due the thread scheduling plus lock contention plus the overhead of managing the thread pool.

The other thing to consider is that depending on your producer and the destination you are sending to message will be sent synchronously to the broker and the producer will block waiting for the acknowledgement from the broker that the message has been stored and won't be lost. This incurs a large overhead but is required for guaranteed message delivery. Even if you are using multiple connections the throughput of all of them can be limited by the speed of the disk where the broker is running as it must write all persistent messages first.

It's really outside the scope of StackOverflow to try and optimize your code, you need to do some research and understand the implications of the architecture of a JMS broker and the tuning capabilities of the Broker you use. If your threads are opening a new connection for each message send this would be a big performance hit as establishing a new connection is an expensive operation so I'd recommend looking into JMS connection pooling also as a way to boost client performance.

For your case you could look into async sends or sending batches of message in transactions to reduce the amount of time each send takes.

Multithreading can be slower than threading for a few reasons. One is that the CPU of the computer is a finite number and thus can't run all the threads at the same time making it slower. Another is that you also have a finite amount of memory causing the thread to take longer since it takes more memory.

Think about multithreading in this way, you have a hallway that can fit 3 at a time optimally. If you have less people going through that hallway at once then it will take longer to get all the people through it. Also, oppositely if you try putting too many people through it at once the hallway to get clogged up and it will be hard for anyone to get through.

This is how multithreading can be bad here and also in some other cases.

--------------------------------------EDIT OF WHAT IS HAPPENING:----------------------------------------------------

You said in your problem that you would divide 3M by 8 for you single threaded program so that it would send no more than 375000 messages. But when you multithreaded you sent all 3M instead of just 375000? If this is true than the reason multithreading is slower than single threading is because java can't perform different threads at the EXACT same time, it looks like its performing at the same time because of the speed its running, but it really is switching between all the thread you have set up. And it DOES take a small bit of time to switch between it. A few nanoseconds, therefore it would take longer since even though each thread in the multithread is running the same amount in the single thread, it needs to switch between threads that make it take that ever so small amount of time that add up to the 8 seconds extra that it took to run.

From a JMS application perspective you have written the application to multi-threaded; multiple sessions each with their own JMS producer objects being driven by separate threads. Assuming that your application has no contention on the resources such as locks etc that is good.

In terms of how efficient it is then at sending messages is up to how efficiently implemented the JMS provider is, both in terms of client and server sides pieces. Are there any locks or contention within the JMS implementation? Maybe it's trying to send everything over the same socket - in which case there's contention. Or maybe there's some other lock.

Maybe there's a lock server side on the underlying queue data structure server side.

To answer your question really needs detailed knowledge of the specific JMS provider.

I would guess overhead from managing multiple sessions, their synchronization with access to single connection, and thread switching could be the reasons.

Why it should work faster with multiple threads on sending side ? The line is only one and maximal number of threads I see as potential performance gain is two - when the first one is sending data, the second one is preparing its data and they switch alternate.

My money is on Calanais concept. Have you tried monitoring the application while it is running? A simple tool like VisualVM would help you to find out where the time is spent.

The difference you notice is very small, but I think the multi-thread processor is spending more time because the concurrency for the cpu resources between the threads. The multi-thread processor needs to share the cpu between the threads, and this may cost time and extra-processing and sometimes become your process more slow. While the single thread processor does not need to share the cpu with no other thread, it can run more efficiently. The another aspect is related to the resources used for each thread. They use only strings in memory, they don't access another resource, as disk files or databases or tcp ports. In this case, I think, single thread process will be faster than a multi thread process.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM