📜 ⬆️ ⬇️

Will Node.js always be slower than Golang?

There is a feeling that literally every week there is a new “web framework” for Node.js, which is called something that works faster than anything that came before it. Everyone knows that Express is slow, but can a regular framework really improve the performance of the Node.js I / O subsystem? The only thing it can do is eliminate the excessive load on the system created by Express. There is no talk of improving something fundamental. As a matter of fact, in order to radically improve the situation, you need to work at a deeper level, and not to add new abstractions over Node.js.

image

What is needed in order for the Node.js platform to be able to create server applications that run much faster than everything that is today?

Analysis of the situation


Express is one of the oldest web frameworks for Node.js. It is based on the standard features of this platform, giving developers a user-friendly interface, built around the concept of the application, and allowing you to manage URL routes, parameters, methods, and so on.

Express is simple; it helps programmers quickly develop applications. The only thing he lacks is productivity. Constantly emerging projects, such as Fastify, tend to give developers the same features as Express, but with less loss of performance. But they themselves are what creates an additional load on the system and badly affect performance. They are strictly limited to what the Node.js platform can provide. And she can give, in comparison with competitors, not so much.


The number of HTTP requests processed by different servers per second

Pay attention to the red line. This is the maximum Node.js platform. The frameworks for it, regardless of whether their names contain the word “fast” or not, cannot cross this line. In fact, this is a very low performance limit if you compare the Node.js platform with its popular alternatives like Golang.

Fortunately, Node.js supports C ++ - addons, Google V8 binders, which allow you to bind JavaScript and C ++, and allow you to call any mechanisms from JavaScript, even if these mechanisms are provided by something different from Node.js platform.

This makes it possible to expand and improve the capabilities of JavaScript-based applications, allows you to reach new levels of performance. This allows JavaScript-based programs to squeeze everything out of the Google V8 engine, not limited to what the Node.js developers considered to be quite sufficient.

About exiting µWebSockets.js


Earlier this month, I released a new project - µWebSockets.js . GitHub is used as a hosting for its code, not npm, but you can install it for Node.js using npm like this:

npm install uNetworking/uWebSockets.js#v15.0.0 

You don’t need a compiler to work with µWebSockets.js. Linux, macOS and Windows are supported. The initial version of the system is 15.0.0, versioning is carried out according to the rules of semantic versioning.

µWebSockets.js is an alternative web server for backend applications written in JS. It consists of approximately 6,000 lines of C and C ++ code, and significantly bypasses in performance the best solutions written in Golang. So, bitfinex.com has already ported both its trading APIs (REST and WebSocket) to µWebSockets.js and is gradually introducing them into production. Paflo Ardoino of Bitfinex notes that this is a great project. I would also like to say that the fact that I had the opportunity to release µWebSockets.js is entirely due to the support provided to me by BitMEX, Bitfinex and Coinbase.

Features µWebSockets.js


µWebSockets.js is a new project released under the Apache 2.0 license, which is a continuation of what is known as “uws”. This project is a complete stack for Google V8, starting at the kernel level of the operating system, completely replacing the standard Node.js features and representing a stable, secure, standards-compliant, fast and lightweight I / O subsystem for Node.js. This is how the JS application interacts with the operating system using µWebSockets.js.


Interaction of JS application with OS using µWebSockets.js

As you can see, the project consists of several layers. Each layer depends only on the previous layer. This architecture simplifies the identification and correction of errors, as well as the work to expand the solution by implementing new features in it.

It should be noted that the µSockets layer itself consists of three sublayers, which are the mechanisms for working with events and the network, as well as tools for data protection. This allows, if necessary, to replace parts of the solution, to add alternative implementations of these or those possibilities to the system, while not encountering the need to change the code at a higher level.

For example, if you need to replace OpenSSL with something, all you need to do is change the ssl.c file with six hundred lines of code for what you need. However, other layers of the system do not even know what SSL is. This approach, in addition to the convenience of replacing some parts of the system with others, also leads to simplification of the process of error detection.


