loadbalance

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2023 License: MIT Imports: 10 Imported by: 1

README

Loadbalance

A Load Balance lib for Go.

Implement Faster Loadbalance Algorithm named DynamicWeighted

DynamicWeighted using two queues implements a concurrency safe , fast , dynamic weighted load-balance supported select, add and delete instance operation and these time complexity of operations all are O(1).The performance of this implementation is unrelated to the number of instance.

DynamicWeight Loadbalance

It has exactly the same effect as normal weighted load balancing, but it performs better and is independent of the number of instances

Here includes other loadbalance algorithm

  • Consistent Hash
  • Random
  • RoundRobin
  • WeightedRandom
  • WeightRoundRobin

How to use

package main

import (
	"fmt"
	"github.com/ydmxcz/loadbalance"
)

// define my instance struct and implement `Instance[string]`
type myService struct {
	Address         string
	Memory          int
}

func (ms *myService) InstanceID() string {
	return ms.Address
}

func (ms *myService) InstanceWeight() int {
	return ms.Memory
}

func main() {
	// define some service
	ins := []*myService{{
		Address: "192.168.0.90:9000",
		Memory:  5, // here memory as weight
	}, {
		Address: "192.168.0.90:9001",
		Memory:  3, // here memory as weight
	}, {
		Address: "192.168.0.90:9002",
		Memory:  2, // here memory as weight
	}}

	var selector loadbalance.Selector[string, *myService]

	// all methods is concurrncy safe and fast
	selector = loadbalance.NewWeightedDoubleQueue[string, *myService]()

	// add some instances 
	selector.Add(ins...)

	// select a instance
	_ = selector.Select()

	// delete a instances
	selector.Del(ins[2])

	// get a instance by its ID,the first result is instance,
	// second result is the instance wether exist
	_, exist := selector.Get("192.168.0.90:9002")

	size := selector.Size()

	// check all instance by for-each
	selector.ForEach(func(s string, ms *myService) bool {
		fmt.Println(ms)
		return true
	})
}


DynamicWeighted Loadbalance Parallel Benchmark Result

-3 indicate that there are 3 instances in Selector

-16384 indicate that there are 16384 instances in Selector

  • WeightDoubleQueue Benchmark Result
goos: linux
goarch: amd64
pkg: github.com/ydmxcz/loadbalance
cpu: Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz
=== RUN   Benchmark_DynamicWeighted_Parallel
Benchmark_DynamicWeighted_Parallel
=== RUN   Benchmark_DynamicWeighted_Parallel/DynamicWeighted_3_Instances
Benchmark_DynamicWeighted_Parallel/DynamicWeighted_3_Instances
Benchmark_DynamicWeighted_Parallel/DynamicWeighted_3_Instances-8
24744768                47.46 ns/op            0 B/op          0 allocs/op
=== RUN   Benchmark_DynamicWeighted_Parallel/DynamicWeighted_16384_Instances
Benchmark_DynamicWeighted_Parallel/DynamicWeighted_16384_Instances
Benchmark_DynamicWeighted_Parallel/DynamicWeighted_16384_Instances-8
23361574                50.54 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/ydmxcz/loadbalance   2.925s
  • Other Load-Balance Implementations benchmark results
