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이라는 기능을 도입해서, 클라이언트가 서버의 응답을 기다리지 않고 여러 요청을 보낼 수 있게 했어요. 서버는 받은 순서대로 클라이언트에 응답해요.

pipelining은 해결책으로 보였지만, 다음과 같은 문제에 직면했어요:


HTTP/1.1을 지원하는 서버의 페이지 로딩을 최적화하기 위해 웹 브라우저는 차선책을 구현했어요. 서버와 6~8개의 병렬 연결을 열어서 여러 요청을 동시에 전송할 수 있도록 했어요. 이런 병렬 처리는 pipelining과 관련된 문제를 완화하고 전체 페이지 로딩 시간을 개선하는 것을 목표로 해요.

웹 브라우저가 6~8개의 병렬 연결을 선택한 것은 최적화 고려 사항에 기반해요. 이 숫자를 선택한 구체적인 이유에는 리소스 활용도, 네트워크 효율성, 잠재적인 병목 현상 회피 사이의 트레이드오프가 있어요. 

HTTP 2.0

pipelining에서 직면한 제약에 대응하기 위해, HTTP/2는 멀티플렉싱이라는 기능을 도입했어요. 멀티플렉싱단일 연결로 여러 요청과 응답을 동시에 전송할 수 있게 해서 클라이언트와 서버 간의 더 효율적인 통신을 가능하게 해요.

HTTP/2는 바이너리 프레이밍 메커니즘을 사용하는데, 이는 HTTP 메시지가 프레임이라는 더 작고 독립적인 단위로 분할된다는 것을 의미해요. 이 프레임들은 서로 인터리브되어 연결을 통해 독립적으로 전송될 수 있어요. 수신 측에서는 프레임들이 다시 조립되어 원래의 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;