ΜSockets inner liners

The architecture presented here is seriously different from the monolithic one that is used in Node.js, where you can find libuv calls, commands to work with the system, and access OpenSSL and V8 in the same source code file. In Node.js, all this is mixed, no one set out to isolate certain parts of this platform. This greatly complicates the process of making major changes to Node.js.

About development for µWebSockets.js


Here is an extremely simplified and abbreviated example of working with µWebSockets.js, whose main task is to demonstrate the basic capabilities of the system.

 /* SSL-приложение с маршрутами */ uWS.SSLApp({   key_file_name: 'misc/key.pem',   cert_file_name: 'misc/cert.pem',   passphrase: '1234' }).get('/hello', (res, req) => {   /* Очень сильно упрощено */   res.end('Hello World!'); }).ws('/*', {   open: (ws, req) => {       console.log('A WebSocket connected via URL: ' + req.getUrl() + '!');   },   message: (ws, message, isBinary) => {       /* OK имеет значение false при переполнении        * рекомендовано дождаться сброса буфера */       let ok = ws.send(message, isBinary);   },   drain: (ws) => {       console.log('WebSocket backpressure: ' + ws.getBufferedAmount());   },   close: (ws, code, message) => {       console.log('WebSocket closed');   } }).listen(port, (token) => {   if (token) {       console.log('Listening to port ' + port);   } }); 

In a certain sense, we can say that µWebSockets.js using SSL can bypass Gorilla WebSocket, the implementation of the WebSocket protocol on Go, without SSL. That is, it turns out that the JS code can exchange messages using SSL even faster than, under certain conditions, a code written on Go without SSL. I believe that this is an excellent result.

Fast WebSocket protocol implementation


Socket.IO, in many ways, can be considered the equivalent of Express, working in real time. Both of these projects appeared quite a long time ago, it’s easy to work with them, they are popular. But they, among other things, are also slow.


Various WebSocket implementations

The tasks that the Socket.IO developer helps to solve are reduced to the implementation of the functionality of publishing messages and subscribing to them, to the possibilities of sending and receiving messages.

At the same time, it is necessary to note the uselessness of using some spare mechanisms for working with the WebSocket protocol, since browsers have long supported this technology. SSL traffic cannot be interpreted by corporate proxy servers; it passes through them in the same way as any HTTP traffic passes; as a result, using the WebSocket protocol over SSL does not block the corresponding traffic. Spare mechanisms for supporting WebSocket can be foreseen, but there is no point in using them. They only unnecessarily increase the complexity of the decisions.

One of the goals of µWebSockets.js is to give developers similar capabilities as those in Socket.IO so that µWebSockets.js can completely replace Socket.IO without the need for any higher level wrappers. . This is possible if you do not use any special non-standard protocol.

Many companies are faced with the problems of publishing messages and subscribing to them when working with WebSocket. It should be noted that in the release described by µWebSockets.js, these features were not given special attention, but now they are working hard. What happens as a result will be very fast (tests show that µWebSockets.js is already faster than Redis). So stay tuned.

Results


Currently, µWebSockets.js is developing, new features are added to the project, bugs are fixed. It will take some time to get rid of those minor flaws that are characteristic of the first releases of new programs. Consider the fact that we are talking about a large project consisting of many thousands of lines of code written in C and C ++, which is stored in three repositories. Here lies the JavaScript wrapper - uWebSockets.js. Here is a web server written in C ++ - uWebSockets. And here is the base library written in C - uSockets.

The project in question is used by companies, the programs used by them create a huge load on input-output subsystems. In these companies, stability and security, which is completely natural and obvious, are the most important characteristics of the software they use.

Dear readers! Do you plan to use µWebSockets.js in your projects?

Source: https://habr.com/ru/post/439976/