当前位置:首页 > 技术文章 > 正文内容

Golang:在一个端口上运行多种服务

lcy2019-11-12技术文章2494

Ever faced the problem of having multiple ports in an application, one for each service? In this post, I’m going to brief about how to run multiple services via the same listener port.

At Dgraph , we used to have one port to serve HTTP requests, one for gRPC and one more for internal communication among the servers. But now we just use one port for all the outside facing services and one for internal server communications.

Cmux is a connection multiplexing library for Go. It allows you to differentiate services based on the payload. Hence, you can serve HTTP, HTTPS, gRPC, etc on the same port. For complete information on the protocols supported, refer to their godoc.

Let us jump into the three simple steps with some code sample and get this working in a jiffy.

First setup the different services as you would usually do. In our case we setup a gRPC service and an HTTP handler function.

// Setup gRPC server.type grpcServer struct{}

func (s *grpcServer) Query(ctx context.Context,
  req *graph.Request) (*graph.Response, error) {
  .
  .
  .
}// Handler function for http/https queries.func queryHandler(w http.ResponseWriter, r *http.Request) {
  addCorsHeaders(w)
  .
  .
  .

}

Second, write separate functions to start each service using a net.Listener object as if it is the only service using that listener. Later we’ll multiplex a single TCP listener into multiple listeners.

// Wrapper functions to start serving different services.func serveGRPC(l net.Listener) {
  s := grpc.NewServer(grpc.CustomCodec(&query.Codec{}))
  graph.RegisterDgraphServer(s, &grpcServer{})  if err := s.Serve(l); err != nil {    log.Fatalf("While serving gRpc request: %v", err)
  }
}

func serveHTTP(l net.Listener) {  if err := http.Serve(l, nil); err != nil {    log.Fatalf("While serving http request: %v", err)
  }
}

Third, create a listener object and multiplex it using a cmux matcher. It’ll read the header bytes of exchanges and figure out which service to trigger by giving us a new sub-listener (We just call it that, though it’s actually just net.Listener) for every match. We then call the services that we wrote earlier with these corresponding sub-listeners. Look at the following code sample to get a better hang of the above-mentioned steps.

func setupServer() {
  go worker.RunServer(*workerPort) // For internal communication.

  // Create a listener at the desired port.
  l, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))  if err != nil {    log.Fatal(err)
  }  // Create a cmux object.
  tcpm := cmux.New(l)  // Declare the match for different services required.
  httpl := tcpm.Match(cmux.HTTP1Fast())
  grpcl := tcpm.MatchWithWriters(
    cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc"))
  http2 := tcpm.Match(cmux.HTTP2())  // Link the endpoint to the handler function.
  http.HandleFunc("/query", queryHandler)  // Initialize the servers by passing in the custom listeners (sub-listeners).
  go serveGRPC(grpcl)
  go serveHTTP(httpl)
  go serveHTTP(http2)  // Close the listener when done.
  go func() {
    <-closeCh    // Stops listening further but already accepted connections are not closed.
    l.Close()
  }()  log.Println("grpc server started.")  log.Println("http server started.")  log.Println("Server listening on port", *port)  // Start cmux serving.
  if err := tcpm.Serve(); !strings.Contains(err.Error(),    "use of closed network connection") {    log.Fatal(err)
  }
}

So, there we have it. A single port to cater to many services that you might be using.

Hope you had fun with this post and learnt something new. Thanks for reading and do let us know your thoughts and how it works out for you.

来源:https://blog.dgraph.io/post/cmux/

 

版权声明:本文由cy's Blog发布,如需转载请注明出处。

本文链接:https://www.c3389.com/post/456.html

相关文章

H​y​p​e​r​-​V​ ​挂载物​理​硬​盘

挂载物理磁盘如果是新盘 直接让磁盘状态变为脱机即可 老盘的话需要删除磁盘 脱机 然后方可挂载。  ...

tcpdump高级过滤

tcpdump高级过滤

一:查看帮助选项#tcpdump --help Usage: tcpdump [-aAbdDefhHIJKlLnNOpqStuUvxX#] [ ...

利用命令行查看3389端口VBS版方法

很多时候我们只能暂时取得肉鸡的Cmd 权限,很多时候肉鸡的3389端口已经被更改,在这种情况下,大家不妨用这个方法来查看一下,使用方法,完全复制,粘贴到cmd上,回车即可!Echo Dim ReadC...

docker跑甜糖CDN

docker安装并运行arm模拟器容器docker run --rm --privileged multiarch/qemu-user-static --reset -p yes新建甜糖缓存目录(目录...

国内银行CNAPS CODE 查询

原地址:http://weekend.blog.163.com/blog/static/746895820127961346724/全国各地,无论哪个银行,无论什么分行,所有的CNAPS CODE都能...

如何在IIS7或IIS7.5中导入导出站点及应用程序池

为实现负载平衡,我们可能会使用多个WEB服务器,也就会需要给多个IIS配置同样的站点和应用程序池.那么我们需要一个一个的重新建吗?当然不用,我们只需要一些简单的命令就可以在IIS7(Windows S...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。