Go RPC workframe
Go RPC workframe
RPC Framework Project
Introduction
- what`s rpc
- 远程过程调用, 可以基于HTTP、TCP等
- 与之相比较的是RESTful api(基于HTTP), 如今二者的区别越来越小
- rpc更灵活, 性能更好, 更高效; RESTful api可读性更好, 兼容性更好
Function
- 确定传输协议
- 一般是TCP或HTTP
- 确定报文编码格式
- JSON、gob、protobuf
- 编码->压缩->解压->解码
- 可用性问题
- 超时处理
- 异步请求和并发
- 注册中心
- 心跳功能
- 负载均衡
- 在net/rpc标准库上增添了
协议交换,注册中心,服务发现,负载均衡,超时处理等特性,
Detail
编码格式
- 报文格式为
Option{magic number(校验), codec type: 编码格式(JSON/gob等)} | Header{service method name ...} | Body(request/response)- 对于client发送的报文body是req.Args; 对于server发送的报文body是resq.Replyv
- client和server通过header确定调用的哪个method, 并且保证请求的顺序(在client中通过seq记录call)
- Option自身的编码格式是固定的, Option中协商的编码格式是header和body的格式
- 一次连接中, Option在报文的最开始, header和body可以有多个
option|header1|body1|header2|body2|...
Server
- read request 一次连接允许多个请求, 因此无限制等待请求到来
- read header
- read body
- handle request 并发处理请求
- resp, err := call service method(req)
- send response 响应必须逐个发送
客户端
- net/http规定一个函数支持rpc需要满足
- func (t *T) Method(req T1, resp *T2) error
- client有发送请求, 接收响应两大功能
- 接收响应
- resp可能出现的情况
- call在client中不存在, 发送的请求可能没有发送完整或者中途取消了, 但是server仍接收到了这个call
- server出错, resp.header出现error
- resp正常, 然后client需要读出resq.body
- resp可能出现的情况
- client发送请求是有序互斥的
- 建立连接发送Option, 协商报文细节
- 有序发送报文
header | body, 报文互斥发送, 避免不同请求的header和body混淆
超时处理
- 实现超时返回的常见方法有context.WithTimeout和time.After
- rpc framework处理超时的场景
- client
- 与server建立连接时
- 发送请求时, 写报文超时
- 等待server响应时, (server挂了等情况)
- 接收响应时, 读报文超时
- server
- 读请求报文时, 读报文超时
- 发送响应时, 写报文超时
- 处理call时, 执行method超时
- 在三个地方添加了超时处理
- client创建连接时
- client.Call时(包括send request、wait handle、recive response)
- server handleRequest时
- client
支持HTTP协议
- rpc不止可以使用TCP, 也支持HTTP协议
- RPC报文格式和标准HTTP格式不兼容, 采用协议转换
- 通过CONNECT报文实现
- CONNECT报文用于代理服务
- client -
CONNECT-> 代理服务器 -建立隧道-> 目标服务器 - client -
发送请求-> 代理服务器 -转发-> 目标服务器
- client -
- 允许client通过代理服务器与目标服务器建立一条直接的TCP连接, 用于传输非HTTP协议的数据
- 用途
- HTTPS的代理转发、websocket的代理转发等
- CONNECT报文用于代理服务
- http协议转转换到rpc的实现
- conn, _, err := w.(http.Hijacker).Hijack() 获取了tcp套接字
- Hijack了http的tcp连接来做conn
- conn, _, err := w.(http.Hijacker).Hijack() 获取了tcp套接字
- 使用http协议进行转换的优点
- 支持添加不同路径提供不同服务
- 对于一个server也许除了提供rpc服务外还提供其他服务
- 提供rpc服务外, 也提供了一个rpc debug的api服务, 如果不支持不同path提供不同服务的话, 这个api服务就必须放在另一个port上
- 对于一个server也许除了提供rpc服务外还提供其他服务
- 支持添加不同路径提供不同服务
websocket
- http1.1是半双工的(tcp本身是全双工的), 不支持server push, 不适合如实时通信等场景, 因此有了websocket这个利用tcp全双工的协议
建立websocket连接
- websocket利用了http协议的连接过程, 先完成tcp三次握手, 然后发送带有upgrate字段的http header进行协议升级
- 升级后的websocket与http就没有关系了, 之后用websocket报文进行通信
- 服务器支持websocket则会进行websocket握手, 返回状态码101(协议转换)的resp
- 服务器通过某种公开算法将Sec-WebSocket-Key(base64)转换成另一字符串, client同样进行转换, 并将结果和服务器转换的结果进行比较, 如果一致, 则建立websocket成功
req和resp报文
1
2
3
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2
1
2
3
4
HTTP/1.1 101 Switching Protocols\r\n
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA
Upgrade: WebSocket\r\n
Connection: Upgrade\r\n
负载均衡
- random、轮询、一致性哈希等
- 支持广播功能Broadcast
- 将请求广播到所有服务实例上, 如果任意一个实例发生错误, 则返回其中一个错误; 如果调用成功, 返回其中一个结果
- 广播的请求时并发的, 但是对返回值(replyv and error)的处理是要互斥的
注册中心
This post is licensed under CC BY 4.0 by the author.
