Go Application

infiniSoft Blog > Blog > Solution > Go Application

Let’s initiate module for our future code:

go mod init infinisoft/dispatcher-go

Now we’ll add main.go file that implements logic of the dispatcher:

package main

import (
	"net/http"
	"sync"

	"github.com/gin-gonic/gin"
	hash "github.com/theTardigrade/golang-hash"
)

type name struct {
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
}

var NameStorage = map[uint64]name{}

var mutex = &sync.Mutex{}

func nameToHash(n name) uint64 {
	return hash.Uint64String(n.FirstName) ^ hash.Uint64String(n.LastName)
}

func postNames(c *gin.Context) {
	var Names []name
	var resp = map[uint64]name{}
	var temp = map[uint64]name{}

	if err := c.BindJSON(&Names); err != nil {
		return
	}

	mutex.Lock()
	for _, element := range Names {
		if _, ok := NameStorage[nameToHash(element)]; ok {
			resp[nameToHash(element)] = element
		} else {
			temp[nameToHash(element)] = element
		}
	}

	for index, element := range temp {
		NameStorage[index] = element
	}
	mutex.Unlock()

	respSlice := make([]name, 0, len(resp))

	for _, value := range resp {
		respSlice = append(respSlice, value)
	}

	c.IndentedJSON(http.StatusOK, respSlice)
}

func deleteNames(c *gin.Context) {
	var Names []name

	if err := c.BindJSON(&Names); err != nil {
		return
	}

	mutex.Lock()
	for _, element := range Names {
		delete(NameStorage, nameToHash(element))
	}
	mutex.Unlock()
}

func main() {
	router := gin.Default()
	router.POST("/names", postNames)
	router.DELETE("/names", deleteNames)

	router.Run(":9000")
}

Running application as go run . with further tests in Postman confirms that the logic works similar to what we recently implemented in Java, JavaScript and C#. Note that server runs on port 9000:

Repeat request to see exclusion:

And cleanup:

It’s time to dockerize application – add the following Dockerfile:

## Build
FROM golang:1.16-buster AS build

WORKDIR /app

COPY go.mod ./
COPY go.sum ./
RUN go mod download

COPY *.go ./

RUN go build -o /go-docker

## Deploy
FROM gcr.io/distroless/base-debian10

WORKDIR /

COPY --from=build /go-docker /go-docker

EXPOSE 9000

USER nonroot:nonroot

ENTRYPOINT ["/go-docker"]

Build image as:

docker build . -t infinisoft/dispatcher-go

As before, take a note that image size is just 29.8MB – so far the smallest.

Run application in Docker as docker run -p 9000:9000 -d infinisoft/dispatcher-go and note initial memory consumption: 9.262MiB.

Next let’s run updated JMeter scenario (attached) to populate and clean up dispatcher cache. As before, we’ll run 100 threads in 100 cycles with 1 second ramp-up period.

On completion in 8 seconds (AMD FX-8320 with 16GB RAM) the Apache JMeter shows:

During test we’ll notice that application uses only single CPU core, 19.5-18.45MiB of RAM.

Thus solution for Dispatcher application on Go has smallest footprint and in the same time it is fastest among solutions we discussed before:

LanguageCompiled application, MbDocker Image, MbMemory Consumption, MbThroughput, requests/sec
Java16.8320273.5-439.41541.2
C#2.5*20828.4-126.72506.5
JavaScript91913.29-85.73842.3
Go10.829.89.262-19.53686

* Folder size with executable application and required assemblies

Leave a Reply

Your email address will not be published. Required fields are marked *

About This Site

This may be a good place to introduce yourself and your site or include some credits.

Recent Comments

    Archives

    Find Us

    Mailing Address
    1703 Evans Rd 9108
    San Antonio, TX 78258

    Hours
    Monday–Friday: 9:00AM–5:00PM
    Saturday & Sunday: 11:00AM–3:00PM