goos: linux
goarch: amd64
pkg: github.com/ydmxcz/loadbalance
cpu: Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel
Benchmark_GetterLoadBalance_Get_Parallel
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel/Random_LoadBalance-3
Benchmark_GetterLoadBalance_Get_Parallel/Random_LoadBalance-3
Benchmark_GetterLoadBalance_Get_Parallel/Random_LoadBalance-3-8
20297527                56.63 ns/op            0 B/op          0 allocs/op
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel/Random_LoadBalance-16384
Benchmark_GetterLoadBalance_Get_Parallel/Random_LoadBalance-16384
Benchmark_GetterLoadBalance_Get_Parallel/Random_LoadBalance-16384-8
18015231                57.05 ns/op            0 B/op          0 allocs/op
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel/RoundRobin_LoadBalance-3
Benchmark_GetterLoadBalance_Get_Parallel/RoundRobin_LoadBalance-3
Benchmark_GetterLoadBalance_Get_Parallel/RoundRobin_LoadBalance-3-8
18871276                63.51 ns/op            0 B/op          0 allocs/op
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel/RoundRobin_LoadBalance-16384
Benchmark_GetterLoadBalance_Get_Parallel/RoundRobin_LoadBalance-16384
Benchmark_GetterLoadBalance_Get_Parallel/RoundRobin_LoadBalance-16384-8
19355181                62.16 ns/op            0 B/op          0 allocs/op
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel/WeightRoundRobin_3_Instances
Benchmark_GetterLoadBalance_Get_Parallel/WeightRoundRobin_3_Instances
Benchmark_GetterLoadBalance_Get_Parallel/WeightRoundRobin_3_Instances-8
22504696                52.33 ns/op            0 B/op          0 allocs/op
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel/WeightRoundRobin_16384_Instances
Benchmark_GetterLoadBalance_Get_Parallel/WeightRoundRobin_16384_Instances
Benchmark_GetterLoadBalance_Get_Parallel/WeightRoundRobin_16384_Instances-8
   33603             35602 ns/op               0 B/op          0 allocs/op
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel/WeightedRandom_LoadBalance-3
Benchmark_GetterLoadBalance_Get_Parallel/WeightedRandom_LoadBalance-3
Benchmark_GetterLoadBalance_Get_Parallel/WeightedRandom_LoadBalance-3-8
20667918                58.46 ns/op            0 B/op          0 allocs/op
=== RUN   Benchmark_GetterLoadBalance_Get_Parallel/WeightedRandom_LoadBalance-16384
Benchmark_GetterLoadBalance_Get_Parallel/WeightedRandom_LoadBalance-16384
Benchmark_GetterLoadBalance_Get_Parallel/WeightedRandom_LoadBalance-16384-8
  159358              7232 ns/op               0 B/op          0 allocs/op
PASS
ok      github.com/ydmxcz/loadbalance   11.602s

Documentation

Overview

Example
// define some service
ins := []*myService{{
	Address: "192.168.0.90:9000",
	Memory:  5, // here memory as weight
}, {
	Address: "192.168.0.90:9001",
	Memory:  3, // here memory as weight
}, {
	Address: "192.168.0.90:9002",
	Memory:  2, // here memory as weight
}}

var selector loadbalance.Selector[string, *myService]

// all methods is concurrncy safe and fast
selector = loadbalance.NewDynamicWeighted[string, *myService]()

// add some instances
selector.Add(ins...)

// select a instance
_ = selector.Select()

// delete a instances
selector.Del(ins[2])

// get a instance by its ID,the first result is instance,
// second result is the instance wether exist
_, _ = selector.Get("192.168.0.90:9002")

_ = selector.Size()

// check all instance by for-each
selector.ForEach(func(_ string, ms *myService) bool {
	fmt.Println(ms)
	return true
})
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetHashFunc

func GetHashFunc[T Hashable]() func(T) uint64

func Hash

func Hash[T Hashable](elem T) uint64

Types

type ConsistentHash

type ConsistentHash[T Hashable] struct {
	// contains filtered or unexported fields
}

func NewConsistentHash

func NewConsistentHash[T Hashable](replicas ...int) *ConsistentHash[T]

func (*ConsistentHash[T]) Add

func (c *ConsistentHash[T]) Add(instances ...Instance[T]) int

Add 方法用来添加缓存节点,参数为节点key,比如使用IP

func (*ConsistentHash[T]) Del

func (c *ConsistentHash[T]) Del(instances ...Instance[T]) int

func (*ConsistentHash[T]) ForEach

func (c *ConsistentHash[T]) ForEach(callback func(T, Instance[T]) bool)

func (*ConsistentHash[T]) Get

func (c *ConsistentHash[T]) Get(key T) (Instance[T], bool)

func (*ConsistentHash[T]) Select

func (c *ConsistentHash[T]) Select(key string) Instance[T]

Select 方法根据给定的对象获取最靠近它的那个节点

func (*ConsistentHash[T]) Size

func (c *ConsistentHash[T]) Size() int

type DynamicWeighted added in v0.0.2

type DynamicWeighted[T Hashable, I Instance[T]] struct {
	// contains filtered or unexported fields
}

DynamicWeighted uses two queue implements a concurrency safe , fast , dynamic weighted load-balance supported select, add and delete instance operation and these time complexity of operations all are O(1). The performance of this implementation is unrelated to the number of instance.

At first,define a struct named `instanceWrapper` which is includes two filed that one named `instance`(a type implements generic interface `Instance[T]`) and the other named `weight` (int).

