Skip to content

gptankit/harmonic

Repository files navigation

Harmonic Build Status GoDoc

Harmonic is the request dispatch algorithm powering ServiceQ (https://github.com/gptankit/serviceq). It is exposed in this repository as a package with enhanced support for initializing cluster state and error management.

Introduction

Assume a cluster of homogenous services that can serve user requests for a resource. One or more services might exhibit errors during their run ranging from connectivity loss, latency, misconfigurations and so on. Harmonic's role, in this scenario, is to select a service that has the best chance of processing an incoming request, thus improving the total probability of success for a group of requests.

How To Get

go get github.com/gptankit/harmonic

Then, import the module -

import "github.com/gptankit/harmonic"

How To Use

Harmonic works on user-supplied cluster state which includes a list of services (can be IP, fully-qualified URL or any unique identifier). By default, harmonic will zero the error count on each service and return a reference to cluster state, that can further be used to manage error counts.

// Initialize cluster state
serviceList := []string{"s0", "s1", "s2"}
cs, _ := harmonic.InitClusterState(serviceList)

// Call SelectService with retryIndex=0 and prevService=""
svc, _ := harmonic.SelectService(cs, 0, "")

The request can now be forwarded to the selected svc. Usually, the above call to SelectService should be enough to select a healthy service. If the request to svc succeedes, reset the error count -

// Reset error count for a service
cs.ResetError(svc)

As a good practice, it is advisable to do retries if the request to svc fails. The retry call to SelectService can be made after incrementing error count, incrementing retryIndex and passing previously selected svc -

// Increment error count for a service
cs.IncrementError(svc)
svc, _ := harmonic.SelectService(cs, 1, svc)

Note: What constitutes a success or failure response will depend on the type of application and use case, and needs to be defined accordingly by the application owner.

A complete example is added in sample folder.

Error Management

Listed are functions to manage error counts, and can be used depending on application needs -

func (cs *ClusterState) GetError(service string) (uint64, error)
func (cs *ClusterState) IncrementError(service string) error
func (cs *ClusterState) UpdateError(service string, errorcount uint64) error
func (cs *ClusterState) ResetError(service string) error
func (cs *ClusterState) ResetAllErrors() error

Benchmarks

Go bench results (env: linux/amd64)

Call to SelectService, first try -

Ops Time
2000 0.089s
20000 0.575s
200000 2.027s

Avg execution time: 8889 ns/op

Call to SelectService, retries -

Ops Time
5000 0.063s
50000 0.082s
500000 0.089s

Avg execution time: 32.4 ns/op

Feel free to play around and post feedbacks