Элегантный способ обработки горутины в состоянии ожидания ввода-вывода в GRPC

Наш сервер (grpc-gateway + grpc) работает на K8S с go 1.13 и завершает информацию о стеке.

    Last State:    Terminated
      Reason:      Error
      Message:     o.(*Reader).fill(0xc002ec78c0)
                   /Users/local/go/src/bufio/bufio.go:100 +0x103
bufio.(*Reader).Peek(0xc002ec78c0, 0x4, 0x0, 0x0, 0x0, 0x0, 0xc002e79ad0)
  /Users/local/go/src/bufio/bufio.go:138 +0x4f
net/http.(*conn).readRequest(0xc00245a000, 0x1ef4800, 0xc000be7780, 0x0, 0x0, 0x0)
  /Users/local/go/src/net/http/server.go:962 +0xb3b
net/http.(*conn).serve(0xc00245a000, 0x1ef4800, 0xc000be7780)
  /Users/local/go/src/net/http/server.go:1817 +0x6d4
created by net/http.(*Server).Serve
  /Users/local/go/src/net/http/server.go:2928 +0x384

goroutine 8724981 [IO wait]:
internal/poll.runtime_pollWait(0x7f5d3a8f84e8, 0x72, 0xffffffffffffffff)
  /Users/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc000155d98, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
  /Users/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
  /Users/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc000155d80, 0xc00138b000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
  /Users/local/go/src/internal/poll/fd_unix.go:169 +0x1cf
net.(*netFD).Read(0xc000155d80, 0xc00138b000, 0x1000, 0x1000, 0xc00142b9e8, 0x4ce13d, 0xc000155d80)
  /Users/local/go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc0000dd690, 0xc00138b000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
  /Users/local/go/src/net/net.go:184 +0x68
net/http.(*connReader).Read(0xc001e9b050, 0xc00138b000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
  /Users/local/go/src/net/http/server.go:785 +0xf4
bufio.(*Reader).fill(0xc0021fe060)
  /Users/local/go/src/bufio/bufio.go:100 +0x103
bufio.(*Reader).Peek(0xc0021fe060, 0x4, 0x0, 0x0, 0x0, 0x0, 0xc00142bad0)
  /Users/local/go/src/bufio/bufio.go:138 +0x4f
net/http.(*conn).readRequest(0xc0008f43c0, 0x1ef4800, 0xc000503640, 0x0, 0x0, 0x0)
  /Users/local/go/src/net/http/server.go:962 +0xb3b
net/http.(*conn).serve(0xc0008f43c0, 0x1ef4800, 0xc000503640)
  /Users/local/go/src/net/http/server.go:1817 +0x6d4
created by net/http.(*Server).Serve
  /Users/local/go/src/net/http/server.go:2928 +0x384

      Exit Code:    2

Согласно этому вопросу, одним из возможных решений является

>  s := new(http.Server)
>  // ...
>  s.ReadTimeout = 5 * time.Second
>  s.WriteTimeout = 5 * time.Second
>  // ...

Однако нам не удалось найти ReadTimeout из grpc.NewServer, мы что-то упустили? или как более элегантно обрабатывать горутину в состоянии ожидания ввода-вывода в GRPC?

версия grpc: v1.21.1


person zangw    schedule 15.06.2021    source источник


Ответы (2)


gprc.NewServer допускает ноль или более ServerOption при создании:

func NewServer(opt ...ServerOption) *Server

хотя похоже, что ReadTimeout или WriteTimeout не существует эквивалента http.Server, вы можете попробовать keepalive.ServerParameters:

type ServerParameters struct {
    MaxConnectionIdle     time.Duration // The current default value is infinity.
    MaxConnectionAge      time.Duration // The current default value is infinity.
    MaxConnectionAgeGrace time.Duration // The current default value is infinity.
    Time                  time.Duration // The current default value is 2 hours.
    Timeout               time.Duration // The current default value is 20 seconds.
}

(полная документация keepalive.ServerParameters)

и настройте say keepalive.ServerParameters.Time на что-то менее 2 часов:

srv := grpc.NewServer(
    keepalive.ServerParameters{Time:5*time.Minute},
)

Это уменьшит повторное использование соединений, но также освободит клиентские соединения, которые давно мертвы.

person colm.anseo    schedule 15.06.2021

Вы используете Context с тайм-аутом.

https://golang.org/pkg/context/

person Moo    schedule 15.06.2021
comment
Это клиентское решение. ОП спрашивает о серверной части. - person colm.anseo; 15.06.2021
comment
Какая? context.Context находится на стороне сервера! http.запрос.контекст() - person Moo; 15.06.2021
comment
ieftimov.com/post / - person Moo; 15.06.2021
comment
Это контекст запроса на стороне сервера после обработки запроса. Его можно использовать для обнаружения отмены активного запроса. Что делать, если клиент установил соединение, но еще не отправил запрос? - person colm.anseo; 15.06.2021