一 概述
本文主要介绍 grpc-gateway
使用以及实现原理。
二 grpc-gateway 基础
1. 是什么
grpc-gateway
是 protobuf
生成器 protoc
的一个插件。
2. 能做什么
在 protobuf
的定义文件中添加 google.api.http
注解,grpc-gateway
可以读取 protobuf
定义文件并且生成反向代理服务,用来将 RESTful JSON
接口转换为gRPC
格式。
3. 安装
grpc-gateway
依赖 ProtocolBuffer
,需要先安装 ProtoBuffer
:
1 | mkdir tmp |
安装 grpc-gateway
:
1 | # 下载 genproto |
三 完整示例
创建一个 SayHi 服务,接收 name
参数并返回 echo
消息。
1. 定义 gRPC
服务
创建 say_hi.proto
文件,文件内容如下:
1 | syntax = "proto3"; |
2. 生成 gRPC
桩代码
1 | protoc -I/usr/local/include -I. \ |
执行完命令后会生成 proto/say_hi.pb.go
桩代码文件。
3. 生成反向代理服务
1 | protoc -I/usr/local/include -I. \ |
执行完命令后将生成 proto/sai_hi.pb.gw.go
反向代理文件。
4. 实现服务端接口
1 | package srv |
以上只需按一般方式实现 grpc server
。
5. 将反向代理服务与 grpc server
关联
1 | package main |
6. 编译测试
1 | go build main.go |
四 深入grpc-gateway
内部实现
在完整示例部分展示了如何将 HTTP
服务与 grpc
服务关联起来,其中的关键代码在下面:
1 | err := gw.RegisterSayHiHandlerFromEndpoint(ctx, mux, grpcAddr, opts) |
其调用过程为:
1 | st=>start: main |
1. RegisterSayHiHandlerFromEndpoint
1 | // RegisterSayHiHandlerFromEndpoint is same as RegisterSayHiHandler but |
这个函数的主要功能是创建一个 grpc
连接 conn
,并将其作为参数传递给 RegisterSayHiHandler
函数,ctx
在整个调用过链中是为了保证在主调用协程关闭时(调用了 cancel
方法)进行资源清理。
2. RegisterSayHiHandlerClient
1 | // RegisterSayHiHandler registers the http handlers for service SayHi to "mux". |
3. RegisterSayHiHandlerClient
1 | // RegisterSayHiHandlerClient registers the http handlers for service SayHi |
本函数是功能的核心,用来将服务接口路径(pattern_SayHi_SayHi_0
)与处理函数相关联。处理函数注意有分为三个部分:将 RESTful 请求转换为 protobuf 格式、调用 grpc 接口进行处理、将 protobuf 应答转换 RESTful 格式应答并发送给客户端。
4. 处理 HTTP
请求
以上 1 - 3 都在将请求之前的配置过程,在 HTTP
请求到来时怎么做呢?其实核心还是在 ServeMux
中,ServeMux
实现了 net/http.Handler
接口,主程序中已经通过代码 http.ListenAndServe(httpAddr, mux)
将 mux
设置为 HTTP
处理接口。
1 | // ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.Path. |
五 总结
grpc-gateway
的本质是启动另外一个 HTTP
服务,用来将 HTTP
协议请求转换为 grpc
格式请求。
在 ServeMux
中 Handler
的存储结构为 slice
,如果 Handler
过多会成为性能瓶颈。
六 其他说明
ServeMux
ServeMux(grpc-ecosystem/grpc-gateway/runtime.ServeMux
)是 grpc-gateway
的请求多路复用器,用来匹配 HTTP
请求并调用相应的处理函数。