- read

Go vs. Rust Load Testing Using Grafana K6

Ruangyot Nanchiang 47

Hi to every Rust and Go fanboy. I was so curious and restless about which one is faster Rust or Go for the backend services.

Then, I just get up from the bed and do a load testing for them. Okay, let’s do the testing by defining all conditions first.

Note that: If I was wrong or missing something, Please tell me. For the reasons of my first time doing the load testing.

Conditions

I need to write an API services application that contains just one endpoint for each lang. Thus I just need to create an API to respond “Hello, 世界!” as a stupid text response. (世界 means world in Japanese.)

Next, I need to pack all applications into the Docker container and deploy them up to the GCP (Google Cloud Platform) using the compute engine.

The spec of the compute engine in summary are

  • CPU -> E2-micro 2 vCPU 1 core
  • RAM -> 1 GB
  • Disk/Storage -> Balanced persistent disk

Dockerfile is going to be a multistage building and based on Bullseye Debian.

The requests are going to be done by Grafana K6 + Docker. For each round of load testing must be 250, 500, and 1000 virtual users and the duration of the request is 30 seconds constant.

The number of virtual users is related to the number of the request. Thus max requests are 250, 500, and 1000 requests for each round of load testing. respectively.

Golang Coding and Dockerfile

I use Echo to do an API services application by following of this code section below.

API code

package main

import (
"net/http"

"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)

func main() {
e := echo.New()

e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
Skipper: middleware.DefaultSkipper,
AllowOrigins: []string{"*"},
AllowMethods: []string{http.MethodGet},
}))

e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, 世界!")
})
e.Logger.Fatal(e.Start(":3000"))
}

Dockerfile

FROM golang:1.21-bullseye AS build

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
RUN CGO_ENABLED=0 go build -o /bin/app

FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y ca-certificates
COPY --from=build /bin/app /bin

CMD ["/bin/app"]

Rust Coding and Dockerfile

In Rust’s API services, I use Axum to build by the following code.

use axum::{
routing::get,
Router, http::Method,
};
use tower_http::cors::{CorsLayer, Any};

#[tokio::main]
async fn main() {
let cors = CorsLayer::new()
.allow_methods([Method::GET])
.allow_origin(Any);

// build our application with a single route
let app = Router::new()
.layer(cors)
.route("/", get(|| async { "Hello, 世界!" }));

// run it with hyper on localhost:3000
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}

Dockerfile

FROM rust:1.71-bullseye as builder

WORKDIR /usr/src/myapp
COPY . .
RUN cargo install --path .

FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/local/cargo/bin/rust-helloworld /usr/local/bin/rust-helloworld
CMD ["rust-helloworld"]

Then, deploy them up to the compute engine and configure the Firewall to allow TCP access within the port you want.

Set up the test script.js

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
vus: 250 // Don't forget to change this value for each round of testing,
duration: '30s',
};

export default function () {
const res = http.get('http://0.0.0.0:3000/');
check(res, { 'status was 200': (r) => r.status == 200 });
sleep(1);
}

Let’s run the test.

docker run --rm -i grafana/k6 run - <script.js

And see the result.

Result

Rust 250, 500, 1000 vus

#250 vus
data_received..................: 923 kB 30 kB/s
data_sent......................: 585 kB 19 kB/s
http_req_blocked...............: avg=9.88ms min=1µs med=3.7µs max=499.89ms p(90)=11µs p(95)=22.17µs
http_req_duration..............: avg=71.55ms min=33.49ms med=44.51ms max=499.03ms p(90)=116.33ms p(95)=206.49ms
vus............................: min=64 max=250

#500 vus
data_received..................: 1.8 MB 59 kB/s
data_sent......................: 1.2 MB 38 kB/s
http_req_blocked...............: avg=8.56ms min=1.1µs med=3.6µs max=449.49ms p(90)=6.1µs p(95)=15.09µs
http_req_duration..............: avg=74.73ms min=32.57ms med=41.99ms max=509.74ms p(90)=186.39ms p(95)=281.23ms
vus............................: min=66 max=500

#1000 vus
data_received..................: 2.0 MB 65 kB/s
data_sent......................: 1.3 MB 41 kB/s
http_req_blocked...............: avg=89.68ms min=1.2µs med=3.7µs max=15.35s p(90)=7µs p(95)=476.18ms
http_req_duration..............: avg=883.84ms min=34.22ms med=1.07s max=1.81s p(90)=1.39s p(95)=1.48s
vus............................: min=95 max=1000

Go 250, 500, 1000 vus

#250 vus
data_received..................: 977 kB 32 kB/s
data_sent......................: 566 kB 18 kB/s
http_req_blocked...............: avg=5.49ms min=1.4µs med=4.2µs max=259.29ms p(90)=7µs p(95)=22.3µs
http_req_duration..............: avg=121.09ms min=33.04ms med=50.11ms max=689.9ms p(90)=329.37ms p(95)=458.56ms
vus............................: min=250 max=250

#500 vus
data_received..................: 1.7 MB 55 kB/s
data_sent......................: 1000 kB 32 kB/s
http_req_blocked...............: avg=20.6ms min=1µs med=3.8µs max=964.68ms p(90)=6.4µs p(95)=25.63µs
http_req_duration..............: avg=275.63ms min=33.71ms med=170.2ms max=1.05s p(90)=678.4ms p(95)=830.93ms
vus............................: min=307 max=500

#1000 vus
data_received..................: 2.3 MB 72 kB/s
data_sent......................: 1.3 MB 42 kB/s
http_req_blocked...............: avg=59.23ms min=1.1µs med=3.6µs max=1.8s p(90)=6.6µs p(95)=326.87ms
http_req_duration..............: avg=935.49ms min=33.05ms med=1.04s max=1.8s p(90)=1.22s p(95)=1.39s
vus............................: min=348 max=1000

Summary

If we take http duration of each test to plot into the graph.

Rust faster than Go by the calculation below

  • Rust Http Duration Average = 343.37 ms
  • Go Http Duration Average = 444.07 ms

Rust is faster than go by 33 % for avg of 250, 500 and 100 vus