How Suning Supercharged Node.js Performance: From CSS Merging to 75% TPS Gains
This article details Suning's step‑by‑step Node.js performance improvements—including CSS/JS registration, EJS template caching, static route optimization, and TPS enhancements—that reduced request latency, cut resource loads, and boosted throughput by up to 75 percent.
Node.js Project Background
Since 2016 Suning has been running large‑scale Node.js projects using an Nginx + Node.js + PM2 stack, upgrading from Node 6 to 8 and migrating from Express to Koa2, with performance optimization as a core focus.
Initial Optimization – CSS/JS Registration and Merging
EJS Template Related Optimization
Suning initially used Express, later switching to Koa after Node.js 8 LTS, and employed EJS as the template language.
Impact of Merging CSS and JS
Common parts were extracted into layout.ejs, and pages included it via EJS include. This separated layout from business logic but placed static resource tags inside the body, causing many <link> and <script> tags to appear in the body.
//layout.ejs
<link type="text/css" rel="stylesheet" href="public.css" />
<script src="public.js"></script>
...
include(page1);
//page1.ejs
<link type="text/css" rel="stylesheet" href="page1.css" />
<script src="page1.js"></script>
<h1>hello</h1>After rendering, the page showed resource tags inside the body:
...
<link type="text/css" rel="stylesheet" href="public.css" />
<script src="public.js"></script>
</header>
<body>
<div class="header"></div>
<link type="text/css" rel="stylesheet" href="page1.css" />
<script src="page1.js"></script>
<h1>hello</h1>
</body>
...Suning introduced an EJS static‑resource registration mechanism using getResource() placeholders and a register() method to control where resources are injected.
...
{{{CSS_PLACEHOLDER}}}
</header>
<body>
<div class="header"></div>
<h1>hello</h1>
</body>
{{{JS_PLACEHOLDER}}}
...After replacement, CSS and JS tags appear in the correct locations, and registered resources are merged into combined URLs, reducing the number of HTTP requests.
…
<link type="text/css" rel="stylesheet" href="public.css,page1.css" />
</header>
<body>
<div class="header"></div>
<h1>hello</h1>
</body>
<script src="public.js, page1.js"></script>
...Cache Mechanism
Because each request performed string replacement, Suning added a cache keyed by request pathname; if a page was cached, getResource() returned the cached content and the registration step was skipped, shaving 4–8 ms off response time on repeated accesses.
Advanced Optimization – Massive Route Matching
Suning’s Hong Kong site had 173 static routes and 11 dynamic routes. Express matches routes by converting each rule to a regular expression and testing them sequentially, leading to O(n) complexity.
Static routes were re‑implemented as a hash map (Object) for O(1) lookup, while dynamic routes still use regex. This change dramatically reduced matching time, though developers must ensure route order is respected.
High‑Level Optimization – TPS Improvement
Initial stress tests showed very low TPS despite using Node.js 8.9.1. The bottleneck was disabled EJS template caching, causing disk reads on every render. Enabling cache yielded a ten‑fold performance boost.
Further gains required reducing synchronous operations. Profiling revealed CPU consumption inside the EJS engine: shallow copies and repeated fs.existsSync checks for includes. Caching include existence and using prototype‑based object creation eliminated unnecessary copies.
The function getIncludePath still performed absolute‑path resolution on every include, invoking file‑system calls. Suning introduced a per‑template map to cache these mappings, avoiding repeated path calculations.
After these optimizations, local benchmarks showed a 50 % performance increase, and online stress testing raised TPS from ~2000 to over 3500—a 75 % improvement, surpassing the Java baseline.
Conclusion
Node.js excels at asynchronous I/O, so performance bottlenecks usually stem from synchronous code. Suning’s optimizations—resource registration, caching, route‑matching redesign, and deep EJS engine tweaks—demonstrate how targeted backend improvements can dramatically boost throughput.
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.
Suning Technology
Official Suning Technology account. Explains cutting-edge retail technology and shares Suning's tech practices.
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.
