Почему мой сервер Hello World выходит из раздачи ApacheBench?
package main
import (
"io"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!\n")
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8000", nil)
}
У меня есть несколько невероятно простых HTTP-серверов, и все они демонстрируют эту проблему.
$ ab -c 1000 -n 10000 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
apr_socket_recv: Connection refused (61)
Total of 5112 requests completed
При меньшем значении concurrency все еще падает. Для меня проблема, похоже, обычно появляется вокруг метки 5k-6k:
$ ab -c 10 -n 10000 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
apr_socket_recv: Operation timed out (60)
Total of 6277 requests completed
И на самом деле вы можете полностью отказаться от concurrency и проблема (иногда):
$ ab -c 1 -n 10000 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
apr_socket_recv: Operation timed out (60)
Total of 6278 requests completed
Я не могу не задаться вопросом, не нахожу ли я какой-то предел операционной системы? Как я могу сказать? И как бы смягчить?
Ответы
Ответ 1
Короче говоря, у вас закончились порты.
Диапазон эфемерных портов по умолчанию для osx равен 49152-65535, что составляет только 16383 порта. Поскольку каждый запрос ab
http/1.0
(без сохранения в ваших первых примерах), каждый новый запрос принимает другой порт.
Поскольку каждый порт используется, он попадает в очередь, где он ожидает tcp "Максимальное время жизни сегмента", которое настроено на osx на 15 секунд. Таким образом, если вы используете более 16 383 порта за 15 секунд, вы эффективно будете получать дросселирование ОС при дальнейших соединениях. В зависимости от того, какой процесс выходит из портов первым, вы получите ошибки соединения с сервером или зависает от ab
.
Вы можете уменьшить это, используя генератор нагрузки http/1.1
, такой как wrk
, или используя параметр keepalive (-k
) для ab
, чтобы соединения повторно использовались на основе настроек инструмента concurrency.
Теперь код сервера, который вы сравниваете, делает так мало, что генератор нагрузки облагается налогом так же сильно, как сам терминал, а локальный стек и сетевой стек, вероятно, вносят хороший вклад. Если вы хотите сравнить HTTP-сервер, лучше сделать какую-то значимую работу от нескольких клиентов, не работающих на одном компьютере.