<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: GoChronicles</title>
    <description>The latest articles on DEV Community by GoChronicles (@gochronicles).</description>
    <link>https://dev.to/gochronicles</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4752%2Fd64f1dba-bde4-4713-943c-b33544594529.png</url>
      <title>DEV Community: GoChronicles</title>
      <link>https://dev.to/gochronicles</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gochronicles"/>
    <language>en</language>
    <item>
      <title>Bench-marking RESTful APIs | Part - II: On the Cloud</title>
      <dc:creator>Nikhil Akki</dc:creator>
      <pubDate>Sun, 26 Sep 2021 08:07:43 +0000</pubDate>
      <link>https://dev.to/gochronicles/bench-marking-restful-apis-part-ii-on-the-cloud-fd0</link>
      <guid>https://dev.to/gochronicles/bench-marking-restful-apis-part-ii-on-the-cloud-fd0</guid>
      <description>&lt;p&gt;Have you ever load tested your APIs on the cloud? In this post we explore how to load test and benchmark different RESTful framework's performance&lt;/p&gt;

&lt;h3&gt;
  
  
  Recap 🤠
&lt;/h3&gt;

&lt;p&gt;In our previous post, we did some benchmarks of frameworks from different languages. Our test hardware/server was my Raspberry Pi 3 Model B from 2016, it was a good experiment, but this time around we needed something more realistic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR - We used Kubernetes 😉 on Cloud (Google Cloud Platform) -&amp;gt; jump to benchmarks section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's get back to our story if are following the storyline from the first post 😄&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dave went back to his peers to show benchmark results that he had got in the initial tests which he ran on his Raspberry Pi 3, while some of his peers liked the idea and appreciated the outcome, some pointed out that they would need the test on real production-grade hardware to believe the results! Dave went back to his garage to tweak his test bench.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Intro
&lt;/h3&gt;

&lt;p&gt;Our setup is quite straightforward, each RESTful service gets the same amount of CPU and memory (enforced via k8s config). The entire setup takes few minutes to initialize, thanks to tools like gcloud CLI, Terraform &amp;amp; Pulumi. You can get it up and running with the environment without much hassle. And if you want to run the benchmark without fancy infra (i.e. without private VPC etc.). We recommend that you use the CLI wrapper as it is built over gcloud SDK and for the adventurous type, we have a slightly more elaborate setup with Terraform (GCP) &amp;amp; Pulumi (GCP &amp;amp; Digital Ocean).&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment Review
&lt;/h3&gt;

&lt;p&gt;Kubernetes is a planet scale tool that can orchestrate containerized applications and more.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Checkout our series on Kubernetes it is swell! 😃&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we didn't want to scale the application as load increases, we have put some limits. The config ensures that the deployments stay put and do not auto-scale in the K8s cluster. The whole point of this exercise is to simulate a prod environment (but without auto-scaling). We then load test and measure performance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quite the step up from the test on Raspberry Pi 3, isn't it? 😉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It took us a while to figure out the right configuration for the cluster so that you could replicate the tests on your own with the optimal amount of resources. The K8s environment can be setup on GCP free tier (at the time of writing this article)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Source code link for this entire project is given the references section! 😎&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Let's review our K8️⃣s Config file
&lt;/h3&gt;

&lt;p&gt;Deployment config looks like this - 👀&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rest-net-http-golang&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rest-net-http-golang&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rest-net-http-golang&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rest-net-http-golang&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/gochronicles/benchmark-rest-frameworks/rest-net-http-golang:latest&lt;/span&gt;
          &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IfNotPresent&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1Gi"&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500m"&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notice that we have allocated memory - 1Gi and CPU 500m or half vCPU. This constraint is given to all frameworks, this will ensure that the amount of compute given to each deployment is consistent.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rest-net-http-golang&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt; &lt;span class="c1"&gt;# provide public ip to the service&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rest-net-http-golang&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Service config exposes the RESTful apps in the cluster network via Public IP so that our bench-marking client can connect and run load simulations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Our attack tool for load testing🍾
&lt;/h3&gt;

&lt;p&gt;This time around, we decided to play around with different benchmark &amp;amp; load testing tools. Finally, we chose Hey.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hey is a drop-in replacement for ab tool (Apache benchmark).&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hey &lt;span class="nt"&gt;-c&lt;/span&gt; 800 &lt;span class="nt"&gt;-n&lt;/span&gt; 35000 &amp;lt;http://ip-addr-url/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will send 800 concurrent &amp;amp; total 35k requests to the RESTful API services on the K8s cluster.&lt;/p&gt;

