ExpressJS vs. Actix-Web: performance and running cost comparison

栏目: IT技术 · 发布时间: 4年前

内容简介:Thanks DarinIf you have found any problem please feel free to drop comment or DM me on

ExpressJS vs Actix-Web. It is exactly what you think

ExpressJS vs. Actix-Web: performance and running cost comparison

Feb 25 ·7min read

The goal of this analysis is to try to understand what kind of gains a programmer should expect by using Rust and actix-web rather than Node and Express under typical use, without custom optimizations.

Summary

  • Compare performance, stability and running cost of simple microservice-like workload on node/expressJS Vs actix. Setup is limited by 1 CPU Core and using a common pattern of development for each.
  • Actix provides 85% running cost saving in a heavily loaded environments, while also providing smaller memory footprint and more runtime safety warranties. It also has an option to scale on CPU with minimum memory expense which unveils more saving opportunities.
  • Rust’s types and concurrent logic validation saved time providing reliable working code after it compiled, Node’s solution required some time to debug and fix issues in runtime as well as explicit type validation.
  • ExpressJS is fast, minimalist and most popular Node.js web framework. Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine . It is among top 10 popular application servers used by high traffic sites according to w3techs research as it’s share is growing.
  • Actix is a small, pragmatic, and extremely fast web framework for Rust. According to techempower round 18 report is fastest web application platform in 4 out of 6 categories.

Disclaimer!! Provided research is focusing purely on quality aspects and cost of running apps. It should not be taken as advice to rewrite from JavaScript to Rust and it does not account for cost of such rewrite.

Test scenario and setup

Presume we have microservice which allows its clients to search for tasks where tasks might be assigned to workers. Our simple database model has just two tables WORKER and TASK, and TASK has assignee relation to WORKER :

Let’s compare how application servers behave and check on resource consumption under moderate to high load. Let’s assume that database is not a bottleneck for now (we’ll leave it for different post).

Node.js app is built with express web framework and knex SQL builder library, both are widely popular. Knex claims to use prepared SQL statements under the hood and has embedded pool so it should be comparable to the Rust setup. Main handler:

Actix-web service is based on async-pg example . It uses deadpool-postgres as async connection pool and tokio-pg-mapper for SQL type bindings. Main route handler looks similar to the express one except that type checks on parameters performed based on type definition:

Load test

Testing performed on Ubuntu 18 Xeon E5–2660 with 40 cores . Database initialized with randomly generated 100_000 tasks assigned to 1000 workers.

Using wrk we are going to load server with a similar requests over a number of concurrent connections with predefined request. This should suit our case well as our server is not using cache for search.

We’ll need to run multiple tests with measurements of CPU, memory, latency and rps, so automation would pay off. Rust has a rich toolbox for writing CLI automation, including config , structopt and resources monitoring so it was quite easy to automate . Tests which will follow can be executed via:

cargo run --bin benchit --release -- -m -t 30

1. Fetch top 10 tasks

Search will return same first 10 records without “fat” description field, each row data is under 500b. It will be light for SQL server and should provide maximum requests per second. Test will be performed with the following command line under the hood:

wrk -c <concurrency> -d 30s "http://<host>:<port>/tasks"

For comparison of actix-web with nodeJS we will limit actix to 1 Core (e.g. 1 worker) initially, which will execute our web processing code. Deadpool will be configured with 15 connections and will handle database communication in parallel.

WORKERS=1 cargo run --release --bin actix-bench

Node.js executes JavaScript in a single thread and uses multiple threads for running asynchronous communication, we will configure knex to use 5..15 connections in the pool and this should match deadpool configuration:

cd node-bench; npm run start

ExpressJS vs. Actix-Web: performance and running cost comparison

ExpressJS vs. Actix-Web: performance and running cost comparison

Looking at the concurrency and rps even with a small load actix provides at least 2 times faster responses than node and under heavy load it is 6x faster. If we look at the database utilization actix seems performing 5 times more efficient. If we look at the response times, node.js for concurrency = 4 provides similar delay (~4ms) as actix with concurrency = 32 , which is 8 times better. From the memory footprint point of view it’s even better, on a long run with 1 million requests memory for actix service was around 26MB, while node.js grew up to 104MB, hello gc!

Conclusion: for loaded systems we will need 6 times less CPU Cores with actix than with node.js which is 85% cost saving.

Actix is super efficient when using multiple CPU Cores: fixed set of worker threads ( workers ) minimizes context switches. By default actix starts as many worker threads as there are CPU Cores.

