「GoCN酷Go推薦」使用 cmux 實現(xiàn)服務(wù)端連接多路復(fù)用
如果一個應(yīng)用需要同時對外提供 HTTP 和 gRPC 服務(wù),通常情況下我們會為兩個服務(wù)綁定不同的監(jiān)聽端口,而本文要介紹的 cmux 為我們提供了一種連接多路復(fù)用的新選擇,使用 cmux 可以將不同服務(wù)綁定在同一個網(wǎng)絡(luò)端口上!
?
簡介
?
多路復(fù)用是個很常見的概念,我們在編寫 HTTP 服務(wù)時通常會用 http.ServeMux 或類似的三方工具實現(xiàn)請求與 handler 的匹配和綁定,這類多路復(fù)用一般作用在某個服務(wù)內(nèi)部。而 cmux(github.com/soheilhy/cmux) 則提供了基于請求內(nèi)容對連接進行多路復(fù)用的能力,使用 cmux 我們可以在同一個 TCP 監(jiān)聽(端口)上提供包括 gRPC、SSH、HTTPS、HTTP、Go RPC 在內(nèi)的幾乎任何協(xié)議。
cmux 通過擴展 net.Listener 的方式實現(xiàn)了連接多路復(fù)用能力,在接收到客戶端請求后,cmux 會根據(jù)注冊的規(guī)則對客戶端請求進行鑒別和匹配,并根據(jù)匹配結(jié)果將請求轉(zhuǎn)發(fā)給相應(yīng)的服務(wù)。
?
使用舉例
?
cmux 的使用特別簡單,我們只需要為每個服務(wù)指定相應(yīng)的匹配規(guī)則即可:
package?main
import?(
?"context"
?"log"
?"net"
?"net/http"
?"google.golang.org/grpc"
?pb?"google.golang.org/grpc/examples/helloworld/helloworld"
?"github.com/soheilhy/cmux"
)
func?main()?{
?lis,?err?:=?net.Listen("tcp",?"localhost:50051")
?if?err?!=?nil?{
??log.Fatalf("failed?to?listen:?%v",?err)
?}
?mux?:=?cmux.New(lis)
?//?gRPC?匹配規(guī)則
?grpcL?:=?mux.MatchWithWriters(
??cmux.HTTP2MatchHeaderFieldSendSettings("content-type",?"application/grpc"),
?)
?//?otherwise?serve?http
?httpL?:=?mux.Match(cmux.Any())
?//?gRPC?server
?grpcS?:=?grpc.NewServer()
?pb.RegisterGreeterServer(grpcS,?&server{})
?//?HTTP?server
?httpS?:=?&http.Server{
??Handler:?http.HandlerFunc(func(w?http.ResponseWriter,?r?*http.Request)?{
???w.Write([]byte("greet?from?HTTP\n"))
??}),
?}
?//?start?serving!
?go?grpcS.Serve(grpcL)
?go?httpS.Serve(httpL)
?log.Printf("serve?both?grpc?and?http?at?%v",?lis.Addr())
?if?err?:=?mux.Serve();?err?!=?nil?{
??log.Fatalf("failed?to?serve:?%v",?err)
?}
}
type?server?struct?{
?pb.UnimplementedGreeterServer
}
func?(*server)?SayHello(ctx?context.Context,?in?*pb.HelloRequest)?(*pb.HelloReply,?error)?{
?return?&pb.HelloReply{Message:?"greet?from?gRPC"},?nil
}
先來試試 http 訪問是否正常
$ curl -D - http://localhost:50051
HTTP/1.1 200 OK
Date: Mon, 21 Mar 2022 08:20:15 GMT
Content-Length: 16
Content-Type: text/plain; charset=utf-8
greet from HTTP
再來試試 gRPC 訪問
$ ${GOPATH}/bin/greeter_client -addr localhost:50051
2022/03/21 16:12:11 Greeting: greet from gRPC
測試客戶端安裝:go install google.golang.org/grpc/examples/helloworld/greeter_client
如上,我們通過 50051 這個端口同時承載了 HTTP 和 gRPC 兩個服務(wù),是不是特別神奇!
?
總結(jié)
?
使用 cmux 我們可以輕松實現(xiàn)對服務(wù)端連接的多路復(fù)用,cmux 僅會在連接建立之初讀取少量請求樣本進行路由匹配,因此在客戶端長連接場景下的性能損失幾乎可以忽略不計。大家來試試吧!
?
參考資料
?
https://github.com/soheilhy/cmux
《酷Go推薦》招募:
各位Gopher同學(xué),最近我們社區(qū)打算推出一個類似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個庫或者好的項目,然后寫一點這個庫使用方法或者優(yōu)點之類的,這樣可以真正的幫助到大家能夠?qū)W習(xí)到
新的庫,并且知道怎么用。
大概規(guī)則和每日新聞類似,如果報名人多的話每個人一個月輪到一次,歡迎大家報名!戳「閱讀原文」,即可報名
想要了解更多 Golang 相關(guān)的內(nèi)容,歡迎掃描下方???關(guān)注?公眾號,回復(fù)關(guān)鍵詞 [實戰(zhàn)群]? ,就有機會進群和我們進行交流~
