这是我参与「第五届青训营 」伴学笔记创作活动的第 20 天
本篇文章归档于 “第五届字节跳动青训营”,主要是为了完成和记录掘金的 “伴学笔记创作活动” 活动,如果你对我的其他文章感兴趣,可以去我的 专栏 中逛逛看有没有你想要的东西。
- 第 1 篇 - Kitex 口水话
- 第 2 篇 - Hertz 口水话
- 第 3 篇 - 微服务口水话
- 第 4 篇 - Kafka 口水话
- 第 5 篇 - BMQ 口水话
- 第 6 篇 - RecketMQ 口水话
- 第 7 篇 - 数据库口水话
- 第 8 篇 - RDBMS 口水话
- 第 9 篇 - TOS 口水话
- 第 10 篇 - tinyTikTok 环境配置
- 第 11 篇 - tinyTikTok 规范设计
- 第 12 篇 - tinyTikTok 项目管理
- 第 13 篇 - tinyTikTok 认证授权
- 第 14 篇 - tinyTikTok 服务功能
- 第 15 篇 - tinyTikTok 测试分析
- 第 16 篇 - tinyTikTok 项目总结
HTTP 的相关概念
关于 HTTP(Hypertext Transfer Protocol),很多面试官会把它与 RPC、TCP 之类的混在一起考察。但实际上,HTTP 作为应用层的协议,从操作系统的角度来看仅存在于用户态,本质相差甚远,更多知识也建议出门右转 Google,这里简单记录一点概念:
- 请求行/状态行:方法名、URL、协议版本、状态码、状态码描述;
- 请求头/响应头:协议约定相关业务;
- 请求体/响应体:更多信息。
HTTP 在应用层的请求流程:
- 业务层:实现业务逻辑;
- 服务治理层:可以自己实现,也可以利用中间件进行服务治理;
- 路由层:为 URL 和处理函数设计匹配策略;
- 编解码层:将协议编解码为字节流进行传输。
HTTP 的演化之路:
- HTTP 1.0 -> HTTP 1.1:
- 短连接改为长连接
- 支持管道传输 -> 可能导致 HTTP 队头阻塞
- HTTP 1.1 -> HTTP 2.0:
- 头部压缩
- 二进制格式
- 多路复用(并发传输 Stream)-> 可能导致 TCP 队头阻塞
- 服务推送(Server 主动连接 Client)
- HTTP 2.0 -> HTTP 3.0:
- UDP 替代 TCP,使用 QUIC
- 解决 TCP 队头阻塞
- 加密减少 3 次握手次数
- 连接迁移(连接 ID)
Anyway,还有很多如缓存策略等细节没有提及,有空可以自行 Google~
HTTP 的分层设计
分层设计的核心:高内聚、低耦合,易复用和高扩展性,系统设计应由简至繁。
这一部分的课程感觉很注重实践,和之前的开发经历产生了很多共鸣,可以反复体会一下,这里就简单归纳一下:
- 应用层:API 的可读性(特别是对于开源项目来说,这能极大地降低维护成本),兼容性,可观测,可测试,可扩展;
- 服务治理层:保障完整的生命周期,预处理和后处理,多中间件可插拔,易用性;
- 路由层:静态路由,参数路由,路由修复,冲突和优先级,HTTP 匹配和多处理函数;
- 编解码层:抽象合适的接口,应该传递上下文,而非嵌入,在连接上读取数据;
- 传输层:BIO、AIO 和 NIO 之类的网络模型。
总的来说,在进行分层设计时,应该:明确需求 -> 业界调研 ->方案权衡 -> 方案评审 -> 确定开发
HTTP 的性能优化
课程里谈到了两方面的优化:网络库和协议。网络库的优化就是之前提到的 Netpoll,这里不再赘述啦。我们看看 Hertz 是如何对协议进行优化的:
- Headers 解析:找到特征边界
\n\r,通过 key 的首字母筛除 key,解析对应的 value 并使用 byte slice 进行管理;-> 核心字段快速解析,额外存储负担,普通 Header 性能低(无 map) - Header key 规范化:表映射;-> 高转换率,额外内存负担,变更困难
- 热点资源池化。-> 减少内存分配、GC 压力,提高内存复用、性能,需要额外的 Reset 逻辑,问题难定位,请求内有效
顺便记录一下一些思考,后面会进行解答:
- 为什么HTTP框架做要分层设计?分层设计有哪些优势与劣势;
- 现有开源社区HTTP框架有哪些优势与不足;
- 中间件还有没有其他实现方式?可以用伪代码说明;
- 完成基于前缀路由树的注册与查找功能?可以用伪代码说明;
- 路由还有没有其他的实现方式?
Hertz 架构
之前的内容已经提到了 Hertz 的一些优化思路,这里就直接上官网链接(中文)啦:
最后想说的话
追求性能会不可避免地让上手难度增加,以及生态建设缓慢,但这些优化思路还是蛮有意思的,值得回味。