Middle
/* Postoji aplikacija s arhitekturom mikroservisa. Mikroservis se može apstrahirati pomoću sučelja Backend. Za pristup primjerku mikroservisa, možete koristiti tip BackendImpl, koji je već implementiran. Svaki mikroservis ima nekoliko desetaka pokrenutih primjeraka, od kojih je svaki dostupan putem svoje adrese addr. Međutim, pojedinačni primjerci mikroservisa nisu pouzdani: the mogu pasti, biti nedostupni ili preopterećeni. Stoga morate implementirati tip Balancer, koji također implementira sučelje Backend i vrši balansiranje opterećenja na strani klijenta između primjeraka mikroservisa, birajući svaki put **najmanje opterećen** primjerak. */ type Request interface{} type Response interface{} type Backend interface { Invoke(ctx context.Context, req Request) (Response, error) } var _ Backend = &BackendImpl{} // addr sadrži ip:port određenog primjerka func NewBackend(addr string) *BackendImpl type Balancer struct { // TODO } var _ Backend = &Balancer{} // addrs sadrže adrese svih uravnoteženih primjeraka func NewBalancer(addrs []string) *Balancer { // TODO }
sobes.tech АИ
Одговор од АИ
Для реализации Balancer, который выбирает наименее нагруженный экземпляр микросервиса, нужно хранить состояние нагрузки каждого экземпляра и при вызове Invoke выбирать тот, у которого нагрузка минимальна.
Примерный подход:
- В
Balancerхранить срез экземпляровBackendImplи счётчики текущих запросов (нагрузки) для каждого. - При вызове
Invokeвыбрать экземпляр с минимальной нагрузкой. - Увеличить счётчик нагрузки перед вызовом, уменьшить после завершения (в defer).
Пример кода:
import (
"context"
"sync"
)
type Balancer struct {
backends []*BackendImpl
mu sync.Mutex
loads []int // количество текущих запросов на каждый backend
}
func NewBalancer(addrs []string) *Balancer {
b := &Balancer{
backends: make([]*BackendImpl, len(addrs)),
loads: make([]int, len(addrs)),
}
for i, addr := range addrs {
b.backends[i] = NewBackend(addr)
}
return b
}
func (b *Balancer) Invoke(ctx context.Context, req Request) (Response, error) {
b.mu.Lock()
// Найти индекс с минимальной нагрузкой
minIdx := 0
minLoad := b.loads[0]
for i, load := range b.loads {
if load < minLoad {
minLoad = load
minIdx = i
}
}
b.loads[minIdx]++
b.mu.Unlock()
// Вызов backend
resp, err := b.backends[minIdx].Invoke(ctx, req)
b.mu.Lock()
b.loads[minIdx]--
b.mu.Unlock()
return resp, err
}
Таким образом, каждый запрос направляется на наименее загруженный экземпляр, что обеспечивает client-side балансировку нагрузки.