在上一章节的基础上,增加grpc协议支持,而无需改动之前代码。
多协议支持好处
- 灵活性和适应性:不同的微服务可能需要使用不同的通信协议,例如 HTTP、gRPC、Thrift 等,支持多种协议可以使得系统更加灵活,根据需求选择合适的通信方式。
- 技术选型自由:通过支持多种通信协议,开发者可以更自由地选择技术栈,不受限于特定的技术选型,有助于满足不同场景的需求。
- 互操作性:支持多种通信协议可以使得服务更易于与其他系统进行交互,不受限于特定的协议,提高了系统的互操作性。
- 性能优化:不同的通信协议适用于不同的场景,例如 gRPC 适用于高性能的内部通信,而 HTTP 适用于与外部系统进行通信,通过选择合适的协议可以更好地优化系统的性能。
go-kit 分层设计湿的多协议支持非常简单,这也体现出了分层设计的好处。只需要在Transport层增加一个对应协议Server即可。
在系统维护过程中,唯一不变的是变化,你不知道未来系统架构如何演进,一个可插拔的系统机制在未来重构时更加灵活。
实现步骤
示例代码: https://github.com/fengjx/go-kit-demo/tree/master/greetgrpc
安装 grpc 编译工具
- protoc 安装:https://grpc.io/docs/protoc-installation/
- protoc grpc 插件安装:https://grpc.io/docs/languages/go/quickstart/
定义 protobuf 协议
syntax = "proto3";
package pb;
option go_package="github.com/fengjx/go-kit-demo/greetgrpc/pb";
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloReq) returns (HelloResp) {}
}
// The request message containing the user's name.
message HelloReq {
string name = 1;
}
// The response message containing the greetings
message HelloResp {
string msg = 1;
}
编译protobuf
cd pb
bash build.sh
编译后会生成 greet.pb.go
和 greet_grpc.pb.go
两个文件
$ ls
build.sh greet.pb.go greet.proto greet_grpc.pb.go
参考代码
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net"
"net/http"
"github.com/go-kit/kit/endpoint"
grpctransport "github.com/go-kit/kit/transport/grpc"
httptransport "github.com/go-kit/kit/transport/http"
"google.golang.org/grpc"
"github.com/fengjx/go-kit-demo/greetgrpc/pb"
)
func main() {
svc := greetService{}
helloEndpoint := makeHelloEndpoint(svc)
satHelloHandler := httptransport.NewServer(
helloEndpoint,
decodeRequest,
encodeResponse,
)
startHTTPServer := func() {
log.Println("http server start")
http.Handle("/say-hello", satHelloHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
go startHTTPServer()
// grpc server
grpcServer := grpc.NewServer(grpc.UnaryInterceptor(grpctransport.Interceptor))
pb.RegisterGreeterServer(grpcServer, newGreeterServer(helloEndpoint))
startGRPCServer := func() {
log.Println("grpc server start")
ln, err := net.Listen("tcp", ":8000")
if err != nil {
panic(err)
}
log.Fatal(grpcServer.Serve(ln))
}
startGRPCServer()
}
type greetService struct {
}
func (svc greetService) SayHi(_ context.Context, name string) string {
return fmt.Sprintf("hi: %s", name)
}
func makeHelloEndpoint(svc greetService) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(*pb.HelloReq)
msg := svc.SayHi(ctx, req.Name)
return &pb.HelloResp{
Msg: msg,
}, nil
}
}
func decodeRequest(_ context.Context, r *http.Request) (interface{}, error) {
name := r.URL.Query().Get("name")
req := &pb.HelloReq{
Name: name,
}
return req, nil
}
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
data := map[string]any{
"status": 0,
"msg": "ok",
"data": response,
}
return json.NewEncoder(w).Encode(data)
}
type GreeterServer struct {
pb.UnimplementedGreeterServer
sayHello grpctransport.Handler
}
func newGreeterServer(e endpoint.Endpoint) pb.GreeterServer {
svr := &GreeterServer{}
svr.sayHello = grpctransport.NewServer(
e,
svr.decodeSayHello,
svr.encodeSayHello,
)
return svr
}
func (s *GreeterServer) SayHello(ctx context.Context, req *pb.HelloReq) (*pb.HelloResp, error) {
_, resp, err := s.sayHello.ServeGRPC(ctx, req)
if err != nil {
return nil, err
}
return resp.(*pb.HelloResp), nil
}
func (s *GreeterServer) decodeSayHello(_ context.Context, req interface{}) (interface{}, error) {
helloReq := req.(*pb.HelloReq)
return &pb.HelloReq{
Name: helloReq.Name,
}, nil
}
func (s *GreeterServer) encodeSayHello(_ context.Context, resp interface{}) (interface{}, error) {
return resp, nil
}
启动服务
go run main.go
测试
http 协议
# sya-hello
curl http://localhost:8080/say-hello?name=fengjx
{"data":{"msg":"hi: fengjx"},"msg":"ok","status":0}
grpc 协议
go run cmd/greetcli/mian.go
message -> hi: fengjx
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。