1 | ## Understanding the analysis
|
2 |
|
3 | Node.js provides a platform for non-blocking I/O.
|
4 | Unlike languages that typically block for IO (e.g. Java, PHP), Node.js passes I/O operations
|
5 | to an accompanying C++ library (libuv) which delegates these operations to the Operating System.
|
6 |
|
7 | Once an operation is complete, the notification bubbles up from the OS, through libuv, which can then
|
8 | trigger any registered JavaScript functions (callbacks) for that operation. This is the typical
|
9 | flow for any asynchronous I/O (where as *Sync API*'s will block, but should never be used in a
|
10 | server/service request handling context).
|
11 |
|
12 | The profiled process has been observed is unusually idle under load, typically this means
|
13 | it's waiting for external I/O because there's nothing else to do until the I/O completes.
|
14 |
|
15 | To solve I/O issues we have to track down the asynchronous call(s) which are taking an
|
16 | abnormally long time to complete.
|
17 |
|
18 | I/O root cause analysis is mostly a reasoning exercise. [Clinic.js Bubbleprof](https://clinicjs.org/bubbleprof) is a tool developed specifically to inform and ease this kind of reasoning.
|
19 |
|
20 | ## Next Steps
|
21 | - Use `clinic bubbleprof` to create a diagram of the application's asynchronous flow.
|
22 | + See <code class='snippet'>clinic bubbleprof --help</code> for how to generate the profile
|
23 | + Visit the [Bubbleprof walkthrough](https://clinicjs.org/bubbleprof/walkthrough) for a guide on how to use and interpret this output
|
24 | - Explore the Bubbleprof diagram. Look for long lines and large circles representing persistent delays, then drill down to reveal the lines of code responsible
|
25 | - Pay particular attention to "userland" delays, originating from code in the profiled application itself.
|
26 | - Identify possible optimization targets using knowledge of the application's I/O touch points (the I/O to and from the Node.js process, such as databases, network requests, and filesystem access). For example:
|
27 | + Look for operations in series which could be executed in parallel
|
28 | + Look for slow operations that can be optimised externally (for example with caching or indexing)
|
29 | + Consider if a large processes has good reasons for being almost constantly in the queue (for example, some server handlers)
|
30 |
|
31 | ## Reference
|
32 |
|
33 | * [Overview of blocking vs non-blocking](https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/)
|
34 | * [`console.time`](https://developer.mozilla.org/en-US/docs/Web/API/Console/time)
|
35 | * [`console.timeEnd`](https://developer.mozilla.org/en-US/docs/Web/API/Console/timeEnd)
|
36 | * **Advanced**: [Node Docs: Perf Hooks](https://nodejs.org/api/perf_hooks.html)
|
37 | * **Advanced**: [Node Docs: Async Hooks](https://nodejs.org/dist/latest-v8.x/docs/api/async_hooks.html)
|
38 | * **Advanced**: [V8 Stack Trace API](https://github.com/v8/v8/wiki/Stack-Trace-API)
|