&lt;h4&gt;
  
  
  Honorable mentions -
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Locust!&lt;/strong&gt; 🛩️-
This was the ideal tool for this test for couple of important reasons.
We could deploy this python based web app like load test tool on K8s cluster and run benchmarks from with in the cluster network (no need for public IP)
It comes with a nice UI dashboard to visualize the results.
The test results was same across frameworks, it looked like we couldn't schedule enough number of workers to really push the throttle on the RESTful APIs.
We had a limit on the number of processors we could deploy on our GCP instance (free tier has 8CPU limit for the entire project)
If you want to tinker with locust, here's the k8s config we created.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apache Benchmark&lt;/strong&gt; - 
Good old tool we could still probably use, but the results were better and faster with hey and it shares the almost similar CLI options.
CPU monitoring tool (htop) revealed that ab tool didn't take advantage of all the CPU cores, where as hey tool fired up on all CPU cores with same parameters out of the box.
Benchmarks 📈
The order of slowest to fastest framework is as expected in the benchmark results. Go frameworks are at a minimum 10x faster than Node &amp;amp; Python-based frameworks. However, the interesting bit is FastAPI (Python framework) isn't too far off from NestJS (which is about ~12% faster).&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;FastAPI (Python)&lt;/p&gt;

&lt;p&gt;NestJS (Node)&lt;/p&gt;

&lt;p&gt;ExpressJS (Node)&lt;/p&gt;

&lt;p&gt;Gin (Golang)&lt;/p&gt;

&lt;p&gt;Net-http (Go std libray)&lt;/p&gt;

&lt;p&gt;Fiber (Golang)&lt;/p&gt;

&lt;h3&gt;
  
  
  Close thoughts 🤔
&lt;/h3&gt;

&lt;p&gt;Results are as we anticipated - Go-based frameworks are at least 10x faster than Node &amp;amp; Python-based frameworks. One thing surprised us and possible areas for more research -&lt;/p&gt;

&lt;p&gt;In our local testing, Gin has always performed faster than Net/HTTP (Golang). However, in this test, it has scored lower. The source code for this service and the Kubernetes config can be found here and here respectively.&lt;/p&gt;

&lt;p&gt;Let us know in the comments if you found a better way to do these tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Your feedback 💁 and support🤝 means a lot, do share some love🥰 by sharing our posts on social media and subscribe to our newsletter! Until next time! 🎂😎&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;



&lt;p&gt;&lt;em&gt;This article was originally published on&lt;/em&gt; &lt;strong&gt;&lt;em&gt;GoChronicles.com&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;by the same author and has been repost with permission.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>kubernetes</category>
      <category>node</category>
      <category>benchmarks</category>
    </item>
    <item>
      <title>Bench-marking RESTful APIs</title>
      <dc:creator>Nikhil Akki</dc:creator>
      <pubDate>Sat, 25 Sep 2021 04:43:19 +0000</pubDate>
      <link>https://dev.to/gochronicles/bench-marking-restful-apis-16id</link>
      <guid>https://dev.to/gochronicles/bench-marking-restful-apis-16id</guid>
      <description>&lt;p&gt;Are your RESTful services ready to handle a surge in traffic? One way to find out....&lt;/p&gt;

