HTTP框架修炼之道| 青训营

52 阅读3分钟

HTTP协议

HTTP协议是什么

超文本传输协议 Hypertext Transfer Protocol

为什么需要协议:需要一个明确的规则用于传输信息

HTTP协议里有什么

  • 请求行/状态行
  • 请求头/响应头
  • 请求体/响应体

不足与展望

  • HTTP1

    1. 队头阻塞
    2. 传输效率低
    3. 明文传输不安全
  • HTTP2

    1. 多路复用
    2. 头部压缩
    3. 二进制协议
  • QUIC

    1. 基于UDP实现
    2. 解决队头阻塞
    3. 加密减少握手次数
    4. 支持快速启动

HTTP框架的设计与实现

分层设计

TCP/IP 4层TCP/IP 5层OSI 7层主要功能传递对象
应用层应用层应用层SMTP, FTP, Telnet, DNS, TFTP, RPC etc报文
表示层
会话层
应用层应用层传输层TCP, UDP传输协议分组
网络层网络层网络层IP, ARPIP数据报
网络接口层数据链路层数据链路层链路控制和媒体访问
物理层物理层以太网

分层设计提升了系统设计的专注性、扩展性、复用性

分层设计时需要考虑到:

  • 高内聚,低耦合
  • 易复用
  • 高扩展性

应用层设计

应用层主要包括:Context、Request、Response、Handler

设计应用层的主要目的是提供合理的API

  • 可理解性

  • 简单性

    常用的API放到上层,无用/低频的API放到下层

  • 冗余性

    不需要冗余,或能通过多个API组合实现功能

  • 兼容性

    尽量避免Break change

  • 可测性

  • 可见性

    最小暴露原则

中间件设计

中间件层主要包括:Recovery、CircuitBreak、Timeout、AccessLog

中间件层需求:

  • 配合Handler实现一个完整的请求处理生命周期
  • 拥有预处理逻辑和后处理逻辑
  • 可以注册多个中间件
  • 对上层模块用户逻辑模块易用

中间件层通常采用“洋葱模型”

一个请求首先以此通过日志中间件、Metrics中间件,然后在Handler获取响应,然后经历后处理逻辑再传递出去,洋葱模型极大提高了组件的复用性

常见的适用场景:

  • 日志记录
  • 性能统计
  • 安全控制
  • 事务处理
  • 异常处理

路由层设计

路由层主要包括:Add、Find、Route Tree、Route Group

框架路由实际上就是为了URL匹配对应的处理函数

功能点实现
静态路由/a/b/c /a/b/d
参数路由/a/:id/c /*all
路由修复/a/b <-> /a/b/
冲突路由以及优先级/a/b /:id/c
匹配HTTP方法
多处理函数方便添加中间件

使用的数据结构:前缀匹配树

协议层设计

协议层主要包括:WebSocket、HTTP1、Quic、HTTP2

协议层设计的主要方式:抽象出合适的接口

go
复制代码
go
复制代码
type Server interface {
    Serve(c context.Context, conn network.Conn) error
}

网络层设计

网络层主要包括: netpoll, go net

BIO和NIO

BIO:Block IO 阻塞IO

go
复制代码
go
复制代码
go func() {
    for {
        conn, _ := listener.Accept()
        go func () {
            conn.Read(request)

            // handle ...

            conn.Write(response)
        }()
    }
}

NIO:Non-Blocking IO

go
复制代码
go
复制代码
go func () {
    for {
        readableConns, _ := Monitor(conns)
        for conn := range readableConns {
            go func () {
                conn.Read(request)

                // handle ...

                conn.Write(response)
            }()
        }
    }
}

NIO通过监听器实现不会像BIO一样阻塞

性能

针对网络库的优化

go net

  • 存下全部的Header
  • 减少系统调用次数
  • 能够复用内存
  • 能够多次读

netpoll

  • 存下全部的Header
  • 拷贝完整的Body

不同网络库的优势

网络库优势
go net流式友好,小包性能高
netpoll中大包性能高,时延低

针对协议的优化

Header解析

  • 通过Header Key首字母快速筛除完全不可能的Key
  • 解析对应value到对应字段
  • 用Byte slice管理对应的header存储,方便复用

引用 HTTP框架修炼之道