Skip to content

Instantly share code, notes, and snippets.

@druminski
Last active July 4, 2022 01:11
Show Gist options
  • Save druminski/1e59a70cf70dab1061c75e26b3d0e321 to your computer and use it in GitHub Desktop.
Save druminski/1e59a70cf70dab1061c75e26b3d0e321 to your computer and use it in GitHub Desktop.
BigCache service example with external benchmarks

Cache service example. It uses fasthttp as an http server and bigcache as the cache.

External benchmarks are provided.

Running cache service

go run main.go

Server listens on 8080 port.

API

To cache an entry PUT /cache/{key} request with value in body needs to be send. To read it, GET /cache/{key}.

External benchmarks

Wrk2 is used here as benchmark tool. Therefore it needs to be installed in the first place. After it's done, below tests can be run.

Running writes test

./wrk -t1 -c100 -d10m -R5000 --latency -s putEntries.lua  http://localhost:8080

Test configuration can be adjusted.

Running reads test

./wrk -t1 -c100 -d10m -R5000 --latency -s getRandomEntries.lua http://localhost:8080

Test configuration can be adjusted.

Gathering results

Results with latency distribution can be visualized on this site

local maxCounterValue = 5000 * 60 * 10 -- rps * seconds * minutes, after what value counter should be reset
--[[
This script generates GET requests with random resource id.
Resource id generation is based on counter. When it reaches its configured limit then it is reset to 0 value.
--]]
wrk.method = "GET"
math.randomseed(os.time())
math.random(); math.random(); math.random()
local counter = 0
local maxCounterValue = 5000 * 60 * 10 -- rps * seconds * minutes, after what value counter should be reset
local pathTemplate = "/cache/%09d"
request = function()
counter = counter + 1
if counter == maxCounterValue then counter = 0 end
path = string.format(pathTemplate, math.random(counter))
return wrk.format(wrk.method, path, wrk.headers, wrk.body)
end
package main
import (
"github.com/allegro/bigcache"
"github.com/valyala/fasthttp"
"log"
"time"
"strings"
)
const pathPrefix = "/cache/"
var cache, cacheInitError = bigcache.NewBigCache(bigcache.Config{
Shards: 256, // number of shards (must be a power of 2)
LifeWindow: 10 * time.Minute, // time after which entry can be evicted
MaxEntriesInWindow: 10000 * 10 * 60, // rps * lifeWindow
MaxEntrySize: 1024, // max entry size in bytes, used only in initial memory allocation
Verbose: true, // prints information about additional memory allocation
})
func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
path := string(ctx.Path())
method := string(ctx.Method())
key := path[len(pathPrefix):]
if (method == "GET" && strings.HasPrefix(path, pathPrefix)) {
if value, err := cache.Get(key); err == nil {
ctx.SetStatusCode(fasthttp.StatusOK)
ctx.SetBody(value)
} else {
ctx.Error(err.Error(), fasthttp.StatusNotFound)
}
} else if (method == "PUT" && strings.HasPrefix(path, pathPrefix)) {
cache.Set(key, ctx.Request.Body())
ctx.SetStatusCode(fasthttp.StatusOK)
} else {
ctx.Error("Invalid path or method. Use GET or PUT with path: " + pathPrefix, fasthttp.StatusNotFound)
}
}
func main() {
if (cacheInitError != nil) {
log.Fatal(cacheInitError.Error())
}
log.Fatal(fasthttp.ListenAndServe(":8080", fastHTTPHandler))
}
--[[
This script generates PUT requests with resource id incremented in every request.
Incrementation is based on counter. When counter reaches its configured limit then it is reset to 0 value.
The script was written in that way to allow run at the same time GET requests by another script.
--]]
wrk.method = "PUT"
local counter = 0
local maxCounterValue = 5000 * 60 * 10 -- rps * seconds * minutes, after what value counter should be reset
pathTemplate = "/cache/%09d"
entryTemplate = [[{
"id": "%i"
"name": "Helen Tran",
"gender": "female",
"about": "Eu esse commodo ipsum qui eu in pariatur consectetur exercitation nisi quis ut magna cupidatat. Dolor et magna officia incididunt cillum. Veniam laboris nisi dolor sunt id fugiat consectetur nostrud incididunt ipsum Lorem reprehenderit pariatur eiusmod.",
"generated": "2015-06-06T09:35:40 -02:00",
"latitude": -31.283821,
"longitude": 29.399596
}]]
request = function()
counter = counter + 1
if counter == maxCounterValue then counter = 0 end
body = string.format(entryTemplate, counter)
path = string.format(pathTemplate, counter)
return wrk.format(wrk.method, path, wrk.headers, body)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment