极客时间——深入浅出grpc
目录:
0 gRPC入门
RPC框架的目的是让远程调用变得简单和透明,负责屏蔽底层的传输方式、序列化方式和通信细节。服务可以通过调用本地端口的方式调用远程服务提供者
业界主流的rpc框架分为三类
- 多语言的rpc框架,例如grpc,Thrift
- 只支持特定的语言的rpc框架,例如Motan
- 支持服务治理等服务化特性的分布式服务框架,底层依然是RPC框架,例如dubbo
随着微服务发展,语言的中立性原则构建微服务称为主流趋势
grpc是一个高性能,开源和通用的RPC框架,面向服务端和移动端,基础HTTP/2设计,支持C,Java和Go
grpc的特点
- 语言中立
- 基于IDL文件定义服务,通过proto3工具生成指定语言的数据结构,服务端接口以及客户端Stub,和RPC使用动态代理和反射机制进行调用对比性能更好
- 通信协议基于HTTP/2设计,支持双向流、消息头压缩、单TCP多路复用、Server端推送等特性,使得支持移动端更加省点和节省网络流量(这里的Server端推送是对响应的持续推送)
- 序列化支持ProtocolBuffer
1 服务端创建和调用原理
服务端创建流程
- 创建HTTP2Server
- 将调用的服务端接口实现注册到内部的registry,RPC调用的时候,可以根据RPC请求中定义的服务信息查询到服务接口实现方法
- 创建gPRCServer,聚合各种Listener,用于RPC消息的统一调度和处理
服务端调用流程
- gRPC接收请求
- gRPC消息头和消息体的处理
- 内部路由和调用
- 响应消息发送
gRPC消息头和消息体的处理
- Header的Content-Type必须为"application/grpc"
- Header的URL中提取接口和方法名,例如"helloworld.Greeter/SayHello"
- 将Header转为gRPC的内部metadata
- 创建stream对象,实现协议消息处理,并完成消息上下文和grpc监听器的创建
- 如果Header的grpc-timeout,会启动延时任务
内部路由和调用
- 将body序列化为IDL定义的请求参数对象
- 根据Header中的方法到注册中心查询对应的服务定义
- 调用对应的注册方法
2 客户端创建和调用原理
Client调用流程
- 发起RPC调用
- 进行域名解析获取地址列表,使用负载策略,选择一个具体的gRPCServer实例
- 如果与Server端没有可用的连接,则发起HTTP/2连接
- 对请求消息做protobuf做序列化,通过HTTP/2的stream发送给gRPCServer
- 接收到Server响应之后,使用protobuf反序列化
- 唤醒Client线程获取RPC响应
http2在tcp连接的时候会进行协议的协商版本标识为2种
- 基于TLS的HTTP2,即HTTPS,为h2
- 直接使用TCP的HTTP2,即HTTP,为h2c
http2的连接创建方式
- 协商升级
- 直接连接
如果不知道服务端是否支持HTTP2,可以用HTTP1.1进行协商,报文如下
GET / HTTP/1.1
Host: 127.0.0.1
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
如果不支持HTTP2则会按照HTTP1.1响应,双方通过HTTP1.1通信
HTTP/1.1 200 OK
Content-Length: 28
Content-Type: text/css
body...
如果服务器支持HTTP2,协商成功返回101状态码,通知Client升级为HTTP2通信
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
[ HTTP/2 connection...
101响应之后,Server端发送SETTINGS帧作为连接序言,Client接收到101响应之后也会发送连接序言
PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
SETTINGS帧
Client发送了连接序言之后,可以不等待Server的SETTINGS帧直接发送业务请求的Frame
如果知道对端支持HTTP2,则可以在TCP连接完成直接发送序言
负载策略,支持两种
- 使用第一个
- rr