Post

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

  1. read request 一次连接允许多个请求, 因此无限制等待请求到来
    1. read header
    2. read body
  2. handle request 并发处理请求
    1. resp, err := call service method(req)
  3. send response 响应必须逐个发送

客户端

  • net/http规定一个函数支持rpc需要满足
    • func (t *T) Method(req T1, resp *T2) error
  • client有发送请求, 接收响应两大功能
  • 接收响应
    • resp可能出现的情况
      1. call在client中不存在, 发送的请求可能没有发送完整或者中途取消了, 但是server仍接收到了这个call
      2. server出错, resp.header出现error
      3. resp正常, 然后client需要读出resq.body
  • client发送请求是有序互斥的
    1. 建立连接发送Option, 协商报文细节
    2. 有序发送报文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时

支持HTTP协议

  • rpc不止可以使用TCP, 也支持HTTP协议
    • RPC报文格式和标准HTTP格式不兼容, 采用协议转换
  • 通过CONNECT报文实现
    • CONNECT报文用于代理服务
      • client -CONNECT-> 代理服务器 -建立隧道-> 目标服务器
      • client -发送请求-> 代理服务器 -转发-> 目标服务器
    • 允许client通过代理服务器与目标服务器建立一条直接的TCP连接, 用于传输非HTTP协议的数据
    • 用途
      • HTTPS的代理转发、websocket的代理转发等
  • http协议转转换到rpc的实现
    • conn, _, err := w.(http.Hijacker).Hijack() 获取了tcp套接字
      • Hijack了http的tcp连接来做conn
  • 使用http协议进行转换的优点
    • 支持添加不同路径提供不同服务
      • 对于一个server也许除了提供rpc服务外还提供其他服务
        • 提供rpc服务外, 也提供了一个rpc debug的api服务, 如果不支持不同path提供不同服务的话, 这个api服务就必须放在另一个port上

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)的处理是要互斥的

注册中心

  • 常见的注册中心etcd、zookeeper
  • 提供服务注册、接收心跳、服务发现功能(basic function)
  • 整体流程
    • overall
  • 服务注册
    • 将结构体映射为Service, struct实现的func映射为Method, Method参数映射成Req.Args和*Resp.Replyv
      • 通过反射实现映射, 也通过反射实现call method
This post is licensed under CC BY 4.0 by the author.