亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Golang 中的 GRPC 連接管理

Golang 中的 GRPC 連接管理

Go
慕妹3242003 2023-06-19 13:45:17
我是 GRPC 的新手,想確保我正在使用 golang 正確地進行連接管理。我不想為每個呼叫都創建一個新連接,但我也不想在擴展時造成瓶頸。我所做的是在 init 函數中創建一個連接:var userConn *grpc.ClientConnvar userServiceName stringfunc 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 連接的可接受方式嗎?關于更好的方法有什么建議嗎?
查看完整描述

2 回答

?
繁花不似錦

TA貢獻1851條經驗 獲得超4個贊

是的,每個服務有一個 GRPC 客戶端連接很好。此外,我在這里看不到任何其他選項。GRPC 在幕后完成所有繁重的工作:例如,您不需要編寫自己的客戶端連接池(就像您為典型的 RDBMS 所做的那樣),因為它不會提供比單個 GRPC 連接更好的結果。


但是我建議您避免使用全局變量和初始化函數,尤其是對于網絡設置。此外,您不需要c := user.NewUserClient(userConn)在每次向 GRPC 服務發送請求時都創建 GRPC 客戶端 ( ):這只是垃圾收集器的額外工作,您可以在應用程序啟動時創建客戶端的唯一實例。


更新


假設您正在編寫服務器應用程序(因為它可以從您調用遠程 GRPC 服務的方法中看出),您可以簡單地定義一個類型,該類型將包含與整個應用程序本身具有相同生命周期的所有對象。按照傳統,這些類型通常被稱為“服務器上下文”,盡管這有點令人困惑,因為 Gocontext在其標準庫中有一個非常重要的概念。


   // 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...

   }


細節可能會根據您的實際工作而改變,但我只是想表明,將應用程序的狀態封裝在不同類型的實例中比感染全局命名空間要好得多。


查看完整回答
反對 回復 2023-06-19
?
叮當貓咪

TA貢獻1776條經驗 獲得超12個贊

一些事情使這個實現工作。

  1. gRPC 通道(即cfrom?c := user.NewUserClient(userConn))由 http/2 連接支持。當連接關閉或失效時,它會自動重新連接或重試連接。

  2. http/2 支持在單個連接中同時發送消息。考慮到這種場景,service Order 對service Product 一次獲取一個產品庫存,更新產品庫存,更改產品優惠券。三個 grpc 請求可以重用單個 http/2 連接,grpc 將并發處理數據交換。所以只使用一個連接是可以的,而不是創建三個連接(比如 http/1)來實現這一點。

  3. 為避免過早優化,一個連接應該可以為一項服務啟動。為了將來的池性能,考慮為熱點 grpc 請求創建一個單獨的 tcp 連接(然后單獨的 http/2 連接)。

保持連接活動可能是件好事,以防某些代理可能會終止空閑連接。

查看完整回答
反對 回復 2023-06-19
  • 2 回答
  • 0 關注
  • 272 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號