Then the step of select algorithm as follows:

  1. pop node every time from this queue if the weight of current `instanceWrapper` is `minInt64` , indicate that the instance was flagged delete, re-pop a Wrapper and give the current `instanceWrapper` to gc.
  2. While the main queue is empty,swap the main queue and second queue.
  3. After popping `instanceWrapper` that it didn't flag deleted, then the weight of current `instanceWrapper` subtract one,
  4. if the weight is 0 , reset the weight by the method of instance named `InstanceWeight()` , and push to the second queue, otherwise push to the main queue. At last,get and return the instance from the current `instanceWrapper`.

some notes :

  1. type I better is a type that can be compared with `nil`, such as a pointer or an interface.
  2. this processing needs the protection of the mutex lock, After doing many implements includes using lock-free queue and atomic operations and doing more times test and benchmark,the performance of current way is the best.
  3. Maybe my implementation used lock-free queue has some problem, the result of implementation that used lock-free queue and atomic operation of benchmark test always about 180 ns/op.

func NewDynamicWeighted added in v0.0.4

func NewDynamicWeighted[T Hashable, I Instance[T]]() *DynamicWeighted[T, I]

func (*DynamicWeighted[T, I]) Add added in v0.0.2

func (sl *DynamicWeighted[T, I]) Add(instances ...I) int

Add some instances and return the number of successful operation

func (*DynamicWeighted[T, I]) Del added in v0.0.2

func (sl *DynamicWeighted[T, I]) Del(instances ...I) int

Del some instances and return the number of successful operation

func (*DynamicWeighted[T, I]) ForEach added in v0.0.2

func (sl *DynamicWeighted[T, I]) ForEach(callback func(T, I) bool)

ForEach every instances. it is concurrency safe.

func (*DynamicWeighted[T, I]) Get added in v0.0.2

func (sl *DynamicWeighted[T, I]) Get(key T) (ins I, ok bool)

Get the value corresponding to the key

func (*DynamicWeighted[T, I]) Select added in v0.0.2

func (sl *DynamicWeighted[T, I]) Select() (ins I)

Select a instance

func (*DynamicWeighted[T, I]) Size added in v0.0.2

func (sl *DynamicWeighted[T, I]) Size() int

type Hashable

type Hashable interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
		~float32 | ~float64 | ~complex64 | ~complex128 | ~string | ~unsafe.Pointer
}

type Instance

type Instance[T Hashable] interface {
	InstanceID() T
	InstanceWeight() int
}

type InstanceList

type InstanceList[T Hashable, I Instance[T]] []I

func (InstanceList[T, I]) Len

func (ig InstanceList[T, I]) Len() int

func (InstanceList[T, I]) Less

func (ig InstanceList[T, I]) Less(i, j int) bool

func (InstanceList[T, I]) Swap

func (ig InstanceList[T, I]) Swap(i, j int)

type Random

type Random[T Hashable, I Instance[T]] struct {
	// contains filtered or unexported fields
}

Random 随机负载均衡

func NewRandom

func NewRandom[T Hashable, I Instance[T]]() *Random[T, I]

func (*Random[T, I]) Add

func (rb *Random[T, I]) Add(instances ...I) int

func (*Random[T, I]) Del

func (rb *Random[T, I]) Del(instances ...I) int

func (*Random[T, I]) ForEach

func (rb *Random[T, I]) ForEach(callback func(T, I) bool)

func (*Random[T, I]) Get

func (rb *Random[T, I]) Get(key T) (I, bool)

func (*Random[T, I]) Select

func (rb *Random[T, I]) Select() (ins I)

func (*Random[T, I]) Size

func (rb *Random[T, I]) Size() int

type RoundRobin

type RoundRobin[T Hashable, I Instance[T]] struct {
	// contains filtered or unexported fields
}

轮询负载均衡

func NewRoundRobin

func NewRoundRobin[T Hashable, I Instance[T]]() *RoundRobin[T, I]

func (*RoundRobin[T, I]) Add

func (rr *RoundRobin[T, I]) Add(instances ...I) int

func (*RoundRobin[T, I]) Del

func (rr *RoundRobin[T, I]) Del(instances ...I) int

func (*RoundRobin[T, I]) ForEach

func (rr *RoundRobin[T, I]) ForEach(callback func(T, I) bool)

func (*RoundRobin[T, I]) Get

