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

99 阅读3分钟

HTTP 框架修炼之道

课程引入

http协议大家应该很熟悉了,http协议也是当今使用的最多的协议之一。

大家的课程大作业,项目也接触过。

在学校老师 只会讲到http是什么,而不会谈到底层原理。

这样在工作中是万万不够的。

01. 再谈 HTTP 协议

最开始大规模使用的HTTP协议是 v0.9

1.1 为什么需要协议

image-20230601183134606

协议有明确的边界

协议元数据:进行信息的描述,图片、音频、视频、超链接

1.2 协议里有什么

image-20230601183319920

协议开始 请求方法空格url空格协议版本

元数据 由 : 分隔的键值对

image-20230603145745778

请求回复

http版本空格状态码空格OK (OK是对应状态码200 的描述)

image-20230601191700046

各方法所在的版本(版本向下兼容)

image-20230601194102164

patch 对应部分更新

put 对应整体更新

put 具有幂等性 而patch 无幂等性

一个小demo

package main

import (
	"context"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/app/server"
)

func main() {
	h := server.New()

	h.POST("/sis", func(c context.Context, ctx *app.RequestContext) {
		ctx.Data(200, "text/plain; charset=utf-8", []byte("OK"))
	})

	h.Spin()
}

image-20230603150158984

1.3 请求流程

image-20230601193810627

1.4 不足和展望

image-20230601194022641

02. HTTP 框架的设计与实现

2.1 分层设计

image-20230601194306746

image-20230601201524520

image-20230601201809135

一个切实可行的复杂系统势必是从一个切实可行的简单系统发展而来的。从头开始设计的复杂系统根本不切实可行,无法修修补补让它切实可行。你必须由一个切实可行的简单系统重新开始。 --- 盖尔定律

2.2 应用层设计

image-20230601202433709

提供合理的 API

  • 可理解行: 如 ctx.Body() ctx.GetBody()

    ctx.BodyA() ==是不清晰的==

  • 简单性: 如 ctx.Request.Header.Peek(key)

    /ctx.GetHeader(key) ==高频==

  • 冗余性 有了ctx.Body(),就不要有ctx.GetBody() ,不要一个接口是 两个接口拼接起的

  • 兼容性

  • 可测性

  • 可见性 为了安全性 保障框架的安全性

2.3 中间件设计

image-20230601202451945

需求

  • 配合Handler实现一个完整的请求处理生命周期
  • 拥有预处理逻辑与后处理逻辑
  • 可以注册多中间件
  • 对上层模块用户逻辑模块易用

洋葱模型

image-20230601202625524

调用链

image-20230601203110991

==思考== : 有没有其他的方式来处理 中间件

2.4 路由设计

image-20230601204823048

image-20230601203229509

路由匹配

image-20230601204356735

参数路由

image-20230601204514066

匹配 HTTP 方法

构造多个路由树

image-20230601204614830

实现添加多处理函数

image-20230601204642768

==思考== 如何查找路由

总结

image-20230601204709506

2.5 协议层设计

image-20230601204831806

image-20230601204940160

2.6 网路层设计 传输层

image-20230601205006428

BIO 阻塞IO Block

NIO

红圈内 go 经典对go func的一个处理 -》 先读完了, 再进行数据的 处理

设置监听器, 当有足够的 数据后 再处理

image-20230601205055116

image-20230601205301168

go net 需要用户来管理 buffer

image-20230601205316006

字节开源 netpoll 的设计

image-20230601205458652

2.7 总结

image-20230601205702777

03. 性能修炼之道

3.1 针对网络库的优化

现状

go net 是 BIO

需求

image-20230602112656139

image-20230602113013938

3.2 针对协议的优化 --- Headers 解析

找到Header Line 边界 : \r\n

从有一定特征的字符串 中 找 杀鸡焉用牛刀

先找到\n 再看他前一个是不是\r

O(n)O(n)

image-20230602113631998

能不能更快呢?

SIMD Single Instruction Multiple Data

单指令集 多数据

一次处理多条数据

sm加速

image-20230602113907479

取舍

image-20230602114305627

3.3 Header key 规范化

image-20230602114637017

image-20230602114452262

3.4 热点资源池化

image-20230602114559257

image-20230602114708166

image-20230602114715284