With your efforts, this app attracted more and more users. Everything works smoothly and you introduced more features into the app.
For example, for the registration process, your app calls the UserService not only to send SMS but also to push notifications and reward points to the user.

Assume each invocation takes 50ms, at least 200ms for a single registration is spent, doubling the original time cost.
When there's a peak in user requests, this results in a heavy workload for the server and suboptimal performance in general.
How can you improve the performance of the app?
Quickly you realized that there are 2 major pain points here:
- Synchronized: UserService only returns after all 3 tasks are completed
- Tight coupling: the result of user registration is highly coupled with the other three services. If one of the services fails, registration fails.
We should prioritize user registration as the main functionality and make the services independent of each other.
How can we solve it?
Messaging Queue.

UserService can just return after it throws the registration event to a messaging queue. This makes the synchronous process an asynchronous one. Other services only need to pull the event from the queue and consume it individually — a producer-consumer architecture.
Now, the registration process only consumes 50ms (calling UserService) and 5ms (throwing event to the MQ). That's a total of 55ms, which is approximately one-quarter of the previous structure.
But what queue should be used?
You may think of the JDK built-in queue. But there are problems regarding JDK queue:
1. The queue is present in the producer's local cache. Making consumers go into the producer's cache does not make sense. 2. Message Loss. If the producer's server is down, we have nowhere to retrieve the messages. 3. One queue can only be consumed by one service. If ServiceA consumes the message, the same message can't be consumed by ServiceB and ServiceC.
Ok, no in-built JDK queue. Any better alternative?
A Broker-like Messaging Queue, which receives producers' messages, has its persistence mechanism, and message pushing/pulling mechanism for the consumers.

That's how Kafka, RocketMQ, RabbitMQ, and some enterprise-specific MQ came about.
In general, MQ can achieve these things that the JDK queue isn't able to:
- The messages are persisted in the disk.
- High availability by master-slave structure, sharding, and load balancing.
- High performance with large throughput in receiving and publishing messages.
I hope you find this article helpful.
I am a backend software engineer. If you are aspiring to learn about technology, follow my channel and stay updated on my inspirations from my daily work and life.
Read More: A Case About Java Static Keyword During My Job How Can You Solve This Java Multithreading Interview Problem?
Get Connected: MyLinkedIn