У меня есть простое приложение отдыха golang, которое отвечает на эхо-запрос, как это:
// Return echo message
func echoHandler(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
message := params["message"]
fmt.Fprintf(w, "%s", message)
}
func main() {
// Config data
port := ":9596"
router := mux.NewRouter() //.StrictSlash(true)
router.HandleFunc("/echo/{message}", echoHandler).Methods("GET")
srv := &http.Server{
Addr: port,
// Good practice to set timeouts to avoid Slowloris attacks.
// Using just the read parameter due to this article
// https://stackoverflow.com/questions/29334407/creating-an-idle-timeout-in-go
//WriteTimeout: time.Second * 60,
ReadTimeout: time.Second * 15,
////: time.Second * 120,
//Handler: router,
Handler: router,
}
// Run our server in a goroutine so that it doesn't block.
go func() {
log.Println("Running server....")
//log.Fatal(http.ListenAndServe(port, router))
//log.Println(s.ListenAndServe())
if err := srv.ListenAndServe(); err != nil {
log.Println(err)
}
}()
c := make(chan os.Signal, 1)
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
signal.Notify(c, os.Interrupt)
// Block until we receive our signal.
<-c
// Create a deadline to wait for.
ctx, cancel := context.WithTimeout(context.Background(), wait)
defer cancel()
// Doesn't block if no connections, but will otherwise wait
// until the timeout deadline.
srv.Shutdown(ctx)
// Optionally, you could run srv.Shutdown in a goroutine and block on
// <-ctx.Done() if your application should wait for other services
// to finalize based on context cancellation.
fmt.Println("\n\n")
log.Println("shutting down")
log.Println("Goddbye!....")
os.Exit(0)
}
Эта программа вызывается другой службой через запрос GET:
// Return default message for root routing
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}
// Handle iterative path and calls iterative calculation service
func echoHandler(calledServiceURL string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
url := calledServiceURL + "/echo/" + params["message"]
tr := &http.Transport{
//MaxIdleConns: 500,
//MaxIdleConnsPerHost: 500,
}
netClient := &http.Client{Transport: tr}
req, reqErr := http.NewRequest("GET", url, nil)
if reqErr != nil {
log.Fatal("Error en response: ", reqErr)
fmt.Fprintf(w, "Error en response: %s", reqErr)
return
}
//req.Header.Set("Connection", "close")
//req.Header.Set("Connection", "Keep-Alive")
//resp, err := netClient.Get(url)
resp, err := netClient.Do(req)
if err != nil {
log.Fatal("Error en response: ", err)
fmt.Fprintf(w, "Error en response: %s", err)
return
}
respData, errResp := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if errResp != nil {
log.Fatal("Error en RespData", errResp)
fmt.Fprintf(w, "Error en respData: %s", err)
return
}
fmt.Fprintf(w, "%s", respData)
}
}
// Main function
func main() {
// Set default values
port := ":9296"
calledServiceURL := "http://localhost:9596"
router := mux.NewRouter() //.StrictSlash(true)
router.HandleFunc("/", Index).Methods("GET")
router.HandleFunc("/echo/{message}", echoHandler(calledServiceURL)).Methods("GET")
srv := &http.Server{
Addr: port,
// Good practice to set timeouts to avoid Slowloris attacks.
// Using just the read parameter due to this article
// https://stackoverflow.com/questions/29334407/creating-an-idle-timeout-in-go
//WriteTimeout: time.Second * 60,
ReadTimeout: time.Second * 15,
//IdleTimeout: time.Second * 120,
//Handler: router, // Pass our instance of gorilla/mux in.
Handler: router,
}
// Run our server in a goroutine so that it doesn't block.
go func() {
log.Println("Running server....")
if err := srv.ListenAndServe(); err != nil {
log.Println(err)
}
}()
c := make(chan os.Signal, 1)
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
signal.Notify(c, os.Interrupt)
// Block until we receive our signal.
<-c
// Create a deadline to wait for.
ctx, cancel := context.WithTimeout(context.Background(), wait)
defer cancel()
// Doesn't block if no connections, but will otherwise wait
// until the timeout deadline.
srv.Shutdown(ctx)
// Optionally, you could run srv.Shutdown in a goroutine and block on
// <-ctx.Done() if your application should wait for other services
// to finalize based on context cancellation.
fmt.Println("\n\n")
log.Println("shutting down")
log.Println("Goddbye!....")
os.Exit(0)
}
У меня были проблемы с закрытыми соединениями под нагрузкой при тестировании с помощью инструмента ab для 500 одновременных подключений с 50000 запросами на моем Mac, которые я решил, отправив соединение с закрытием заголовка в запросе GET, и теперь проверка на моем компьютере прошла успешно ,
Однако, когда я попытался запустить тест в окне Windows 10, я снова получаю сообщения, подобные этому:
2019/03/08 20:47:47 Error en response: Get http://localhost:9596/echo/javier: dial tcp [::1]:9596: bind: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
После поисков в течение некоторого времени в поисках окон, альтернативных ulimit, чтобы изменить ограничения ресурсов, я нашел сообщения, подобные этому:
Я не верю, что текущие операционные системы Windows имеют ограничение на общее количество
количество файловых дескрипторов, но библиотека времени выполнения MS (msvcrt.dll)
имеет ограничение на процесс 2048, хотя, насколько я знаю, это не
применяется О / С.
Якобы его можно увеличить, только создав собственную версию
Библиотека времени выполнения MS из источника.
Тогда мне любопытно, потому что у меня один и тот же сервис, созданный с помощью Java и NodeJS, и оба могут успешно выполнить тест на тех же компьютерах, где мое приложение go не работает из-за упомянутых выше ошибок.
Так что теперь мои вопросы / сомнения:
Чем Java и NodeJS отличаются от go http-сервера, чтобы пройти мой тест без ограничений операционной системы?
Что я могу сделать, чтобы мои сервисы go были успешными в любой системе, как это делали Java и NodeJS?
Наконец, есть ли способ сообщить моим службам go предельные значения ОС, чтобы они не достигли их и не прошли тесты?
Эта проблема сводит меня с ума, и даже когда она позволяет мне многое узнать о протоколе http, становится все темнее с каждым днем, так как я не могу найти решение, и я буду рад, если мое приложение будет разрабатываться на ходу, а не на Java. потому что, кажется, намного лучше, когда работает хорошо.
Заранее спасибо
J * * тысяча тридцать восемь