本次笔记主要围绕第四节课——HTTP框架修炼之道展开
1 走进HTTP协议
第一节课为HTTP协议的基本介绍,给刚入门的人梳理更清晰的知识点,让人能快速回忆起来。 超文本传输协议最开始起源于通网后将两台PC端之间互相交流和分享点什么东西,于是通过网线将两台PC端连接起来,在网线上传输0和1,实现了网络文本传输,随着进一步发展逐渐有了图片、音乐、视频、超文本的传输需求,这些资源针对text是一种扩充,于是被称为超文本,传输这种资源的协议就叫做hypertext transfer protocol。
1.1 为什么需要协议
在网线上传输的都是0和1的数据,需要一定规则才能让对方理解,具体需要:
- 明确的边界即开始和结束
- 能够携带信息即什么消息,消息类型等
1.2 协议里有什么
- 请求行/状态行:请求行包括方法名(常见方法名有GET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH,GET是HTTP0.9协议里唯一的一个;1.0扩充了HEAD和POST;PUT、DELETE、CONNECT、OPTIONS、TRACE扩充在1.1里面,PATCH在1.1之后额外增加的一个使用比较广泛的方法,PATCH对应部分更新且不是幂等的,PUT对应完整更新且是幂等的)、URL、协议版本。状态行包括协议版本、状态码(1xx:信息类、2xx:成功、3xx:重定义、4xx:客户端错误、5xx:服务端错误)、状态码描述。
- 请求头/响应头:主要分为协议约定和业务相关的部分,比如content-length去指定包里有多少个字节属于协议相关,业务相关的就是自己去定义自己需要传输的源数据了。
- 请求体/响应体
1.3 请求流程
主要分为业务层、服务治理层中间件层、路由层、协议编(解)码层、传输层。在业务层,业务方使用框架提供API去完成业务逻辑,完成业务逻辑之后会进入服务治理的逻辑,服务治理层会存在一些垄断,限流等,服务治理层是依托于中间件层,中间件层对每一个业务层都有一个先后处理的逻辑,是和请求级别绑定的,服务治理也不例外,比如打一个计时的点,进入业务层之前记录一下当前的时间,在业务层执行完毕之后,再记录一下业务执行完毕的时间,再进行一个上报,这样可以记录整个业务逻辑的耗时。之后进入协议编解码,变成别人能看懂的东西。
1.4 不足与展望
- HTTP1:队头阻塞、传输效率低、明文传输不安全(基于TCP)
- HTTP2:多路复用、头部压缩、二进制协议
- QUIC:基于UDP实现、解决队头阻塞、加密减少握手次数、支持快速启动
2 HTTP框架的设计与实现
2.1 分层设计
进行分层设计的时候考虑的一些点:高内聚、低耦合、易复用、高扩展性,这个架构分为五层,层与层之间接口连接,最顶上是应用层,直接跟用户打交道的一层,提供丰富的API。下一层是中间件层,对用户有一些预处理和后处理的逻辑。路由层会有一个原生的路由曲线,提供注册、寻址相关的操作。协议层,有了这一层只要实现对应的接口,就能完成协议的扩展了。最后是网络层,不同的网络库使用场景并不相同,需要有灵活替换网络库的能力,comments会放一些公共逻辑,每一层都会使用。
- 应用层设计主要提供合理的API,具有可理解性,简单性,不要冗余性,兼容性,可测性,可见性。
- 中间件设计需要
- 配合Handler实现一个完整的请求处理生命周期
- 拥有预处理逻辑和后处理逻辑
- 可以注册多中间件
- 对上层模块用户逻辑模块易用
- 路由设计中框架路由实际上就是为URL匹配对应的处理函数(Handlers)
- 静态路由:/a/b/c、/a/b/d
- 参数路由:/a/:id/c (/a/b/c, /a/d/c)、/*all
- 路由修复:/a/b <-> /a/b/
- 冲突路由以及优先级:/a/b、/:id/c
- 匹配HTTP方法
- 多处理函数:方便添加中间件
- ...
- 协议层设计
- 抽象出合适的接口
- 网络层设计(传输层)
- BIO(超时,会卡在读数据这里)
- NIO(设置一个监听器,在监听到有足够的数据之后再去唤醒下面的function)
3 性能修炼之道与企业实践
3.1 针对网络库的优化
- go net “BIO”(流式友好、小包性能高)
- 存下全部的Header
- 减少系统调用次数
- 能够复用内存
- 能够多次读
- 可以绑定一块缓冲区go net with bufio netpoll(中大包性能高、时延低)
- 存下全部Header
- 拷贝出完整的Body netpoll with nocopy peek
- 分配足够大的buffer
- 限制最大buffer size
3.2 针对协议的优化
- 找到Header Line边界:\r\n
- 先找到\n再看它前一个是不是\r 采用SIMD更快:Sonic:
- 针对协议相关的Header快速解析:
- 通过Header key首字母快速筛除掉完全不可能的key
- 解析对应value到独立字段
- 使用byte slice管理对应header存储,方便复用。请求体中同样处理的Key:User-Agent、Content-Type、Content-Length、Connection、Transfer-Encoding
最后:追求性能;追求易用,减少误用;打通内部生态;文档建设、用户群建设