一 概述
本文主要介绍 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 请求并调用相应的处理函数。