type Response interface{}

В представленном коде балансировщик (Balancer) реализует интерфейс Backend и распределяет вызовы между несколькими экземплярами BackendImpl по кругу (round-robin).

Короткий ответ

Что ответить на собеседовании

В представленном коде балансировщик (Balancer) реализует интерфейс Backend и распределяет вызовы между несколькими экземплярами BackendImpl по кругу (round-robin).

Подробный разбор

Ответ с пояснениями

Условие

type Response interface{}

type Backend interface { Invoke(ctx context.Context, req Request) (Response, error) }

var _ Backend = &BackendImpl{}

// addr содержит ip:port конкретного экземпляра func NewBackend(addr string) *BackendImpl

type backentry struct { backend Backend inflight int64 }

type Balancer struct { backends []*backentry mu *sync.Mutex }

var _ Backend = &Balancer{}

// addrs содержат адреса всех балансируемых экземпляров func NewBalancer(addrs []string) *Balancer { data := make([]*backentry,len(addrs)) for i,addr := range addrs{ data[i] = &backentry{ backend: NewBackend(addr), inflight: 0, } }

return &Balancer{backends:data}

}

func(b *Balancer)Invoke(ctx context.Context, req Request) (Response, error){ b.mu.Lock() entry := b.best() atomic.AddInt64(&entry.inflight,1) b.mu.Unlock() defer atomic.AddInt64(&entry.inflight,-1) return entry.backend.Invoke(ctx,req) }

func(b *Balancer) best() *backentry{ var best *backentry for _,entry := b.backends{ if best == nil || atomic.LoadInt64(&entry.inflight) < atomic.LoadInt64(&best.inflight){ best = entry } } return best }

Ответ

В представленном коде балансировщик (Balancer) реализует интерфейс Backend и распределяет вызовы между несколькими экземплярами BackendImpl по кругу (round-robin).

В методе Invoke есть ошибка в логике обновления индекса:

b.mu.Lock()
index := b.index
if b.index + 1 == len(b.backends) {
    b.index = 0
    index = 0
}
b.mu.Unlock()

Здесь b.index не увеличивается, а только сбрасывается в 0, из-за чего всегда выбирается первый backend.

Правильная реализация должна:

  • Зафиксировать текущий индекс
  • Увеличить b.index с переходом на 0 при достижении конца слайса

Пример исправления:

b.mu.Lock()
index := b.index
b.index = (b.index + 1) % len(b.backends)
b.mu.Unlock()

resp, err := b.backends[index].Invoke(ctx, req)
return resp, err

Также в функции NewBalancer нужно инициализировать слайс backends и заполнить его экземплярами BackendImpl по адресам из addrs:

func NewBalancer(addrs []string) *Balancer {
    backends := make([]*BackendImpl, len(addrs))
    for i, addr := range addrs {
        backends[i] = NewBackend(addr)
    }
    return &Balancer{
        backends: backends,
    }
}

Таким образом, балансировщик корректно распределит запросы по backend-экземплярам в круговом порядке.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее