Middle
/* On olemas rakendus mikroteenuste arhitektuuriga. Mikroteenust saab abstraktselt kirjeldada Backend-liidese abil. Mikroteenuse eksemplarile juurdepääsuks saab kasutada juba rakendatud BackendImpl tüüpi. Igal mikroteenusel on mitu tosinat töötavat eksemplari, millest igaüks on kättesaadav oma aadressi addr kaudu. Kuid mikroteenuse üksikud eksemplarid ei ole usaldusväärsed: need võivad kokku kukkuda, olla kättesaamatud või ülekoormatud. Seetõttu peate rakendama tüübi Balancer, mis samuti rakendab Backend-liidest ja teostab kliendi poolel koormuse jaotamist mikroteenuse eksemplarite vahel, valides iga kord **vähemkoormatud** eksemplari. */ type Request interface{} type Response interface{} type Backend interface { Invoke(ctx context.Context, req Request) (Response, error) } var _ Backend = &BackendImpl{} // addr sisaldab konkreetse eksemplari ip:port aadressi func NewBackend(addr string) *BackendImpl type Balancer struct { // TODO } var _ Backend = &Balancer{} // addrs sisaldavad kõigi tasakaalustatud eksemplaride aadresse func NewBalancer(addrs []string) *Balancer { // TODO }
sobes.tech AI
Vastus AI-lt
Для реализации 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 балансировку нагрузки.