Scaling Websockets using uWebSockets.js

You must have read a lot of articles on scaling WebSockets, but I think this is what you're looking for. I'll talk about uWebSockets, and if you've never heard of it, here's a little intro: you'll never need any other websocket server library or horizontal scaling if you use uWebSockets—unless you're handling billions of connections like WhatsApp, which I think isn't the case, obviously.

speed comparison between uwebsockets and other libraries

1. So what is that? What is uWebsockets?

In simpler words, 47 smart people, to be exact, have created a wonderful library using C and C++ in just 10,000 lines that allows you to create a WebSocket server, a HTTP server, a HTTPS or HTTP/2 server, and, last but not least, a HTTP/3 server. Fascinating, right?

2. Let's talk business now: which one should you use—the JavaScript library or the C++ one?

If you do a Google search for uWebSockets, which you have already done by now I assume, you will see that they have a library written in C++, and if you dig further down, you will find a library for Node.js too.

Now, if you want to handle everything by yourself—by everything, I mean the garbage collection—go ahead and use the C++ library. Its the most scalable. I have added a benchmark at the end of this section that will give you a pretty good idea about the scalability.

From my experience, go for Node.js. While C++ is a faster option and excels over Node.js in all performance benchmarks (HTTP req/sec, WebSocket broadcast, and WebSocket echo/sec), when I ran the same server in both Node.js and C++, I found memory consumption per connection was significantly higher on the C++ server than on the Node.js server. My best guess is that the V8 garbage collector in Node.js really does a good job.

For 10K connections, the Node.js server was only consuming about 70 MB of memory, whereas C++ was consuming around 500 MB. The difference is pretty big, right?

3. I have a lot of RAM, I can afford large memory consumption. Why should I still go for the Node.js library?

Well, do you know how you would make an API call using C++, or how you would connect to an SQS queue? Maybe yes, maybe not. But there's one thing that comes with Node.js: its simplicity. Things are much simpler when you work with Node.js, and I believe that's why the developers created it for Node.js too. You'll find an abundance of resources on how to do just about anything in Node.js, but for C++? Nah, not so much. You see the problem?

But what about the performance? C++ gives better performance than the Node.js library—what about that? Well, I would say the performance difference is not that significant. If you write the code in an optimized manner, you can achieve almost the same performance as the C++ library.

4. What is the limitation of uWebsockets then?

As per my experience, when I hosted my server on a 1 CPU and 1 GB RAM machine and ran some benchmarks—specifically, I tried to make lots of HTTPS connections very quickly—after some time, the connections started timing out. That was because that poor single CPU wasn't able to handle the handshaking, key exchange, and data encryption for all those fast incoming HTTPS connections.

I upgraded the server to 1 premium Intel CPU and 2 GB RAM, and things were smooth. I was able to make 1 HTTPS connection per millisecond—literally 1,000 HTTPS connections per second. I would say it's spooky fast.

And voilà—there it was: 10,000 stable connections in 10 seconds with just 70 MB of memory usage.

5. Do I need to make any changes to my linux OS to handle large number of connections?

Well, for starters, the only change that you need to make is to increase the number of file descriptors for the user who is running the server. One file descriptor is needed for every connection, so the more file descriptors you have, the more connections you can make. Let's say X is a user, and he is running the uWebSockets server. You can increase the number of file descriptors for X by editing the /etc/security/limits.conf file.

X soft nofile 1024045
X hard nofile 1024045

Add the above lines in the limits.conf file and reboot the VM or your computer. After rebooting, enter the command ulimit -n, and you will see the number of file descriptors has been increased to 1024045. You can increase or decrease this number as per your use case; normally, you won't face any problems until 1 million.

There are many more parameters that you can tweak to scale it even better, but that is out of scope for this article. If you're curious enough, I'm sure you can find them using ChatGPT :)

6. How fast is uWebSockets compared to its competitors?

I would say no one stands a chance, Here are some metrics from uWebsockets official github documentation :

At least 10x that of Socket.IO, 8.5x that of Fastify.

I also want to share an interesting official Twitter post by uWebSockets on this reference : fastest standards compliant web server.

7. Does that mean that uWebsockets can be used as a HTTP/HTTPS server too? its not only a websocket server library?

Definitely not, uWebSockets is a very versatile library, and it not only focuses on WebSockets. You can create HTTP and HTTPS servers too, and that also performs a whole lot better than Express.js or any other framework out there.

Here is an idea about how fast its HTTPS server is, picked up straight from the official documentation :

Performance wise you can expect to outperform, or equal, just about anything similar out there, that's the fundamental goal of the project. I can show small-message cases where µWS with SSL significantly outperforms the fastest Golang servers running non-SSL. You get the SSL for free in a sense (shown to be true for messaging with up to 4 kB per message).

8. How to compile and build uWebsockets in C++

When I first tried to run the uWebSockets C++ server, I had some struggles, and I still see lots of people asking, "How can I run a uWebSockets C++ server?" So, here's a little tutorial for you all. I am doing all of this in Ubuntu, but I'm pretty sure it will work on any Linux OS.

  • Step 1: Clone the uWebSockets repository from GitHub
    git clone https://github.com/uNetworking/uWebSockets.git
  • Step 2: Go inside the directory you cloned
    cd uWebSockets/
  • Step 3: Go inside uSockets directory
    cd uSockets/

    You will find that this directory is empty, but if you go and check on GitHub, you will see that it's another repository called uSockets that is used by uWebSockets, and it's not cloned. So, we are going to clone it and replace this empty folder with it.

  • Step 4: Go back to main uWebsockets directory and delete the uSockets folder
    cd ..
    rm -rf uSockets/
  • Step 5: Clone the uSockets repository
    git clone https://github.com/uNetworking/uSockets.git
  • Step 6: Install g++
    sudo apt install g++
  • Step 7: Install make
    sudo apt install make
  • Step 8: Install zlib1g-dev
    sudo apt install zlib1g-dev
  • Step 9: run make
    make

    There you go— all your examples are compiled now!

9. How to compile and build uWebsockets in Nodejs

There is nothing much that needs to be done in Node.js. Simply install the library using the npm command given below, and you are good to go.

npm install uNetworking/uWebSockets.js#v20.48.0

Now you can copy and paste one of the suitable examples for your use case into your index.js file, and you can start from there :)

10. Conclusion

As more and more people are getting to know about uWebsockets, thay are migrating from there slow libraries to uWebsockets, I myself when I started making this website was using socket.io but it was not fast enough and was not able to handle large number of connections so I migrated to the only best option available to me uWebsockets.

If you are looking for a suitable library for creating servers, I would definitely recommend it. It's the fastest, it's versatile, and it's easy to use. What more could you ask for?

If you have any questions or concerns, please contact us.

Last Updated: 10/10/2024