HTTP/2 服务器线程

· 功能

自 sgcWebSockets 2024.2.0 起,HTTP/2 服务器在接收 HTTP/2 请求时得到了改进。现在,默认情况下,当服务器收到新的 HTTP/2 请求时,该请求会被加入队列,并由线程池中的某个线程进行调度处理。这解决了通过同一连接发送多个请求时被顺序处理的问题。

以下是 HTTP 1.1 与 HTTP 2.0 的区别:

HTTP 1.1

 在传统 HTTP 行为中,通过同一连接发起多个请求时,客户端必须等待每个请求的响应后才能发送下一个。这种顺序处理方式显著增加了网站资源的加载时间。为解决此问题,HTTP/1.1 引入了管道化(pipelining)功能,允许客户端无需等待服务器响应即可发送多个请求,服务器则按收到请求的顺序依次响应。

然而,管道化在实际中面临以下挑战:


为优化支持 HTTP/1.1 的服务器的页面加载,浏览器采取了变通方案——向服务器建立 6 到 8 个并行连接,从而同时传输多个请求。这种并行方式旨在缓解管道化的相关问题,提升整体页面加载速度。

浏览器选择 6 到 8 个并行连接的原因涉及优化考量,具体数量的选择可能是资源利用率、网络效率与避免潜在瓶颈之间的权衡。

HTTP 2.0

针对管道化的局限性,HTTP/2 引入了多路复用功能。多路复用通过在单一连接上并发传输多个请求和响应,实现了客户端与服务器之间更高效的通信

HTTP/2 采用二进制帧机制,即将 HTTP 消息拆分为更小的独立单元——帧(frame)。这些帧可以交错发送,彼此独立;接收端再将帧重新组装还原为原始 HTTP 消息。

这种二进制帧机制是实现 HTTP/2 多路复用的基础。它使浏览器能够通过同一连接发送多个请求而不产生阻塞。因此,Chrome 等浏览器对 HTTP/2 请求使用相同的连接 ID,实现客户端与服务器之间高效、不中断的通信。

简言之,HTTP/2 的多路复用功能(由二进制帧机制驱动)通过在单一连接上并发传输多个请求和响应,提升了客户端与服务器之间数据交换的效率与速度。

TsgcWebSocketHTTPServer 组件

为提升 HTTP/2 协议的性能,每当服务器收到新的 HTTP/2 请求时,默认情况下请求会在线程池(默认 32 个线程)中进行调度。这避免了在没有线程池的情况下,单个连接发送大量并发请求时需要顺序处理(在连接线程上下文中)所导致的等待问题。

PoolOfThreads 的行为可通过以下属性进行配置:


若要精细调优请求调度,决定哪些请求必须在线程池中处理(因为耗时较长)、哪些可以在连接线程中处理,可以使用事件 OnHttp2BeforeAsyncRequest。该事件在请求加入线程池队列之前触发,使用参数 Async 来设置请求是否需要线程化处理。
procedure OnHTTP2BeforeAsyncRequest(Sender: TObject; Connection: TsgcWSConnection; const ARequestInfo: TIdHTTPRequestInfo; var Async: Boolean);
begin
  if ARequestInfo.Document = '/time-consuming-request' then
    ASync := False;
end;