第 40 期 - 网络请求全流程及相关技术解析
摘要
本文从输入 URL 开始,详细阐述网络请求涉及的 IP、DNS、CDN、TCP、协议设计、服务器模型、数据层演进等环节,还探讨了性能优化技术,梳理相关技术点并贯通前后端知识。
一、IP、DNS 和 CDN
1. IP 相关
- 首先提到了 IPv4 地址数量有限,不能为每个设备分配一个公网 IP,这就引出了局域网 IP 的概念。常见的局域网 IP 段有 10.x.x.x,172.16 - 31.x.x,192.168.x.x 等,127.0.0.1 是本地回环地址。
- 在设备从局域网连接广域网时,会用到 NAT 技术,其中端口多路复用(PAT)是常用的方式。例如,当设备在局域网内访问外部服务(如 qq)时,路由器会记录内网 IP 和端口,将其转换为路由器公网 IP 和未使用端口向公网发包,并建立映射关系,以确保响应能正确返回。
2. DNS 相关
- 对于 DNS,它的作用是将域名解析为 IP 地址。在 Windows 和 Linux 下,解析域名前会先从本地 hosts 文件查找映射关系,早期可用于切换开发环境等。
- 域名的管理方式多样,个人域名可使用云服务商(如腾讯云)的 DNS 服务器,大型门户网站可能自建 DNS 服务器,自建的好处是方便管理和提高安全等级。
- 当域名访问量较大时,可对应多个 IP 地址,但这可能存在 DNS 缓存不按 TTL 指示的问题,导致 DNS 变更生效时间长,进而影响服务可用性。为解决此问题,有了 LVS/nginx 等动态负载均衡方式,腾讯云的 CLB 选用 BGP 多线可实现多网统一接入和自动负载均衡。
3. CDN 相关
- CDN(内容分发网络)是为了提高用户访问速度。它的原理是一个域名对应多个分布在各地的 IP,DNS 服务器根据用户来源 IP 返回就近的 IP。
- CDN 主要用于 Web 静态资源的分发和加速,一般会采用动静分离的 Web 性能优化方案,将静态资源域名托管给 CDN。现在也有动态 CDN,但原理有所不同,一般不缓存数据在边缘节点。
二、TCP、消息分包和协议设计
1. TCP 是流式协议
- TCP 是一种流式协议,意味着消息之间没有边界。例如发送多条消息,接收时可能一次性收到多条消息的组合,这就需要应用逻辑自行分析完整的消息,这也是所谓的“粘包”概念。
2. 消息分包
- 由于 TCP 的流式特性,应用层需要确定完整消息的方式,即消息分包。
- 以 HTTP 协议为例,它是文本协议,用`
分割消息头和消息体,消息头中的
Content - Length告知消息体大小(GET 请求大多无消息体),响应消息头中可用
Content - Length或
Transfer - Encoding: chunked分析消息体。其他协议如 FTP/SMTP/POP3 用
`作为命令结束标志。
- 自定义协议项目中,不少选择二进制协议,其简单的分包方式是消息头 4 个字节表示消息总长度,还可加入校验方法,如规定消息头 1 个字节为固定值、消息最后 1 个字节为固定值、消息总长度放在特定字节等。
3. 协议设计
- 以 HTTP 协议为例介绍协议设计要点:
- 消息组成:由消息头 + 消息体组成,空行分割 HTTP head 和 body,HTTP 头每行以
- 消息组成:由消息头 + 消息体组成,空行分割 HTTP head 和 body,HTTP 头每行以
。 - 消息分包:如上述用
Content - Length和
Transfer - Encodeing分包。 - 消息压缩:请求中有
Accept - Encoding字段,响应中用
Content - Encoding表明压缩方式,常见为 gzip 压缩。 - 消息加密:https (SSL: Secure Socket Layer)。 - 消息 ID:URL 就是消息 ID。 - 响应状态码:不同数字定义不同响应类别,如 1xx 指示信息等。 - 协议版本号:如 HTTP/1.1 中的 1.1 就是版本号。 - 长连接:请求中
Connection: keep - alive表示希望服务器保持连接。 - 字符集:
Content - Type`字段表明字符集。
- 字符转义:URL 中的参数需要做 URL 转义处理。
4. HTTP 协议和二进制协议的对比
- 文本协议(HTTP 协议)便于人阅读、理解、调试和构造,但解析复杂、冗余多且需要考虑字符转义。
- 二进制协议便于机器,解析更高效。
- 从 Name - Based 和 Position - Based 角度看:
- Name - Based 协议(如 HTTP 协议)协议字段用 Name 标识,与位置无关、可缺省、新增字段方便,但解析复杂且需考虑字符转义。
- Position - Based 协议每个协议字段有特定位置,新增字段需做好协议版本管理(如 protobuf)。
三、CGI 和 FastCGI
1. 古老但常见的 CGI
- CGI 是 Web 服务器和外部程序之间传输数据的标准。例如一个简单的 C ++ CGI 程序,其通过 Web 服务器按照一定流程与外部程序交互。
- Web 服务器收到请求后启动 CGI 程序,通过环境变量和标准输入传递请求信息,CGI 程序执行业务逻辑后通过标准输出和标准错误返回响应数据,然后 CGI 程序退出,Web 服务器组织成 HTTP 响应包发给浏览器。
- Web 服务器会传递常用信息给 CGI 程序,如
CONTENT_LENGTH
、QUERY_STRING
等,CGI 程序可以用任何具有标准输入、标准输出和环境变量的语言编写。
2. FastCGI 应运而生
- CGI 运行性能低,因为每个请求都需 Web 服务器 fork 出 CGI 程序,且 CGI 程序每次从头运行。
- FastCGI 改进了 CGI,Web 服务器收到请求后按 FastCGI 协议通过 socket 发给 FastCGI 程序,FastCGI 程序执行业务逻辑后通过 socket 返回响应数据且不退出。
- FastCGI 程序常驻内存,启动后可反复处理请求,处理请求后不用重新解析配置、连接其他服务等,C/C ++常用 apache 的 mod_fastcgi 模块,PHP 常用 spawn - fcgi 和 PHP - FPM。
3. nginx 的反向代理
- 现在更多使用 nginx 的反向代理功能,将 HTTP 请求转发到后端的 trpc 服务,这里的 trpc 服务类似 FastCGI,但不需要与 nginx 部署在一起。
四、服务器模型谈
1. 同步通讯 vs 异步通讯
- 同步通讯在一个连接中,一个请求应答未回不能发送下一个请求,是请求 - 应答 1 - 请求 - 应答 2 的顺序。异步通讯则可随意发送请求,应答顺序可能与请求顺序不一致,同步通讯性能低于异步通讯,但更简单。
2. 同步逻辑 vs 异步逻辑
- 同步逻辑在代码中遇到等待调用时阻塞等待,异步逻辑不阻塞继续执行后续代码。常见的文件 IO 和网络 IO 接口默认是同步的,需要特殊设置才变为非阻塞,写异步逻辑有挑战。
3. 无状态 vs 有状态
- CGI/FastCGI 每次从数据层获取数据修改后写回,这是无状态的,无状态架构中请求由哪台服务器处理无区别,扩容方便但要防范并发数据不一致问题。
- 有状态是服务器缓存了数据,性能更高但为保持数据一致性,相关请求需分发到同一台服务器,游戏等场景适合有状态架构。
4. Web 模式 vsSvr 模式
- Web 模式是请求 - 应答式、同步通讯、同步逻辑、无状态架构,特点是 Web 服务器实现了通用操作,外部程序只需处理业务逻辑,扩容方便。
- Svr 模式采用长连接,客户端请求不一定有应答,服务器可主动推送消息,通讯不限定同步,对客户端开发要求高,通讯性能更强。
五、数据层的演进
1. 10:简单设计
- 以手游开发为例,初期交互频率不大时用 MySQL 简单设计,如基于主键的“点查询”效率高,“面查询”可能存在性能问题,在用户数不多时系统响应及时。
2. 100:数据库调优
- 随着用户增加 MySQL 压力增大,通过修改 MySQL 参数(如加大 InnoDB 的 cache、不使用事务提交)进行调优,性能提升明显。
3. 1000:分库分表
- 当用户持续增加,单台 db 性能有极限,于是重新设计数据库表结构和后台代码进行分库分表,按规则将主键分库分表,根据用户增长情况可逐步扩容。
4. 关于读写分离
- 在游戏项目中读写分离用处不大,因为游戏读写比例不像网站那样读多写少,而且分库后再搞读写分离会使 db 过于复杂。MySQL 读写分离基于主从复制功能,项目有 OLAP 需求时一般在 slave 上查询。
5. 10000:缓存
- 随着 db 机器增长,为提升单台 db 性能加入 Redis 缓存,读时先从 Redis 读,没有则从 MySQL 查询并写入 Redis,写时同时写入两者,Redis 性能高主要因为数据在内存且操作简单,相比 MySQL 受磁盘 IO 限制且缓存机制复杂。
扩展阅读
Made by 捣鼓键盘的小麦 / © 2025 Front Talk 版权所有