• Stars
    star
    157
  • Rank 236,550 (Top 5 %)
  • Language
    Ruby
  • Created about 1 year ago
  • Updated 12 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Rinha Backend - API

This project was inspired by a community driven challenge that ran on August 2023:

Challenge INSTRUCTIONS:

Challenge STRESS TEST

Unfortunatelly I only heard about it a few days after it was closed, but I decided to try it out here.

The API itself is not the challenge, but to make it fit within the confines of a measle 1.5 vCPU and 3GB of RAM, and endure a very heavy, almost DDoS-like Gatling stress test. It's brutal test.

The goal of this version was to make a fully Rails API based app, with enough speed optimizations without completely breaking the framework. Some tricks are not recommended for real production usage, but it leverages the fact that this is a performance oriented challenge.

This version is OVERENGINEERED. I already missed the deadline anyway, so I went all in in experimentation. I implemented Rails.cache with Redis and async jobs with Sidekiq to queue up the inserts and another job to flush bulk inserts. You don't need it to peak in this stress test.

@lazaronixon did a much simpler and straight forward version that already maxes out the stress test insertion criteria. But this is for fun.

I did had a discovery: I spent hours testing this thinking that my version had some bug that was keeping it down, below 20k even. But turns out that this line in docker-compose.yml is not working properly and I have no idea why:

volumes:
  - ./postgresql.conf:/docker-entrypoint-initdb.d/postgresql.conf

In this config I had set a high max_connections, but the container was actually loading with just the default 100. That was the problem. You can check the database by connecting to it directly after loading docker compose up:

❯ docker-compose exec postgres psql -U postgres
    psql (15.4 (Debian 15.4-1.pgdg120+1))
    Type "help" for help.

    postgres=# SHOW max_connections;
    max_connections
    -----------------
    100
    (1 row)

To make sure it's actually increasing the max connections, I had to do:

command: postgres -c 'max_connections=450'

RESULTS

================================================================================
---- Global Information --------------------------------------------------------
> request count                                     108213 (OK=97044  KO=11169 )
> min response time                                      0 (OK=0      KO=3     )
> max response time                                  60001 (OK=60000  KO=60001 )
> mean response time                                  1855 (OK=1661   KO=3536  )
> std deviation                                       8622 (OK=7720   KO=14116 )
> response time 50th percentile                         25 (OK=90     KO=7     )
> response time 75th percentile                        602 (OK=684    KO=9     )
> response time 95th percentile                       1999 (OK=1980   KO=60000 )
> response time 99th percentile                      54713 (OK=52025  KO=60001 )
> mean requests/sec                                468.455 (OK=420.104 KO=48.351)
---- Response Time Distribution ------------------------------------------------
> t < 800 ms                                         76144 ( 70%)
> 800 ms <= t < 1200 ms                               9516 (  9%)
> t >= 1200 ms                                       11384 ( 11%)
> failed                                             11169 ( 10%)
---- Errors --------------------------------------------------------------------
> j.i.IOException: Premature close                                10512 (94.12%)
> Request timeout to localhost/127.0.0.1:9999 after 60000 ms        581 ( 5.20%)
> status.find.in(201,422,400), but actually found 502                51 ( 0.46%)
> status.find.in([200, 209], 304), found 502                         16 ( 0.14%)
> status.find.is(400), but actually found 502                         6 ( 0.05%)
> status.find.in(201,422,400), but actually found 504                 3 ( 0.03%)
================================================================================

It finished with almost 40K!! So this puts it near the top!!

graph 1

graph 2

HOW TO RUN

To run this application:

docker-compose up

Just for the first time run:

docker-compose exec api1 rails db:create
docker-compose exec api1 rails db:migrate

Application should respond at:

http://0.0.0.0:9999

Run stress test:

wget https://repo1.maven.org/maven2/io/gatling/highcharts/gatling-charts-highcharts-bundle/3.9.5/gatling-charts-highcharts-bundle-3.9.5-bundle.zip
unzip gatling-charts-highcharts-bundle-3.9.5-bundle.zip
sudo mv gatling-charts-highcharts-bundle-3.9.5-bundle /opt
sudo ln -s /opt/gatling-charts-highcharts-bundle-3.9.5-bundle /opt/gatling

cd ..
git clone https://github.com/zanfranceschi/rinha-de-backend-2023-q3.git
cd rinha-de-backend-2023-q3/stress-test

