You could try and check out hlts2/least-connections, a least-connections balancing algorithm written in golang.
Example:
lc, err := New([]*url.URL{
{Host: "192.168.33.10"},
{Host: "192.168.33.11"},
{Host: "192.168.33.12"},
})
src1, done1 := lc.Next() // {Host: "192.168.33.10"}
src2, done2 := lc.Next() // {Host: "192.168.33.11"}
done1() // Reduce connection of src1
src3, done3 := lc.Next() // {Host: "192.168.33.10"}
It does use a sync.Mutex
type leastConnections struct {
conns []conn
mu *sync.Mutex
}
Another more complex example: panjf2000/gnet presented in "Releasing a high-performance and lightweight event-loop networking library for Go", by Andy Pan.
gnet is an event-driven networking framework that is fast and lightweight.
Supporting multiple load-balancing algorithms: Round-Robin, Source Addr Hash and Least-Connections
Example
// start a server
// connect 10 clients
// each client will pipe random data for 1-3 seconds.
// the writes to the server will be random sizes. 0KB - 1MB.
// the server will echo back the data.
// waits for graceful connection closing.
t.Run("poll", func(t *testing.T) {
t.Run("tcp", func(t *testing.T) {
t.Run("1-loop", func(t *testing.T) {
testServe("tcp", ":9991", false, false, false, 10, RoundRobin)
})
t.Run("N-loop", func(t *testing.T) {
testServe("tcp", ":9992", false, true, false, 10, LeastConnections)
})
})
Again, the structure is straightforward:
// leastConnectionsEventLoopSet with Least-Connections algorithm.
leastConnectionsEventLoopSet struct {
sync.RWMutex
minHeap minEventLoopHeap
cachedRoot *eventloop
threshold int32
calibrateConnsThreshold int32
}