Reactive Refactoring of Trip.com Message Push Platform: From Blocking Servlet to EventLoop NIO
This article analyzes the limitations of Trip.com’s blocking‑IO servlet architecture for its email push service, proposes a reactive, non‑blocking redesign using EventLoop and NIO, details the thread‑model and code changes, and demonstrates performance gains through benchmark comparisons.
The Trip.com message push platform, originally built on a synchronous, blocking‑IO servlet model, suffered from high thread counts, excessive memory usage, and poor scalability under peak load.
Problems identified: thread‑context switching overhead, high deployment cost due to thousands of worker threads, and increased timeout risk when requests block on downstream services such as AWS SES.
Solution: migrate to a reactive architecture using EventLoop + NIO to achieve asynchronous, non‑blocking I/O. The redesign introduces multiple thread pools: Tomcat workers, Netty EventLoop for AWS SDK, and callback pools for RPC and business logic.
Key code changes include updating the Tomcat connector configuration to allow up to 1024 threads:
<!-- 最大线程数1024,在极端情况下,最高可能启动1024个线程 -->
<Connector port="${port.http.server}" protocol="org.apache.coyote.http11.Http11NioProtocol" minSpareThreads="20" maxThreads="1024"/>Switching to AWS’s asynchronous SDK replaces the blocking HttpClient:
SendEmailResult sendEmail(SendEmailRequest sendEmailRequest);Thread‑pool for async SDK callbacks is configured as:
int processors = Runtime.getRuntime().availableProcessors();
int corePoolSize = Math.max(8, processors);
int maxPoolSize = Math.max(64, processors * 2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 10, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadFactoryBuilder().threadNamePrefix("sdk-async-response").build());Business logic is wrapped into Reactor’s Mono to unify asynchronous models:
// sending with async non‑blocking io
return Mono.fromCompletionStage(() -> {
CompletableFuture<SendEmailResponse> responseFuture = awsAsyncClient.sendEmail(sendEmailRequest);
return responseFuture;
})
.map(response -> this.onSuccess(context, response))
.onErrorResume(throwable -> this.onFailure(context, throwable));The overall request flow now follows:
Tomcat accepts the connection and hands the request to a worker thread.
The worker performs synchronous logic, then enqueues the request to the Netty EventLoop.
AWS async SDK processes the I/O on Netty’s EventLoop, returning a CompletableFuture.
The future is converted to a Mono, allowing reactive composition and callbacks.
Callbacks are registered with the RPC framework (using ListenableFuture) and finally complete the AsyncContext to send the response back through Tomcat.
Performance testing shows the reactive version achieves 2–3× higher QPS, ~50% lower latency, and reduced memory consumption compared to the original blocking implementation.
In conclusion, adopting a reactive, NIO‑based architecture significantly improves throughput, resource utilization, and scalability for IO‑intensive backend services, while also providing a unified asynchronous programming model across different frameworks.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ctrip Technology
Official Ctrip Technology account, sharing and discussing growth.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