&lt;p&gt;Do you know if your RESTful services will take the heat when your service/website gains multi-fold momentum in traffic?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dave works for an eCommerce start-up, one day, he was given a task to find out if the micro-services which he has been writing is scalable and optimized. The marketing team wants to run a big flash sale for a couple of days and expects a massive influx of online traffic to the website and the mobile app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2FTired-man-sleeping-on-laptop-keyboard-small.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2FTired-man-sleeping-on-laptop-keyboard-small.jpg" alt="Your friendly neighbourhood dev - Dave"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dave's task is to figure out how services like order, checkout and other product-related services would perform in such situations.&lt;br&gt;
In this article, we will load-test three REST API frameworks written in &lt;strong&gt;&lt;em&gt;&lt;a href="https://github.com/nikhilakki/benchmark-rest-frameworks/tree/main/rest-express-nodejs" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;&lt;a href="https://www.python.org/downloads/%20" rel="noopener noreferrer"&gt;Python&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; &amp;amp; &lt;strong&gt;&lt;em&gt;&lt;a href="https://golang.org/dl/" rel="noopener noreferrer"&gt;Golang&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; and, the benchmark will be using the Apache Benchmark tool.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The beauty of &lt;strong&gt;&lt;em&gt;&lt;a href="https://gochronicles.com/microservices/" rel="noopener noreferrer"&gt;micro-services&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; is that different teams could write services backed by business logic in whichever programming language &amp;amp; Eco-system conducive to their use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Our Rigg -
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Raspberry_Pi" rel="noopener noreferrer"&gt;Raspberry PI 3 Model B&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;1.2Ghz Quad-core Cortex A53&lt;/li&gt;
&lt;li&gt;whopping 1GB RAM&lt;/li&gt;
&lt;li&gt;16GB Class 10 SD Card.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Well, you could run this benchmark on any compatible system. Benchmarks make sense as long as you test them on the same hardware environment.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Environment -
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Server machine [mighty rpi3] -&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OS - &lt;a href="https://www.raspberrypi.org/software/operating-systems/#raspberry-pi-os-32-bit" rel="noopener noreferrer"&gt;Raspberry PI OS&lt;/a&gt; on armv7l&lt;/li&gt;
&lt;li&gt;Kernel - 5.10.52-v7+&lt;/li&gt;
&lt;li&gt;Application runtimes -

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.python.org/downloads/%20" rel="noopener noreferrer"&gt;Python 3.8.9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;Node v14.17.4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://golang.org/dl/" rel="noopener noreferrer"&gt;Go v1.16.6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Client machine [my laptop ;-)]-&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OS - &lt;a href="https://getfedora.org/" rel="noopener noreferrer"&gt;Fedora 34&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kernel - 5.13.5-200.fc34.x86_64&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amd.com/en/products/apu/amd-ryzen-5-5500u" rel="noopener noreferrer"&gt;Ryzen 5500U (6 Cores &amp;amp; 8 GB DDR4 3200 MHz RAM)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://httpd.apache.org/docs/2.4/programs/ab.html" rel="noopener noreferrer"&gt;Apache Benchmark tool (AB tool)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  And the test -
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ab &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 350 &lt;span class="nt"&gt;-n&lt;/span&gt; 5000 http://&amp;lt;rpi ip&amp;gt;:3000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command sends 5k requests in total with a concurrency of 350 requests. One could tweak these numbers as per requirements.&lt;/p&gt;

&lt;p&gt;The entire testing session ran for a few minutes and, we have the results in the below screenshots. We will start with FastAPI, followed by ExpressJS and then Fiber.&lt;/p&gt;

&lt;h3&gt;
  
  
  FastAPI (Sync) - Python
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffastapi-bench-sync.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffastapi-bench-sync.png" alt="FastAPI Sync"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FastAPI in synchronous mode clocks in at ~178 requests per second.&lt;/p&gt;

&lt;h3&gt;
  
  
  FastAPI (Async) - Python
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffastapi-bench-async.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffastapi-bench-async.png" alt="FastAPI Async"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FastAPI in asynchronous mode clocks in at ~228 requests per second. One important thing to point out, that we are running FastAPI's ASGI server (uvicorn) with default settings (1 worker). If we tweak the worker count to the number of available CPUs, there should be a significant jump in the performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Express JS (Sync) - NodeJS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Fexpress-bench-sync.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Fexpress-bench-sync.png" alt="ExpressJS Sync"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Express JS in the synchronous mode does 447 requests per second which are over ~2x jump from the FastAPI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Express JS (Async) - NodeJS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Fexpress-bench-async.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Fexpress-bench-async.png" alt="ExpressJS Async"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A similar trend is apparent in asynchronous mode, ~509 requests per second. Again, we must note that FastAPI and Express JS apps are running on one worker by default. In both frameworks, we see a single-core performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Now comes our star performer - Fiber (Golang)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Fiber - 5k requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffiber-bench.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffiber-bench.png" alt="fiber 5k req"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fiber takes less than a second to process 5k requests! Since Fiber framework is implemented in Golang, &lt;strong&gt;&lt;em&gt;&lt;a href="https://www.golangprograms.com/go-language/concurrency.html" rel="noopener noreferrer"&gt;concurrency is handled out of the box&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; which means there is no need to specify async await syntax in your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  CPU utilization by Fiber (Golang)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffiber-bench-500k-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffiber-bench-500k-.png" alt="htop fiber preview"&gt;&lt;/a&gt;&lt;br&gt;
Now, you may be wondering Golang is using all CPU cores, but FastAPI and ExpressJS are utilizing only one CPU core per instance. Let's see how they perform when running on all CPU cores.&lt;/p&gt;

&lt;h4&gt;
  
  
  FastAPI Async with 4 workers on 4 Cores
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffastapi-4-workers-async.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Ffastapi-4-workers-async.png" alt="fastapi async multicore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  ExpressJS Async with 4 workers on 4 Cores
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Fnodejs-4-workers.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2Fnodejs-4-workers.png" alt="expressjs async multicore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ExpressJS is 1.5x faster than FastAPI. However, Fiber is still ~7.5 and ~11 times faster than ExpressJS and FastAPI.&lt;/p&gt;

