Sobes.tech
Back to questions
Middle
7

// TODO backends []*BackendImpl index int mu sync.Mutex func (b *Balancer) Invoke(ctx context.Context, req Request) (Response, error) { b.mu.Lock() index := b.index if b.index + 1 == len(b.backends) { b.index = 0 index = 0 } b.mu.Unlock() resp, err := b.backends[index].Invoke(ctx, req) b.mu.Lock() defer b.mu.Unlock() b.index += 1 return resp, err } // addr содержит ip:port конкретного экземпляра func NewBackend(addr string) *BackendImpl // addrs содержат адреса всех балансируемых экземпляров func NewBalancer(addrs []string) *Balancer { // TODO backends := make([]*BackendImpl, len(addrs)) for _, addr := addrs { backends = append(backends, NewBackend(addr)) } return &Balancer{ backends: backends, } }

Companies where asked
Яндекс

Answer from AI

sobes.tech AI

В представленном коде есть несколько ошибок и недочётов, которые мешают корректной работе балансировщика:

  1. В функции Invoke блокировка и обновление индекса сделаны некорректно. Сначала индекс читается и условно сбрасывается, но при этом b.index не увеличивается, а увеличение происходит после вызова Invoke, что может привести к гонкам и неправильному выбору backend.

  2. В функции NewBalancer при создании слайса backends происходит ошибка: сначала создаётся слайс длины len(addrs), а затем в цикле к нему добавляются элементы через append, что приводит к тому, что в слайсе сначала идут нулевые элементы, а потом добавленные. Нужно либо создавать пустой слайс с capacity, либо заполнять по индексам.

Исправленный вариант:

func (b *Balancer) Invoke(ctx context.Context, req Request) (Response, error) {
    b.mu.Lock()
    index := b.index
    b.index = (b.index + 1) % len(b.backends)
    b.mu.Unlock()

    return b.backends[index].Invoke(ctx, req)
}

func NewBalancer(addrs []string) *Balancer {
    backends := make([]*BackendImpl, 0, len(addrs))
    for _, addr := range addrs {
        backends = append(backends, NewBackend(addr))
    }

    return &Balancer{
        backends: backends,
    }
}

Здесь:

  • В Invoke индекс выбирается и сразу увеличивается по модулю длины слайса, чтобы обеспечить циклический обход.
  • В NewBalancer создаётся пустой слайс с нужной capacity, чтобы избежать лишних нулевых элементов.

Такой балансировщик реализует простой round-robin выбор backend для каждого запроса с корректной синхронизацией.