func (rr *RoundRobin[T, I]) Get(key T) (I, bool)

func (*RoundRobin[T, I]) Select

func (rr *RoundRobin[T, I]) Select() (ins I)

func (*RoundRobin[T, I]) Size

func (rr *RoundRobin[T, I]) Size() int

type Selector

type Selector[T Hashable, I Instance[T]] interface {
	Select() I
	// contains filtered or unexported methods
}

type SelectorBy

type SelectorBy[T Hashable, I Instance[T]] interface {
	SelectBy(string) I
	// contains filtered or unexported methods
}

type SourceAddressHash

type SourceAddressHash[T Hashable] struct {
	// contains filtered or unexported fields
}

func NewSourceAddressHash

func NewSourceAddressHash[T Hashable]() *SourceAddressHash[T]

func (*SourceAddressHash[T]) Add

func (kh *SourceAddressHash[T]) Add(instances ...Instance[T]) int

func (*SourceAddressHash[T]) Del

func (kh *SourceAddressHash[T]) Del(instances ...Instance[T]) int

func (*SourceAddressHash[T]) ForEach

func (kh *SourceAddressHash[T]) ForEach(callback func(T, Instance[T]) bool)

func (*SourceAddressHash[T]) Get

func (kh *SourceAddressHash[T]) Get(key T) (Instance[T], bool)

func (*SourceAddressHash[T]) SelectBy

func (kh *SourceAddressHash[T]) SelectBy(key string) Instance[T]

func (*SourceAddressHash[T]) Size

func (kh *SourceAddressHash[T]) Size() int

type WeightNode

type WeightNode[T Hashable, I Instance[T]] struct {
	Weight int //初始化时对节点约定的权重
	// contains filtered or unexported fields
}

type WeightedRandom

type WeightedRandom[T Hashable, I Instance[T]] struct {
	// contains filtered or unexported fields
}

func NewWeightedRandom

func NewWeightedRandom[T Hashable, I Instance[T]]() *WeightedRandom[T, I]

func (*WeightedRandom[T, I]) Add

func (wr *WeightedRandom[T, I]) Add(instances ...I) int

func (*WeightedRandom[T, I]) Del

func (wr *WeightedRandom[T, I]) Del(instances ...I) int

func (*WeightedRandom[T, I]) ForEach

func (wr *WeightedRandom[T, I]) ForEach(callback func(T, I) bool)

func (*WeightedRandom[T, I]) Get

func (wr *WeightedRandom[T, I]) Get(key T) (I, bool)

func (*WeightedRandom[T, I]) Select

func (wr *WeightedRandom[T, I]) Select() (ins I)

func (*WeightedRandom[T, I]) Size

func (wr *WeightedRandom[T, I]) Size() int

type WeightedRoundRobin

type WeightedRoundRobin[T Hashable, I Instance[T]] struct {
	// contains filtered or unexported fields
}

func NewWeightRoundRobin

func NewWeightRoundRobin[T Hashable, I Instance[T]]() *WeightedRoundRobin[T, I]

func (*WeightedRoundRobin[T, I]) Add

func (wrr *WeightedRoundRobin[T, I]) Add(instances ...I) int

func (*WeightedRoundRobin[T, I]) Del

func (wrr *WeightedRoundRobin[T, I]) Del(instances ...I) int

func (*WeightedRoundRobin[T, I]) ForEach

func (wrr *WeightedRoundRobin[T, I]) ForEach(callback func(T, I) bool)

func (*WeightedRoundRobin[T, I]) Get

func (wrr *WeightedRoundRobin[T, I]) Get(key T) (I, bool)

func (*WeightedRoundRobin[T, I]) Select

func (wrr *WeightedRoundRobin[T, I]) Select() (ins I)

func (*WeightedRoundRobin[T, I]) Size

func (wrr *WeightedRoundRobin[T, I]) Size() int

type XorShift64

type XorShift64 struct {
	// contains filtered or unexported fields
}

func NewXorShift64

func NewXorShift64(seed uint64) XorShift64

func (*XorShift64) Int31

func (xs *XorShift64) Int31() int32

func (*XorShift64) Int63

func (xs *XorShift64) Int63() int64

func (*XorShift64) Seed

func (xs *XorShift64) Seed(seed uint64)

func (*XorShift64) Uint64

func (xs *XorShift64) Uint64() uint64

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL