Na poziomie powierzchni jedyne, o co mam pytania, to zamawianie zwiększania grupy oczekiwania i kolejkowanie pracy:
func (s *Scheduler) Enqueue(req interface{}) {
select {
case s.reqChan <- req:
s.wg.Add(1)
}
}
Nie sądzę, że powyższe spowoduje w praktyce duży problem przy tak dużym obciążeniu pracą, ale myślę, że może to być logiczny warunek wyścigu. Na niższych poziomach współbieżności i mniejszych rozmiarach pracy może umieścić wiadomość w kolejce, conext przełączyć się na gorutynę, która rozpocznie pracę nad tą wiadomością, NASTĘPNIE pracę w grupie oczekiwania.
Dalej, czy na pewno process
metoda jest bezpieczna wątkowo? Zakładam, że na podstawie dokumentacji redis go, działa z go run -race
masz jakieś wyjście?
W pewnym momencie jest to całkowicie rozsądne i oczekuje się, że wydajność spadnie. Polecam rozpoczęcie testów wydajności, aby zobaczyć, gdzie zaczynają spadać opóźnienia i przepustowość:
może pula 10, 100, 500, 1000, 2500, 5000, 10000 lub cokolwiek ma sens. IMO wygląda na to, że należy dostroić 3 ważne zmienne:
- Wielkość puli pracowników
- Rozmiar bufora kolejki roboczej
- Ponownie
MaxActive
Największą rzeczą, która wyskakuje, jest to, że wygląda jak redis.Pool jest skonfigurowany tak, aby zezwalać na nieograniczoną liczbę połączeń:
Pula pool := &redis.Pool{
MaxIdle: 50,
IdleTimeout: 240 * time.Second,
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
Dial: func() (redis.Conn, error) {
return dial("tcp", address, password)
},
}
// Maksymalna liczba połączeń przydzielanych przez pulę w danym czasie.// Gdy zero, nie ma limitu liczby połączeń w puli.MaxActive int
Osobiście spróbowałbym zrozumieć, gdzie i kiedy wydajność zaczyna spadać, biorąc pod uwagę wielkość puli pracowników. Może to ułatwić zrozumienie ograniczeń Twojego programu.