Skip to content

Commit

Permalink
merge: branch performance experiments
Browse files Browse the repository at this point in the history
  • Loading branch information
jnsgruk committed Dec 2, 2024
2 parents c2d1424 + a1f71aa commit bf41552
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ Over the past couple of weeks, I've been teaching myself [Rust](https://www.rust

The Rust language also encourages the ideas of safety and soundness - sound code is (approximately) code that can't cause memory corruption or exhibit undefined behaviour. You can read more in this excellent post [Safety and Soundness in Rust](https://jacko.io/safety_and_soundness.html).

This blog post started out life as a post about Rust and my experience learning it, but I got interested in the performance of the server implementation I came up with and the post evolved into a post more about profiling and load testing!

## Learning Rust

It's been a little while since I dug into a new programming language, so I thought I'd mention how I went about it. In general I'm someone who learns best "by doing". I normally try to read through some of the basic concepts, then jump to a project that will enable me to exercise them quite quickly. Fortunately, Rust has an _excellent_ official guide in the form of the [Rust Book](https://doc.rust-lang.org/book/), which covers everything from the obligatory `Hello, World!`, to concurrency, memory safety, publishing packages on [crates.io](https://crates.io) and more. I thoroughly recommend it.

I've also picked up a copy of [Rust for Rustaceans](https://rust-for-rustaceans.com/) which was recommended by a couple of different colleagues - I intend to work through this next.
Expand Down Expand Up @@ -64,7 +68,10 @@ I've been looking for an excuse to play with [k6](https://k6.io/) for a while. A
In very simple terms, to use `k6` you define a script (in Javascript) that outlines a set of requests to make, their success criteria and (optionally) the strategy for ramping up load on the server. It has _many_ more features than I used for this project, but I was impressed with how simple it was to get started. I began by running the following (grabbing `k6` from `nixpkgs`):

```shell
❯ nix run github:NixOS/nixpkgs/nixos-unstable#k6 -- new
# Start a shell with k6 available
❯ nix shell github:NixOS/nixpkgs/nixos-unstable#k6
# Init a new k6 script
❯ k6 new
Initialized a new k6 test script in script.js. You can now execute it by running `k6 run script.js`.
```

Expand All @@ -88,16 +95,19 @@ VUs are an emulation of a user interacting with your service; each of them is an
I wanted to test a variety of requests, so I first generated a list of valid URLs for my server. I used [`cariddi`](https://github.com/edoardottt/cariddi) which is a web crawler written in Go, combined with `jq` to create a list of valid paths in a JSON file:

```shell
echo http://localhost:8080 \
| nix run github:NixOS/nixpkgs/nixos-unstable#cariddi -- -plain \
# Start a shell with k6 available
❯ nix shell github:NixOS/nixpkgs/nixos-unstable#cariddi
# Run cariddi and generate the paths.json
echo http://localhost:8080 \
| cariddi -- -plain \
| cut -d"/" -f4- \
| jq -r -nR '[inputs | select(length>0)]' > paths.json
```

Similarly I generated a list of valid redirects:

```shell
curl -s "https://gist.githubusercontent.com/jnsgruk/b590f114af1b041eeeab3e7f6e9851b7/raw" \
curl -s "https://gist.githubusercontent.com/jnsgruk/b590f114af1b041eeeab3e7f6e9851b7/raw" \
| cut -d" " -f1 \
| jq -r -nR '[inputs | select(length>0)]' > redirects.json
```
Expand Down Expand Up @@ -138,7 +148,7 @@ You can see my final test script [on Github](https://github.com/jnsgruk/server-b
Finally, I ran `k6` and let it rip! This initial run was against `servy`, running on my workstation:

```shell
nix run github:NixOS/nixpkgs/nixos-unstable#k6 -- run script.js
k6 run script.js

/\ Grafana /‾‾/
/\ / \ |\ __ / /
Expand Down Expand Up @@ -317,14 +327,16 @@ info "Results available in summary-${1}.txt, summary-${1}.json and summary-${1}.
This was the final piece of the puzzle for now; after building [and packaging](https://github.com/jnsgruk/server-bench/blob/6db6c179649f44bb2f0fcc6a2441d8fc38b24f03/flake.nix#L60-L67) this script and [defining the test VM as a package](https://github.com/jnsgruk/server-bench/blob/6db6c179649f44bb2f0fcc6a2441d8fc38b24f03/flake.nix#L50) in the flake, I'd enabled the following workflow:
```shell
# Start the devShell for the server-bench project
❯ nix develop github:jnsgruk/server-bench
# Build & run the VM
nix run .#benchvm -- --daemonize --display none
❯ run-benchvm-vm --daemonize --display none
# Start, and load test the gosherve based server
nix run .#benchvm-test -- jnsgruk-go
❯ benchvm-test jnsgruk-go
# Start, and load test the Rust based server
nix run .#benchvm-test -- jnsgruk-rust
❯ benchvm-test jnsgruk-rust
# All done, power down the VM
nix run .#benchvm-exec -- poweroff
❯ benchvm-exec poweroff
```
Excellent! Now on to some actual testing!
Expand Down Expand Up @@ -515,10 +527,13 @@ If you do play with the profile on `pprof.me`, try filtering by function name an
[![filtering by function name on pprof.me](06.png)](06.png)
By the time you read this, the [`parca-agent` should be upstream](https://github.com/NixOS/nixpkgs/pull/360132) into `nixpkgs`, so you can do something like this:
By the time you read this, the [`parca-agent` should be upstream](https://github.com/NixOS/nixpkgs/pull/360132) into `nixpkgs`, but in the mean time you can pull the package I included in the `server-bench` repo and use that:
```shell
❯ sudo nix run github:NixOS/nixpkgs/nixos-unstable#parca-agent -- \
# Start the devShell for the server-bench project
❯ nix develop github:jnsgruk/server-bench
# Start the agent
❯ sudo parca-agent -- \
--remote-store-address="grpc.polarsignals.com:443" \
--remote-store-bearer-token="$TOKEN" \
--node="$HOSTNAME"
Expand Down Expand Up @@ -760,17 +775,16 @@ I also added a [new flake input](https://github.com/jnsgruk/server-bench/blob/6d
As such, if you want to try reproducing any of these results and measure old vs. new vs. `servy`, you just need to do the following:
```shell
# Start the devShell for the server-bench project
❯ nix develop github:jnsgruk/server-bench
# Build & run the VM
❯ nix run github:jnsgruk/server-bench#benchvm -- --daemonize --display none
❯ run-benchvm-vm --daemonize --display none
# Edit the core/memory count as required
❯ vim vm.nix
# Start, and load test a server, choosing your variety
❯ nix run github:jnsgruk/server-bench#benchvm-test -- <jnsgruk-go-old|jnsgruk-go|jnsgruk-rust>
❯ benchvm-test <jnsgruk-go-old|jnsgruk-go|jnsgruk-rust>
# Power down the VM
nix run github:jnsgruk/server-bench#benchvm-exec -- poweroff
❯ benchvm-exec poweroff
```
The results will be gathered in a collection of `summary-*.<txt|html|json>` files for you to inspect.
Expand Down

0 comments on commit bf41552

Please sign in to comment.