Я работаю над приложением с обратным прокси-сервером и встроенным балансом нагрузки.
Когда я выполняю тесты с высокой нагрузкой, мое приложение зависает с таймаутами, возвращаемыми в инструмент тестирования.
I Воспроизведение этого поведения с минимальным кодом ниже.
proxy.go
файл:
package main
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Pong")
}
func newMux() *http.ServeMux {
serverURL, _ := url.Parse("http://127.0.0.1:5000")
proxy := httputil.NewSingleHostReverseProxy(serverURL)
sm := http.NewServeMux()
sm.HandleFunc("/", handler)
sm.HandleFunc("/proxy", proxy.ServeHTTP)
return sm
}
func main() {
server := http.Server{
Addr: ":1447",
Handler: newMux(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
log.Fatal(server.ListenAndServe())
}
backend.go
файл:
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func newMux() *http.ServeMux {
sm := http.NewServeMux()
sm.HandleFunc("/", handler)
return sm
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello")
}
func main() {
server := http.Server{
Addr: ":5000",
Handler: newMux(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
log.Fatal(server.ListenAndServe())
}
Я делаю тесты с wrk2 инструмент с помощью этой команды:
wrk2 -t12 -c100 -d30s -R20000 http://127.0.0.1:1447/
Шаги, применяемые для подтверждения проблемы:
- Скомпилируйте и запустите
backend.go
на 5000
порту - Запустите
wrk2 -t12 -c100 -d30s -R20000 http://127.0.0.1:5000/
, чтобы проверить обнаженный бэкэнд с 20k RPS в течение 30 секунд - Через 30 секунд wrk2 покажет эту статистику
597996 requests in 30.00s, 68.44MB read
- Скомпилируйте и запустите
proxy.go
на 1447
порту - Запустите
wrk2 -t12 -c100 -d30s -R20000 http://127.0.0.1:1447/proxy
, чтобы прокси-запросы на бэкэнд с 20k RPS продолжительностью 30 секунд - Через 30 секунд wrk2 показывает эту статистику
33699 requests in 30.06s, 3.89MB read; Socket errors: connect 0, read 0, write 0, timeout 960
Я не могу понять это поведение - почему выполнение теста прямо на backend.go
нормально без тайм-аутов, но проксирование запросов грубый возврат ReverseProxy почти на 94% времени ожидания?
Сравнительный тест на одном MacBook Pro в середине 2013 года с 8 ГБ ОЗУ и 2,6 ГГц Intel Core i5. Текущие настройки ulimit
:
> ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 8192
pipe size (512 bytes, -p) 1
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 1392
virtual memory (kbytes, -v) unlimited