HTTP 协议
协议的要素包括:
- 明确的边界(开始、结束)
- 携带的信息(信息类型、内容)
HTTP 协议框架设计与实现
分层设计
应用层 Application
提供合理的 API
- 可理解性:如
ctx.getBody() - 简单性:如
ctx.GetHeader(name)而不是ctx.Request.Header.Peek(name) - 冗余性:减少冗余接口
- 兼容性
- 可测性:可测试
- 可见性:保证安全性
中间件 Middleware
将核心逻辑与通用逻辑分离
- 配合 Handler 实现完整请求处理生命周期
- 预处理、后处理逻辑
- 支持多中间件
- 对上层模块用户逻辑模块易用
- 使用
next()之类统一方法调用下一个中间件:后处理逻辑、在同一个调用栈上的逻辑 - 主动帮助用户调用下一个中间件:初始化逻辑,在不同调用栈上的逻辑
- 停止之后的中间件调用:
路由层 Route
- 静态路由
- 参数路由:
:,* - 路由修复:自动识别末尾是否存在
/并修复 - 优先级处理
- 匹配 HTTP 方法(GET,POST...)
- 多处理函数:便于添加中间件
实现方式:
- map
- 快,简单
- 不支持参数路由
- 前缀匹配树
协议层 Codec
核心:抽象出合适的接口
- 不存储上下文,由上层传入上下文
- 需要在连接上写入数据
- 需要给用户感知错误
网路层 Transport
选择 BIO、NIO
公共层
存放公共逻辑
HTTP 框架优化
针对网络库的优化
go net:存下全部 Header,减少系统调用,复用内存,多次读- 绑定一个
bufio
- 绑定一个
netpoll:存下完整 Header,Body- 分配足够大的
buffer,先在底层将请求拼装好 - 限制最大的
buffer
- 分配足够大的
底层包的选择:
go net:针对流式友好(Read 由用户调用),对小包性能友好(连接上绑定了一个小内存)nepoll:对中大包性能好,时延低
针对协议的优化
Header
- 找到边界:两个连续的
\r\n,使用 SIMD(go 自动使用) - 解析 Header:使用首字母筛掉不可能的
key- 使用
byte slice存储 - 对于常用的 Header 对应到独立的字段
- 缺点:没有 map 结构,不常用的 Header 比较难用
- 使用
- HeaderKey 规范化(大小写):表映射
热点资源池化
维护一个 RequestContext 池,减少 GC 压力,提高内存复用
- 额外 reset 操作
- 请求外数据不可靠
- 问题定位难度增加(低并发难以复现)
企业实践
实践中,框架追求(权衡)的东西:
- 性能
- 易用性,减少误用
- 打通内外部生态
- 文档、用户群建设