这是我参与「第三届青训营 -后端场」笔记创作活动的的第14篇笔记
- 再谈HTTP协议
- HTTP协议是什么
- HTTP:超文本传输协议(Hypertext Transfer Protocol)
- 为什么需要协议
- 需要明确的边界
- 开始
- 结束
- 协议元数据
- 能够携带信息
- 消息内容
- 消息类型
- 能够携带信息
- 需要明确的边界
- 协议里有什么
- 请求行
- 方法名
- URL
- 协议版本
- 状态行
- 协议版本
- 状态码
- 状态码描述
- 请求头/响应头
- 协议相关
- 业务相关
- 请求体/响应体
- 请求行
- 请求流程
- 业务层
- 服务治理层/中间件层
- 路由层
- 协议编解码层
- 传输层
- 不足与展望
- HTTP1
- 队头阻塞
- 传输效率低
- 明文传输不安全
- HTTP2
- 多路复用
- 头部压缩
- 二进制协议
- QUIC
- 基于UDP实现
- 解决队头阻塞
- 加密减少握手次数
- 支持快速启动
- HTTP1
- HTTP协议是什么
- HTTP框架的设计与实现
- 分层设计
- 专注性
- 扩展性
- 复用性
- 高内聚 低耦合
- 易复用
- 高扩展性
- 应用层设计
- 提供合理的API
- 可理解性
- 简单性
- 冗余性
- 兼容性
- 可测性
- 可见性
- 提供合理的API
- 中间件层
- 需求
- 配合Handler实现一个完整的请求处理生命周期
- 拥有预处理逻辑与后处理逻辑
- 可以注册多中间件
- 对上层模块用户逻辑模块易用
- 洋葱模型
- 核心逻辑与通用逻辑分离
- 适用场景
- 日志记录
- 性能统计
- 安全控制
- 事务处理
- 异常处理
- 需求
- 路由设计
- 框架路由实际上就是为URL匹配对应的处理函数
- 静态路由
- 参数路由
- 路由修复
- 冲突路由以及优先级
- 匹配HTTP方法
- 多处理函数:方便添加中间件
- 前缀匹配树
- 如何匹配HTTP方法
- 外层Map:根据method进行初步筛选
- 如何实现添加多处理函数
- 在每个节点上使用一个list存储handler
- 如何查找路由
- 如何匹配HTTP方法
- 框架路由实际上就是为URL匹配对应的处理函数
- 协议层
- 抽象出合适接口
type Server interface{ Serve(c context.Context, conn network.Conn) error } - 网络层
BIO:Block IO 阻塞IO
go func(){ for{ conn,_ := listener.Accept() go func(){ conn.Read(request) handle... conn.Write(response) } } }NIO:
go func(){ for{ readableConns,_ := Monitor(conns) for conn := range readableConns{ go func(){ conn.Read(request) handle... conn.Write(response) }() } } }- 设计
netpollNIO- 网络库管理buffer
- 分层设计
- 性能修炼之道
- 针对网络库的优化
- 存下全部Header
- 减少系统调用次数
- 能够复用内存
- 能够多次读
- go net with bufio
- 绑定一块缓冲区
- netpoll
- 存下全部Header
- 拷贝出完整Body
- netpoll with nocopy peek
- 分配足够大的buffer
- 限制最大buffer size
- 不同网络库优势
- go net
- 流式友好
- 小包性能高
- netpoll
- 中大包性能高
- 时延低
- go net
- 针对协议的优化
- Headers解析
- 找到Header Line边界:\r\n
- 先找到\n再看它前一个是不是\r
SIMD
- 针对协议相关的Headers快速解析
- 通过Header key首字母快速筛除掉完全不可能的key
- 解析对应value到独立字段
- 使用byte slice管理对应header存储,方便复用
- 找到Header Line边界:\r\n
- Header key规范化
- 映射表
- 热点资源池化
Request Context-
与请求一一对应,贯穿一个请求始终
-
- Headers解析
- 针对网络库的优化