Let’s see how well actix can scale on CPU with 4 workers and compare with 1 worker Actix setup:

WORKERS=4 PG_POOL_MAX_SIZE=30 cargo run --release --bin actix-bench

ExpressJS vs. Actix-Web: performance and running cost comparison

ExpressJS vs. Actix-Web: performance and running cost comparison

With 4 workers actix provides about 3 times better response time than actix with 1 worker on a heavy load, also providing 3 times more responses per second. Actix scales well on CPU, keeping memory consumption almost at the same level nevertheless of number of CPU’s occupied. Node can also scale on CPU running new process per CPU, which would duplicate memory usage for every new instance.

Actix can fully utilize cheap 2+ core cloud instances, while Node would require more expensive instances with more memory.

2. Search and fetch tasks with description

This search will return 10 matches by indexed varchar summary LIKE .. also fetching ~3–5kb TEXT description field. It definitely will put pressure on SQL server.

wrk -c <concurrency> -d 30s "http://<host>:<port>/tasks?summary=wherever&full=true&limit=10

Test will be heavy on DB hence we will run with 30 connections in the pool.

ExpressJS vs. Actix-Web: performance and running cost comparison

Quite a surprise! that Node.js is loading SQL server on a level similar to actix, while giving ~7 times worse performance. Probably has something to do with knex.js and the way how it handles prepared statements, though the goal of this post was to compare typical use. This leads to final summary

Actix-web and Rust ecosystem are a good fit for developing efficient web services, requiring ~6 times less CPU power and less memory it would allow significant 75%-95% runtime cost saving with just basic not optimized setup.

The goal of this post was to compare typical use and it does not account for deep fine tuning like node’s GC settings or using low level SQL libraries. There are opportunities to optimize Node.js solution and probably minimize the gap, though it will require significant effort from engineer and from other side same effort might be applied optimizing Rust solution too. Though in the next post I am going to use node-postgres and tokio-postgres directly and see if Node code can get closer to Actix-web.

Implementation notes

I have spent about same time on JavaScript and Rust implementations. With JavaScript most of the time was spent fixing issues in runtime, for instance there was race condition bug: I forgot that JavaScript const does not mean immutable and it appeared knex was mutating query object from all the concurrent requests:

const tasks = knex.from('tasks').innerJoin('workers as assignee', 'assignee.id', 'tasks.assignee_id' );

Code appeared to work nicely in local environment, though lead to huge SQL queries under the load. Debugging took some time but fix was simple .

I spent significantly less time fixing Rust part as it provided type safety warranties for request and response formats out of the box, types validation for database queries and concurrency safety.

It was quite a surprising that Rust and JavaScript code appeared to be of similar complexity, for instance below are implementations of main database handlers:

Rust implementation takes more space for types definition, though those also provide very useful checks in runtime. For instance GetTasksQuery type also validates that all supplied GET request query parameters are matching their required type and matching the type required by the database query. JavaScript route handler required 2 explicit checks in the code to provide such safety just in this case.

One more thing to note, Rust server handles data initialization as tokio-postgres supports PSQL COPY ... FROM BINARY statement, this allows to generate and load 100k records in 20 seconds. Texts are generated randomly with with markov chain built from the tale of the ring of Gyges which would emulate regular text load for search index.

P.S. Some generated descriptions are really funny, like this one

no man can be imagined to be a great proof that a man would ever submit to such an iron nature that he would be mad if he were no longer present

Thanks Darin https://github.com/dowwie/ , Michael https://github.com/bikeshedder and Andrey https://github.com/andre1sk for some advice on making this post cleaner and even.

If you have found any problem please feel free to drop comment or DM me on twitter or telegram @ dunnock.


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

精益思想

精益思想

(美)詹姆斯 P.沃麦克(James P.Womack)、(英)丹尼尔 T.琼斯(Daniel T.Jones) / 沈希瑾、张文杰、李京生 / 机械工业出版社 / 2011-4 / 48.00元

打算尝试精益的人,该怎么做? 已经实行精益的人,下一步怎么办? 本书包含了最新的精益理论、方法和工具,一一解答上述问题。 这是目前关于流程再造最好的书,也是最好读的。——《高业周刊》 本书中文简体字版由FreePress通过AiWA授权机械工业出版社在中国大陆独家出版发行。未经出版者书面许可,不得以任何方式抄袭、复制或节录本书中的任何部分。 《精益思想》于1996年秋......一起来看看 《精益思想》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具