HTTP框架修炼之道|青训营笔记

93 阅读3分钟

HTTP框架修炼之道

这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记

[TOC]

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, ARP IP数据报
网络接口层 数据链路层 数据链路层 链路控制和媒体访问
物理层 物理层 以太网

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

分层设计时需要考虑到:

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

应用层设计

应用层主要包括: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

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

type Server interface {
    Serve(c context.Context, conn network.Conn) error
}

网络层设计

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

BIO和NIO

BIO:Block IO 阻塞IO

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

            // handle ...

            conn.Write(response)
        }()
    }
}

NIO:Non-Blocking IO

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存储,方便复用