这是我参与「第五届青训营 」笔记创作活动的第13天
一、本堂课重点内容:
1、HTTP 协议
2、HTTP框架的设计与实现
3、性能修炼之道
4、企业实践
二、详细知识点介绍:
1、HTTP协议
HTTP协议是什么
为什么需要协议
协议里有什么
一个例子:
代码:
package main
/*
开启一个http服务
*/
import (
"fmt"
"net/http"
)
func main() {
fmt.Println("ok")
http.Handle("/", http.FileServer(http.Dir(".")))
http.ListenAndServe("localhost:8080", nil)
}
测试:
请求流程
不足与展望
HTTP1
队头阻塞
传输效率低
明文传输不安全
HTTP2
多路复用
头部压缩
二进制协议
QUIC
基于UDP实现
解决队头阻塞
加名味启
支持快速启动
2、HTTP 框架的设计与实现
分层设计
一个切实可行的复杂系统势必是从一个切实可行的简单系统发展而来的。从头开始设计的复杂系统根本不切实可行,无法修修补补让它切实可行。你必须由一个切实可行的简单系统重新开始。 ———盖尔定律
提高专注性、扩展性、复用性
特点:
高内聚、低耦合、易复用、高扩展性
应用层设计:
提供合理的 API
1、可理解性:如ctx.Body (), ctx.GetBody () ,不要用ctx.BodyA()
2、简单性:如ctx.Request.Header. Peek (key)/ctx.GetHeader (key)
不要试图在文档中说明,很多用户不看文档
中间件设置
中间件需求:
1、配合Handler实现一个完整的请求处理生命周期
2、拥有预处理逻辑与后处理逻辑
3、可以注册多中问件
4、对上层模块用户逻辑模块易用
洋葱模型:
调用链:
适用场景:
1、不调用 Next:初始化逻辑且不需要在同一调用栈
2、调用 Next:后处理逻辑或需要在同一调用栈上
路由设计:
框架路由实际上就是为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 多处理函数:
方便添加中间件 ...
设计:
青铜:
map[string]handlers/a/b/c、/a/b/d/a/ :id/c、/*all
黄金:
前缀匹配树
/a/b/c、/a/b/d
如何做设计
1.明确需求:考虑清楚要解决什么问题、有哪些需求
2.业界调研:业界都有哪些解决方案可供参考
3.方案权衡:思考不同方案的取舍
4.方案评审:相关同学对不同方案做评审
5.确定开发:确定最合适的方案进行开发
协议层设计:抽象出合适的接口
网络层设计:网络模型
3、性能修炼之道
针对网络库的优化:
不同网络库的优势:
go net
流式友好、小包性能高
优化:存下全部 Header减少系统调用次数能够复用内存能够多次读。
netpoll
中大包性能高、时延低
优化:存下全部Header拷贝出完整的 Body。
针对协议的优化——Headers 解析:
针对协议相关的 Headers快速解析:
1.通过Header key首字母快速筛除掉完全不可能的key
2.解析对应value 到独立字段
3.使用byte slice管理对应header 存储,方便复用
优化中的取舍:
取
1、核心字段快速解析
2、使用byte slice存储
3、额外存储到成员变量中
舍
1、普通header 性能较低
2、没有map 结构
针对协议的优化——Header key规范化
规范:aaa-bbb ——Aaa-Bbb
优化中的取舍:
取
超高的转换效率比net.http 提高40倍
舍
额外的内存开销
变更困难
热点资源池化
优化中的取舍:
取
减少了内存分配
提高了内存复用
降低了GC压力
性能提升
舍
额外的 Reset逻辑
请求内有效
问题定位难度增加
三、课后个人总结:
此节课从http协议低层出发,讲解了http协议的设计原理、http协议的优化。后又讲解性能优化,网络库和池化技术也十分重要。