Edit the stress-test run-test.sh variables accordingly:

GATLING_BIN_DIR=/opt/gatling/bin

WORKSPACE=$HOME/Projects/rinha-de-backend-2023-q3/stress-test

Run the stress test:

./run-test.sh # after docker-compose up

On AWS EC2, create a t2.medium instance (2vCPUs 4GB RAM), download the .pem key:

chmod 400 yourkey.pem
ssh -i yourkey.pem -o IdentitiesOnly=yes [email protected]

SSH in:

# Install Docker
sudo amazon-linux-extras install docker
sudo service docker start
sudo usermod -a -G docker ec2-user

# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# install Git
sudo yum update -y
sudo yum install git -y
git clone https://github.com/akitaonrails/rinhabackend-rails-api.git

# run docker compose
cd rinhabackend-rails-api
docker-compose up --force-recreate -d

Don't forget to change run-test.sh and RinhaBackendSimulation.scala to add your own PATH and HOST name (in case you're running on AWS EC2). Also don't forget to edit docker-compose.yml to not build locally, but fetch the image from docker.io.

And in case you're wondering how a more "realistic" setup would look like, I created a "docker-compose-ideal.yml" that breaks the 1.5 vCPU and 3GB of RAM to a whopping 30 vCPUs and 22GB of RAM. If you have the horsepower for that, run:

docker-compose -f docker-compose-ideal.yml up --force-recreate --build

More Repositories

1

akitando_episode_0118

examples to illustrate my YouTube channel's episode 118 about Databases
JavaScript
235
star
2

computer_languages_genealogy_graphs

Graphviz/Dot files generator for computer languages genealogy
Ruby
192
star
3

webdevbox

The Best Web Development Environment in a (Distro)Box
Lua
168
star
4

chainable_methods

The most complete implementation of an Elixir/F#-like "Pipe" for Ruby in the form of "chainable methods"
Ruby
150
star
5

plex-docker-compose

docker compose to run the containers in my local plex server
114
star
6

manga-downloadr

download mangas from MangaReader.net and compile Kindle optimised PDFs
Ruby
88
star
7

plex_home_server_docker

Docker Compose scripts for a Plex Media Server with pull capabilities with Sonarr, Radarr, etc.
83
star
8

cramp_chat_demo

Bare bone chat demo using @lifo's Cramp
JavaScript
81
star
9

ex_manga_downloadr

Port of the Ruby version of Manga Downloadr to fetch mangas from MangaReader.net
Elixir
72
star
10

dynamic_liquid_templates

Manage your templates in your database instead of view files, and with Liquid templating support.
JavaScript
59
star
11

rinhabackend-lucky-crystal-api

Crystal
48
star
12

dotfiles

Chezmoi managed dotfiles
Lua
35
star
13

ObjC_Rubyfication

Attempt to make Objective-C more like Ruby
C
35
star
14

third_rails

A fresh Rails 3.0 app with generators, Rack::Bug with Orchestra and Thorfile examples.
Ruby
32
star
15

rubyconf2011

Site da RubyConf Brasil 2011
Ruby
30
star
16

ASP_Classic_WebForm

A very old (2001) experiment on implement a ASP.NET Web Forms-like framework in ASP Classic
ASP
27
star
17

slack_cleanup

Elixir based command line tool to delete all files from your Slack account
Elixir
24
star
18

locarails

Configuracao de Capistrano automatica para hospedagens Linux Locaweb
Ruby
24
star
19

lw-pagto-certo

Gem que se comunica com o serviço "Pagamento Certo" da Locaweb
Ruby
22
star
20

fiberpool

Simulate a queue and a pool of job workers, in essence a "Fiber Pool" for Crystal
Crystal
22
star
21

cr_manga_downloadr

Second version of the Ruby version of my MangaReader.net crawler adapted for Crystal
Crystal
16
star
22

episode0139

Example files described in the Episode 139, about Containers
JavaScript
15
star
23

ryanb-15min-blog

Ryan Bates' new 15 min blog demo available at the official Ruby on Rails website
Ruby
14
star
24

elo_demo

small demonstration of how using Elo rating makes a lot of difference in rankings
Ruby
13
star
25

ex_messenger_exercise

Original from Drew Kerrigan
Elixir
12
star
26

