首页 > 其他分享 >Go每日一库之139:cmux (连接多路复用)

Go每日一库之139:cmux (连接多路复用)

时间:2023-09-29 21:12:58浏览次数:56  
标签:HTTP 多路复用 gRPC 一库 cmux Go http grpc

如果一个应用需要同时对外提供 HTTP 和 gRPC 服务,通常情况下我们会为两个服务绑定不同的监听端口,而本文要介绍的 cmux 为我们提供了一种连接多路复用的新选择,使用 cmux 可以将不同服务绑定在同一个网络端口上!

简介

多路复用是个很常见的概念,我们在编写 HTTP 服务时通常会用 http.ServeMux 或类似的三方工具实现请求与 handler 的匹配和绑定,这类多路复用一般作用在某个服务内部。而 cmux(github.com/soheilhy/cmux) 则提供了基于请求内容对连接进行多路复用的能力,使用 cmux 我们可以在同一个 TCP 监听(端口)上提供包括 gRPC、SSH、HTTPS、HTTP、Go RPC 在内的几乎任何协议。

cmux 通过扩展 net.Listener 的方式实现了连接多路复用能力,在接收到客户端请求后,cmux 会根据注册的规则对客户端请求进行鉴别和匹配,并根据匹配结果将请求转发给相应的服务。

使用举例

cmux 的使用特别简单,我们只需要为每个服务指定相应的匹配规则即可:

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 匹配规则
 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 访问:
每日一库之139:cmux%20(连接多路复用)-0

$ ${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 两个服务,是不是特别神奇!

总结

使用 cmux 我们可以轻松实现对服务端连接的多路复用,cmux 仅会在连接建立之初读取少量请求样本进行路由匹配,因此在客户端长连接场景下的性能损失几乎可以忽略不计。大家来试试吧!

参考资料

标签:HTTP,多路复用,gRPC,一库,cmux,Go,http,grpc
From: https://www.cnblogs.com/arena/p/17737348.html

相关文章

  • Go每日一库之138:dive(Docker 镜像分析)
    什么是dive?用于探索Docker镜像、每一层中的内容以及发现缩小Docker/OCI镜像大小的方法的工具。安装divego get github.com/wagoodman/divedive特性按层分解Docker镜像可视化展示每一层变化分析镜像空间使用百分比快速构建分析镜像支持多种镜像源和容器引擎......
  • Go每日一库之137:easeprobe(探活工具)
    服务探活在现实场景中应用广泛,比如:服务发现、服务负载均衡、服务调度、服务状态监控等。然而,“探活”往往是作为一个功能模块或者组件集成在各个平台系统中。本次要介绍的easeprobe是一款轻量级的,可独立运行的探活工具,利用easeprobe,无需其他系统支持,就可以对多种类型的服务/中间件......
  • Go每日一库之136:gopherjs(将Go代码编译成JS)
    简介GopherJS可以将Go代码编译成纯JavaScript代码。其主要目的是为了让你可以使用Go来编写前端代码,这些代码可执行在浏览器上运行。你可以通过这里尝试下GopherJS:GopherJSPlayground.例如JavaScript代码:document.write("Hello world!");用GopherJS来写就变成这......
  • Go每日一库之135:Ent(Facebook 开源 Golang 实体框架)
    对于后端开发者来说,一款好用的框架能够大大提升应用的开发效率。为了降低开发者使用TiDB的门槛,方便开发者快速连接到TiDB,我们也在和合作伙伴一起,逐步完善面向主流开发语言和框架的连接支持。近日,Facebook开源的Golang实体框架Ent完成了对TiDB数据库的支持。Ent是......
  • Go每日一库之134:fsm(基有限状态机库)
    开发中,我们经常会遇到这种情况,服务模块有多种状态,它们有一定的顺序,先后执行,逐步切换。这时,fsm这个库可以帮助我们更好的管理多个状态。fsm库,它主要基于两个FSM实现,增加了golang版本的实现:JavascriptFiniteStateMachine,https://github.com/jakesgordon/javascript-state-ma......
  • Go - Using Log Levels
    Examplesofloglevelsfromhightoloware:•Fatal•Error•Warn•Info•DebugTosetuploglevelsforyourlogs,youcanaddtheleveltoeachlineofthelog.ThemoststraightforwardwayofdoingthisistousetheSetPrefixfunction:log.S......
  • CF1425F Flamingoes of Mystery 题解
    题目传送门前置知识前缀和&差分解法令\(sum_k=\sum\limits_{i=1}^{k}a_k\)。考虑分别输入\(sum_2\simsum_n\),故可以由于差分知识得到\(a_i=sum_i-sum_{i-1}(3\lei\len)\),接着输入\(a_2+a_3\)的值从而求出\(a_2=sum_3-a_3,a_1=sum_2-a_2\)。同时因为是交互题,记......
  • Go - Logging to File
    Problem: Youwanttologeventstoalogfileinsteadofstandarderror.Solution: UsetheSetOutputfunctiontosetthelogtowritetoafile. YouuseSetOutputtoredirecttheoutputtoafile.file,err:=os.OpenFile("app.log"......
  • Go - Change What Is Being Logged by the Standard Logger
    Problem: Youwanttochangewhatthestandardloggerlogs.Solution: UsetheSetFlagsfunctiontosetflagsandaddfieldstoeachlogline. Thedefaultbehaviorofthestandardloggeraddsthedateandtimefieldstoeachlineofthelog. Thelogpac......
  • Go - logging
    Thelogpackageprovidesseveralfunctionsthatallowyoutowritelogs.Inparticular,therearethreesetsoffunctions:Print•PrintsthelogstotheloggerFatal•Printstotheloggerandcallsos.Exitwithanexitcodeof1Panic•Printstothelo......