&lt;h3&gt;
  
  
  What do Sync and Async mean?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2F27265-small.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgochronicles.com%2Fcontent%2Fimages%2F2021%2F08%2F27265-small.jpg" alt="async image - traffic on the road"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dave is also a champion chess player and, he has been challenged to play chess with not one but ten different players all at once! He has essentially two approaches&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approach 1- Dave decides to play one player at a time&lt;/strong&gt;* and, if the average time per game is 10minutes (assuming other players are making quick decisions like our champ!), even then it takes 10 mins X 10 players = at least 100 minutes (i.e. over 1.6 hours)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approach 2 - Dave plays all players at once!&lt;/strong&gt; How is that possible? Every time an opponent takes time to think about their next move, Dave moves on to the next player and the next. It continues till the last move of the last remaining game.&lt;/p&gt;

&lt;p&gt;Now swap the crazy madness of a guy playing chess with multiple people with a &lt;a href="https://www.redhat.com/en/topics/api/what-is-a-rest-api" rel="noopener noreferrer"&gt;RESTful service&lt;/a&gt;. The opponents are external DB or service/APIs with which the RESTful service will communicate. Yes, that's how Sync &amp;amp; Async works and, since we are dealing with computers and not humans, they always perform actions as instructed!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Our thoughts -
&lt;/h3&gt;

&lt;p&gt;Well, it is going to be a long one and yet may not be complete. Let's get to it, shall we?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://docs.gofiber.io/" rel="noopener noreferrer"&gt;Fiber&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; (Golang) is way ahead of the game in terms of speed and raw performance. &lt;strong&gt;&lt;em&gt;&lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; (NodeJS) is ~1.5x faster than &lt;strong&gt;&lt;em&gt;&lt;a href="https://fastapi.tiangolo.com/features/" rel="noopener noreferrer"&gt;FastAPI&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; (Python) and, &lt;strong&gt;&lt;em&gt;these frameworks are ~7.5 and ~11.35 times slower than Fiber&lt;/em&gt;&lt;/strong&gt; (as per multi-core async performance).&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;&lt;em&gt;this doesn't mean that you no longer use Python or NodeJS based frameworks&lt;/em&gt;&lt;/strong&gt;. Factors like existing software stack, dev skills &amp;amp; experience in the team will play a significant role in making such decisions. &lt;strong&gt;&lt;em&gt;Remember, good Go devs are hard to find compared to Python &amp;amp; JavaScript devs&lt;/em&gt;&lt;/strong&gt; (at the time of writing this article) simply because these languages and their ecosystem have been here for longer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A few salient features FastAPI brings like Automatic data model documentation, JSON validations, serialization and more. One could achieve the same results in the other two frameworks by writing more code as they are minimalistic by design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We have used FastAPI extensively. Absolute performance becomes relevant when you are doing things at scale. &lt;strong&gt;&lt;em&gt;These benchmarks are solely in terms of raw speed/throughput and do not consider development speed, DB I/O operations, JSON serialization and de-serialization etc.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A general recommendation is that you choose FastAPI when working with AI/ML-based services or, your team knows Python well. And same goes for NodeJS based framework decisions. There is no silver bullet here!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are starting a new project and you are willing to give GoLang a try. Fiber is a great place to start and, &lt;strong&gt;&lt;em&gt;&lt;a href="https://github.com/avelino/awesome-go#web-frameworks" rel="noopener noreferrer"&gt;there are many frameworks to choose from&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We hope this gave you some perspective. Feel free to share comments and feedback. Let us know if we should do another post comparing full-feature frameworks from NodeJS &amp;amp; Golang eco-system such as &lt;strong&gt;&lt;em&gt;&lt;a href="https://docs.nestjs.com/first-steps" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; &amp;amp; &lt;strong&gt;&lt;em&gt;&lt;a href="https://gobuffalo.io/en/" rel="noopener noreferrer"&gt;Go-buffalo.&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Source code -
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/gochronicles/benchmark-rest-frameworks" rel="noopener noreferrer"&gt;GitHub - gochronicles/benchmark-rest-frameworks: Benchmarking RESTful APIs written in Python, NodeJS and Golang&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to follow further development on this project, make sure you give the repo a star! :-)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally posted on&lt;/em&gt; &lt;strong&gt;&lt;em&gt;&lt;a href="https://gochronicles.com/benchmark-restful-apis/" rel="noopener noreferrer"&gt;GoChronicles.com&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;by the same author and has been repost with permission.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For latest updates &amp;amp; posts, &lt;a href="https://gochronicles.com/membership/#/portal/signup/" rel="noopener noreferrer"&gt;please subscribe to GoChronicles&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>benchmarks</category>
      <category>python</category>
      <category>go</category>
      <category>node</category>
    </item>
  </channel>
</rss>
