GRPC Connection Management в Голанге - PullRequest
3 голосов
/ 09 мая 2019

Я относительно новичок в GRPC и хочу быть уверен, что я правильно управляю соединением с golang.Я не хочу создавать новое соединение для каждого вызова, но я также не хочу создавать узкие места при масштабировании.

Я создал одно соединение в функции init:

var userConn *grpc.ClientConn
var userServiceName string

func init() {
    userServiceName := os.Getenv("USER_SERVICE_URL")
    if userServiceName == "" {
        userServiceName = "localhost"
    }
    logging.LogDebug("userClient:  Connecting to: "+userServiceName, "")
    tempConn, err := grpc.Dial(userServiceName, grpc.WithInsecure())
    if err != nil {
        logging.LogEmergency("account_user_client.Init()  Could not get the connection.  "+err.Error(), "")
        return
    }
    userConn = tempConn
}

И затем для каждой функции я буду использовать это соединение для создания клиента:

c := user.NewUserClient(userConn)
// Contact the server and print out its response.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.GetUserFromTokenID(ctx, &user.GetUserFromTokenRequest{TransactionID: transactionID, OathToken: *oathToken})
//Handle Error and Response

это приемлемый способ обработки соединений GRPC?Любые рекомендации о лучших путях?

Большое спасибо.

1 Ответ

3 голосов
/ 10 мая 2019

Да, хорошо иметь одно клиентское соединение GRPC для каждой услуги. Более того, я не вижу здесь других вариантов. GRPC выполняет всю тяжелую работу под капотом: например, вам не нужно писать свой собственный пул клиентских подключений (как вы это сделали бы для типичной СУБД), потому что он не обеспечит лучших результатов, чем одно GRPC-соединение.

Однако я бы посоветовал вам избегать использования глобальных переменных и функций инициализации, особенно для настройки сети. Также вам не нужно создавать клиента GRPC (c := user.NewUserClient(userConn)) каждый раз, когда вы отправляете запрос в службу GRPC: это просто дополнительная работа для сборщика мусора, вы можете создать единственный экземпляр клиента во время запуска приложения .

Обновление

Предполагая, что вы пишете серверное приложение (поскольку это видно из метода, который вы вызываете в удаленной службе GRPC), вы можете просто определить тип, который будет содержать все объекты, которые имеют тот же срок жизни, что и все приложение. сам. Согласно традиции, эти типы обычно называют «контекстом сервера», хотя это немного сбивает с толку, потому что Go имеет очень важную концепцию context в своей стандартной библиотеке.

   // this type contains state of the server
   type serverContext struct {
       // client to GRPC service
       userClient user.UserClient

       // default timeout
       timeout time.Duration

       // some other useful objects, like config 
       // or logger (to replace global logging)
       // (...)       
   }

   // constructor for server context
   func newServerContext(endpoint string) (*serverContext, error) {
       userConn, err := grpc.Dial(endpoint, grpc.WithInsecure())
       if err != nil {
           return nil, err
       }
       ctx := &serverContext{
          userClient: user.NewUserClient(userConn),
          timeout: time.Second,
       }
       return ctx, nil
   }

   type server struct {
       context *serverContext
   }

   func (s *server) Handler(ctx context.Context, request *Request) (*Response, error) {
       clientCtx, cancel := context.WithTimeout(ctx, time.Second)
       defer cancel()
       response, err := c.GetUserFromTokenID(
          clientCtx, 
          &user.GetUserFromTokenRequest{
              TransactionID: transactionID,
              OathToken: *oathToken,
          },
       )
       if err != nil {
            return nil, err
       }
       // ...
   }

   func main() {
       serverCtx, err := newServerContext(os.Getenv("USER_SERVICE_URL"))
       if err != nil {
          log.Fatal(err)
       }
       s := &server{serverCtx}

       // listen and serve etc...
   }

Детали могут меняться в зависимости от того, над чем вы на самом деле работаете, но я просто хотел показать, что гораздо лучше инкапсулировать состояние вашего приложения в экземпляр другого типа, чем заражать глобальное пространство имен.

...