Go微服务八 Go-gGRPC 不同端口提供rpc和http服务

作者: 太阳上的雨天 分类: 微服务 发布时间: 2022-02-27 19:52

[微服务六]略有不同。

以商品详情场景解释本篇和[微服务六]还有[微服务七]的不同之处

微服务六: 不同端口同时支持rpc和http。

​ 场景: 商品服务-> 商品库存等

​ 商品服务-> 商品库存提供rpc:端口(9001) 客户端可以通过rpc调用商品库存rpc接口服务,

此时客户端可能没有使用rpc,只会http api调用的形式。这个时候客户端也可以通过http, 调用用商品库存rpc接口提供的http: 端口(8001)

相当于一个商品库存,通过基于protobuf协议封装的grpc即提供了rpc又提供了http,而且端口还不同,这样也可以,在基于protobuf封装rpc的时候,加一个options参数,使用对应的路由实现。但是有一点不方便,不管是rpc还是http api变动都需要使用proto重新生成对应的*.pb.go文件,增加维护成本,如果调用方不支持rpc可以使用此方式

微服务七: 同一个端口支持grpc和http

​ 场景: 商品服务-> 商品库存、商品详情、商品列表等

​ 商品服务-> 商品库存rpc接口端口(9001) 客户端可以通过rpc调用商品库存rpc接口,但不能通过http调用商品库存rpc服务接口. 但是此时商品服务可能还存在一些其他的api,比如商品详情、商品列表等,此时不想通过封装rpc供客户端调用,想通过简单的http api方式供客户端使用,但是又不想一个商品服务同时暴漏两个端口,可以采用此方法。比方客户端可以通过http调用商品服务另外提供的api,端口也是9001

不建议,最好还是分别使用不同的端口,端口对应独立的服务

本篇文章: 不同端口提供rpc和http

​ 场景: 商品服务-> 商品库存、商品详情、商品列表等
商品服务 ->商品库存只提供rpc 但是商品详情和商品列表不提供rpc只提供http api,端口又不同

目录结构

image-20220311173132032

一 创建项目

mkdir demo

cd demo && go mod init demo && go get google.golang.org/grpc && touch generate_pb && chmod +x generate_pb

mkdir demo-server && mkdir demo-client

cd demo-server && mkdir pb && mkdir proto && mkdir rpcServices && touch main.go

cd demo-client && touch main.go

二 代码编写

rpcDemoService.proto

syntax = "proto3";

package pb;

option go_package = "../pb";

message GetUserInfoRequest {
  int32 id = 1;
}

message GetUserInfoResponse {
  string name = 1;
  int32 age = 2;
}

service RpcDemoService {
  rpc GetUserInfo(GetUserInfoRequest) returns (GetUserInfoResponse){}
}

generate_pb

cd proto && protoc --go_out=plugins=grpc:../pb rpcDemoService.proto

执行./generate_pb,会在pb目录闲生成*.pb.go文件

rpcDemoService.go

package rpcServices

import (
    "context"
    "demo/demo-server/pb"
)

type RpcDemoService struct{}

func (rd *RpcDemoService) GetUserInfo(ctx context.Context, r *pb.GetUserInfoRequest) (*pb.GetUserInfoResponse, error) {
    return &pb.GetUserInfoResponse{
        Name: "demo",
        Age:  18,
    }, nil
}

main.go

package main

import (
    "demo/demo-server/pb"
    "demo/demo-server/rpcServices"
    "flag"
    "log"
    "net"
    "net/http"

    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
)

var grpcPort string
var httpPort string

func init() {
    flag.StringVar(&grpcPort, "g", "8001", "gRPC 启动端口号")
    flag.StringVar(&httpPort, "h", "9001", "HTTP 启动端口号")
    flag.Parse()
}

//RunHttpServer
func RunHttpServer(port string) error {
    serveMux := http.NewServeMux()
    serveMux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
        _, _ = w.Write([]byte(`pong`))
    })

    return http.ListenAndServe(":"+port, serveMux)
}

//RunGrpcServer
func RunGrpcServer(port string) error {
    s := grpc.NewServer()
    pb.RegisterRpcDemoServiceServer(s, new(rpcServices.RpcDemoService))
    reflection.Register(s)
    lis, err := net.Listen("tcp", ":"+port)
    if err != nil {
        return err
    }

    return s.Serve(lis)
}

func main() {
    errs := make(chan error)
    go func() {
        err := RunHttpServer(httpPort)
        if err != nil {
            errs <- err
        }
    }()
    go func() {
        err := RunGrpcServer(grpcPort)
        if err != nil {
            errs <- err
        }
    }()

    select {
    case err := <-errs:
        log.Fatalf("Run Server err: %v", err)
    }
}

cd demo-client

main.go

package main

import (
    "context"
    "demo/demo-server/pb"
    "fmt"

    "google.golang.org/grpc"
)

func main() {
    conn, err := grpc.Dial(":8001", grpc.WithInsecure())
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    demoServiceClient := pb.NewRpcDemoServiceClient(conn)
    result, err := demoServiceClient.GetUserInfo(context.Background(), &pb.GetUserInfoRequest{
        Id: 10,
    })
    if err != nil {
        panic(err)
    }

    fmt.Println(result)
}

测试grpc

执行

cd demo-server
go run main.go

postman 或者curl访问 127.0.0.1:9001/ping

image-20220311173928559

测试http

执行

cd demo-client && go run main.go

image-20220311174052210

修改demo-server/main.go 结合echo框架支持restful api

package main

import (
    "demo/demo-server/pb"
    "demo/demo-server/rpcServices"
    "flag"
    "log"
    "net"
    "net/http"

    "github.com/labstack/echo"

    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
)

var grpcPort string
var httpPort string

func init() {
    flag.StringVar(&grpcPort, "g", "8001", "gRPC 启动端口号")
    flag.StringVar(&httpPort, "h", "9001", "HTTP 启动端口号")
    flag.Parse()
}

//RunHttpServer
func RunHttpServer(port string) {
    //serveMux := http.NewServeMux()
    //serveMux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
    //  _, _ = w.Write([]byte(`pong`))
    //})
    //
    //return http.ListenAndServe(":"+port, serveMux)
    e := echo.New()
    e.GET("/ping", func(c echo.Context) error {
        return c.JSON(http.StatusOK, "pong...")
    })
    e.Logger.Fatal(e.Start(":" + port))
}

//RunGrpcServer
func RunGrpcServer(port string) error {
    s := grpc.NewServer()
    pb.RegisterRpcDemoServiceServer(s, new(rpcServices.RpcDemoService))
    reflection.Register(s)
    lis, err := net.Listen("tcp", ":"+port)
    if err != nil {
        return err
    }

    return s.Serve(lis)
}

func main() {
    errs := make(chan error)
    go func() {
        RunHttpServer(httpPort)
    }()
    go func() {
        err := RunGrpcServer(grpcPort)
        if err != nil {
            errs <- err
        }
    }()

    select {
    case err := <-errs:
        log.Fatalf("Run Server err: %v", err)
    }
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注