Nodeschool workshops have finally started in Bratislava (hosted by Progressbar). At the first meet-up we set up node environment and went through several workshoppers from the nodeschool site. There were people from multiple areas and with different knowledge of javascript (from beginners to experts). Workshop was more or less self-organized with a possibility to ask senior programmers for help. In the middle of workshop there was a presentation which showed us different approaches how to handle concurrent tasks in nodejs. I will focus on it in this tech talk.

Javascript is from it’s nature single-threaded. That means when you run your web server (without load balancing or clusters) it uses only 1 CPU. Nevertheless nodejs is considered one of the fastest web servers nowadays. It’s because applications written for node are supposed to do lots of non-blocking i/o operations.

Non-blocking i/o operation does not block further code execution until the operation finishes. In javascript these operations are asynchronous functions handled by callbacks, events or promises. If function is blocking or not depends on it’s implementation but in general javascript libraries are written asynchronously and non blocking.

Here are some examples of non-blocking i/o operations:

  • file reading
  • database operations
  • http requests
  • bash execution

On the other hand, there are time consuming tasks which blocks execution (heavy computation), e.g.:

  • factorial computation
  • calculating fibonacci series
  • processing large data

It’s worth to say that almost all operations which are regular web servers expected to do are i/o.

 

Back to nodejs performance, let’s say I have 3 routes in my rest API:

  • /index‘ – prints “Hello world!” (takes 3ms)!
  • /factorial‘ – computes factorial of some big number – blocking (takes 3000ms)
  • /fractal‘ – request db to compute bit fractal – non blocking (takes 3000ms)

If I make requests in this order:

I will get response:

I had to wait 3 seconds to get “Hello World” responses. What happened is that factorial operation blocked all execution and other requests had to wait until it finished. It is too slow and if I had many clients it would be practically not usable.

If I make similar requests but for fractal:

and I will get response:

Fractal operation did not block other requests. It created query to the database, waited (but not blocked) until it’s finished and then sent response back to the client. If your server was under heavy load, other clients would not be affected and the responsivity would be great. And what is the best you don’t need any threads to serve tousands of clients concurrently.

If you despite all above need to run time consuming tasks on your server, there are several options.

Service workers

In today’s web browsers it is known the concept of servis workers. Worker runs in different thread as to the main javascript so that it does not block page rendering and other actions which affects user experience. There is a library for nodejs called webworker-threads which implements worker threads API.

When new worker is created library creates completely new process and runs it with given source code. It is possible to send and receive data between server and worker. It is also possible to create pools of workers, which is a cool feature when you don’t want to break down your server.

Main drawback is that workers runs in completely different context as server. For more info look into documentation.

Node Cluster

New versions of nodejs provides Cluster API. It is possible to fork current process and run multiple instances of the server. The main process is called ‘Master’ and the forked processes ‘Workers’ (similiarly to worker threads).

Basic use case for use of node cluster is, let’s say, request load balancing between workers to utilize multiple CPUs. It is possible to use this API and implement workers which runs time consuming tasks.

Currently node cluster does not support thread pooling, so you have to implement it yourself.

Summary

Nodejs is one of the most performant webservers in these days. It’s single threaded nature does not stop it to serve tousands of clients at time with a great responsivity. However it’s important to understand which type of tasks is nodejs dedicated for – non-blocking i/o operations. If you need to run time consuming tasks despite all of this, you can use webworker-threads library or built-in node cluster API.

Related Post

Leave a Comment

© 2021 Instea, s.r.o. All rights reserved. Privacy policy

Contact us

Where to find us