Node 9.X IPC Performance

I wanted to perform image analysis on a public camera overlooking one of the busiest boulevards in Sofia, Bulgaria:

The overall goal is to clip just the part of the image for a single direction of the boulevard and count the number of vehicles passing by in the field of view. Then index the counts aggregated on minute, hour and daily intervals to get a nice overview of the traffic ebbs and dips.

I chose to do it in Node.js and Typescript. The architecture of the components is:

The "Image Downloader & JPEG decoder" component has the following performance markers:
  • around 200ms to download around 60KB JPEG image on a public WiFi in a cafe. 
  • around 83ms on a MacBookPro (2017) to unpack the JPEG into Buffer of bytes. The image has resolution 1280px by 720px. Each pixel is represented with 4 bytes, for a total of 3.5MB of memory of unpacked Uint8Array.
This gives total time for download and decompression between 400 and 500 ms, and a new image ready for analysis roughly every half second:
Sat Apr 14 2018 11:22:19 GMT+0300 (EEST): Image(1280 x 720) processed in 403.811349 ms
Sat Apr 14 2018 11:22:20 GMT+0300 (EEST): Image(1280 x 720) processed in 305.733611 ms
Sat Apr 14 2018 11:22:21 GMT+0300 (EEST): Image(1280 x 720) processed in 484.65647 ms
Sat Apr 14 2018 11:22:21 GMT+0300 (EEST): Image(1280 x 720) processed in 306.6703 ms
Sat Apr 14 2018 11:22:21 GMT+0300 (EEST): Image(1280 x 720) processed in 283.651022 ms
Sat Apr 14 2018 11:22:22 GMT+0300 (EEST): Image(1280 x 720) processed in 310.54076 ms
Sat Apr 14 2018 11:22:22 GMT+0300 (EEST): Image(1280 x 720) processed in 301.422415 ms
Sat Apr 14 2018 11:22:23 GMT+0300 (EEST): Image(1280 x 720) processed in 267.434492 ms
Sat Apr 14 2018 11:22:23 GMT+0300 (EEST): Image(1280 x 720) processed in 277.57939 ms
Sat Apr 14 2018 11:22:24 GMT+0300 (EEST): Image(1280 x 720) processed in 280.239104 ms
Sat Apr 14 2018 11:22:24 GMT+0300 (EEST): Image(1280 x 720) processed in 277.993232 ms
Sat Apr 14 2018 11:22:25 GMT+0300 (EEST): Image(1280 x 720) processed in 263.314174 ms


Obviously Node.js is single threaded but very efficient in downloading resources with its event based model. Practically the thread is free to perform any other task for those 200ms when the image is being transmitted over.

But the JPEG decoding (see jpeg-js) is CPU intensive. In this case Node.js single thread is completely blocked. So I decided to experiment with Node.js Cluster API and to spawn a separate process to host the "Image Downloader & JPEG decoder" component. In this way the CPU on the main thread will be completely free in multi CPU hosts to perform the image analysis.

So I created a Cluster with the master process just waiting for messages and printing performance timings when such messages arrives. The spawned process will download, JPEG decode and send an IPC message with process.send()

I got the following timings:
Master 10167 is running
Image Downloader process(PID=10168) started
2018-04-14T07:51:13.145Z: Image(1280 x 720) processed in 386.500649 ms
2018-04-14T07:51:16.523Z: Image(1280 x 720) processed in 5.429576 ms
2018-04-14T07:51:21.078Z: Image(1280 x 720) processed in 713.327255 ms
2018-04-14T07:51:24.215Z: Image(1280 x 720) processed in 207.49122 ms
2018-04-14T07:51:27.152Z: Image(1280 x 720) processed in 229.344572 ms
2018-04-14T07:51:30.090Z: Image(1280 x 720) processed in 848.952361 ms

The image processing (download & decode) is roughly the same. But.. hh.. wait.. what.. why the main thread gets a new image only once per 3 seconds? It turns out that IPC does not come for free. The spawned process must encode, transmit and then decode those 3.5MB of data to the master process. 

This result defeats the purpose of having a separate thread/process handle the image decoding. Since the IPC communication on a big file is roughly order of magnitude more expensive. When using Cluster API in Node.js for your architecture have in mind that "heavy" IPC message will actually downgrade the performance. You should use it for pooling sockets and exchanging light messages only.

Comments

Popular posts from this blog

Data types: Backend DB architecture

Node.js: Optimisations on parsing large JSON file

Back to teaching