gamegenie

simple exercise to decode Game Genie codes into the proper addresses and values
Crystal
11
star
27

rinhabackend-python-fastapi

Python
11
star
28

mygist

Ruby Gem to interface with Gist + command line to use it interactively
Ruby
11
star
29

vagrant-railsbox

Rails development environment for Vagrant + Berkshelf
Ruby
10
star
30

i3-dotfiles

Arch + i3 + nvim
Vim Script
9
star
31

static_site_demo

Example Rails 4.2 app implementing a fast static site that rivals pure static generators
Ruby
9
star
32

rolling_with_rails_tutorial

Support material for the Rolling with Rails Tutorial
Ruby
8
star
33

image_uploader_demo

Simple Demonstration of how to add S3 Direct Upload with Carrierwave Backgrounder
Ruby
8
star
34

answers_demo

answers.37signals.com clone
Ruby
8
star
35

code42coin-exercise

Leartning from: https://blog.zeppelin.solutions/how-to-create-token-and-initial-coin-offering-contracts-using-truffle-openzeppelin-1b7a5dae99b6
JavaScript
7
star
36

rinhabackend-nim-jester-api

Nim
7
star
37

cr_chainable_methods

Attempt at a (limited) Pipe Operator for Crystal
Crystal
7
star
38

qmk_firmware

fork for my own keymaps
C
7
star
39

typeractive-corne-zmk-config

7
star
40

ASP-Classic-XML-NoSQL

This is an example of how I made AJAX and NoSQL before the terms were even created
ASP
6
star
41

ex_pusher_lite

Implementation of a Phoenix Channel based core for a Pusher replacement
Elixir
5
star
42

cr_subtitle_shift

Port of my Shift-Subtitle Ruby script to Crystal
Crystal
5
star
43

udev-usb-controller

Scripts to enable hotplugging usb joysticks into a running Virsh VM
Shell
4
star
44

depot

Sample application from "Agile Web Development with Rails."
Ruby
4
star
45

Shift-Subtitle

One example of solution for the Rubylearning Challenge #1
Ruby
4
star
46

rust_ruby_exercise_1

Simple Rust exercise to parse a file and be consumed through Ruby/FFI
Rust
4
star
47

jruby_calculator_demo

JRuby Swing Calculator demonstration
Java
4
star
48

RailsConf-2010---Restfulie

Basic demonstration for the RailsConf 2010 talk about RESTful and Restfulie
Ruby
4
star
49

reveal.js-for-developers

Customization over vanilla Reveal.js to make it suitable for Software Developers
JavaScript
4
star
50

elixir-koans-results

Elixir
4
star
51

CoffeeScript-Demonstration

Small demonstration of coffeescript with jQuery UI in a Rails app
Ruby
4
star
52

TinyClone

Rails 3 version of the original Sinatra-based TinyClone
Ruby
4
star
53

wiki_exercicio

Pequeno exercício de Ruby on Rails - não é uma aplicação completa
Ruby
3
star
54

pusher_lite_demo

Basic Rails app to showcase the difference between using Pusher and a Phoenix-based replacement
Ruby
3
star
55

learn_to_program_pt_br

the original source for http://aprendaaprogramar.rubyonrails.pro.br/
Ruby
3
star
56

twitter_dumper

Ruby
3
star
57

screencast_demo

Projeto de demonstração para o Screencast do Git
Ruby
3
star
58

locosxrails_i18n_demo

Demonstration I18n App for Locos x Rails conference
Ruby
2
star
59

demo_responds_to_parent

Exercise With Responds To Parent
JavaScript
2
star
60

gem_exemplo

Gem de exemplo.
2
star
61

ObjC_XmlBuilder

Experimental clone of Ruby's Builder::XmlMarkup
Objective-C
2
star
62

restfulie-full-examples

Full examples on how to use restfulie
Ruby
2
star
63

enki-translator

Importers for enki from other blog engines
2
star
64

ObjC_OnigurumaDemo

Small app to demonstrate integration with ObjC_Rubyfication, particularly using Oniguruma
C
2
star
65

cr_slack_cleanup

Crystal version for my Elixir-based Slack clean up tool
Crystal
1
star
66

pxblog_phoenix_exercise

Elixir
1
star
67

fisl_10_demo

Demonstração da minha palestra no FISL 10 de 2009
Ruby
1
star