EPOLL

Supported by

 

TsgcWebSocketServer

TsgcWebSocketHTTPServer

 

*sgcWebSockets Enterprise Edition이 필요합니다.

 

Linux용 EPOLL은 Indy가 기본적으로 하는 것처럼 연결당 하나의 스레드를 사용하는 대신 제한된 스레드 풀을 사용하여 수천 개의 연결을 처리할 수 있는 API입니다.

Indy 서버에 EPOLL을 활성화하려면 IOHandlerOptions 속성으로 이동하여 IOHandler Type으로 iohIEPOLL을 선택하십시오.


Server.IOHandlerOptions.IOHandlerType := iohEPOLL;
Server.IOHandlerOptions.EPOLL.EPOLLThreads := 0;
Server.IOHandlerOptions.EPOLL.WorkOpThreads := 0;
Server.IOHandlerOptions.EPOLL.PartialRequestTimeout := 0;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Enabled := True;
Server.IOHandlerOptions.KeepAliveTimeout := 120;

 

EPOLLThreads는 EPOLL 비동기 요청(오버랩 작업)에 사용되는 스레드입니다. 기본적으로 값은 0이며, 이는 스레드 수가 프로세서 수를 사용하여 계산됨을 의미합니다(cpucount 함수가 지원되지 않아 스레드 수가 32로 설정되는 Delphi 7 및 2007 제외). 스레드 수를 수동으로 조정할 수 있습니다.

WorkOpThreads는 요청을 처리하기 위해 준비 상태로 유지되는 워커 스레드의 최소 개수를 설정하며, 기본값은 0입니다. EPOLL 스레드는 소켓이 준비되었다는 것만 감지하고 실제 작업은 이 풀에 넘기므로, 느린 클라이언트 때문에 차단되는 일이 없습니다. 모든 워커가 이미 작업 중이면 이 풀은 고정된 최대값까지 필요에 따라 늘어나므로, 크기를 미리 정해 둘 필요가 없습니다. 첫 요청이 도착하기 전에 풀을 미리 준비해 두고 싶은 경우에만 이 값을 높이십시오. 그러면 연결이 한꺼번에 몰리는 초기에 스레드 생성 비용을 치르지 않아도 됩니다.

2026.9.0에서 변경되었습니다. 이전에는 WorkOpThreads가 모든 연결을 이 스레드 중 하나에 고정했기 때문에 한 연결의 모든 요청이 동일한 스레드에서 실행되었고, WorkOpRoundRobin은 새로운 연결을 이 스레드들에 어떻게 분배할지 결정했습니다. 이 고정 방식은 제거되었습니다. 요청의 나머지 부분을 기다리며 멈춰 있는 연결이 동일한 스레드에 할당된 다른 모든 연결을 차단하여 서버를 정체시켰기 때문입니다. 이제 같은 연결의 요청이 서로 다른 스레드에서 실행될 수 있으므로, 데이터베이스 연결이나 스레드 로컬 캐시처럼 스레드별로 보관하는 것이 연결을 따라간다고 가정해서는 안 됩니다. WorkOpRoundRobin은 더 이상 존재하지 않습니다. 코드에서 제거하십시오. 그리고 Object Inspector에서 이 옵션을 활성화했다면 폼의 .dfm에서도 WorkOpRoundRobin 줄을 삭제하십시오. 그렇지 않으면 폼이 로드되지 않습니다.

PartialRequestTimeout은 서버가 이미 길이를 알고 있는 HTTP 요청 본문의 나머지 부분을 기다리게 하며, 단위는 밀리초이고 기본값은 0으로 이 경우 비활성화됩니다. 이 옵션이 없으면, 예를 들어 여러 패킷으로 나뉘어 전송된 대용량 POST 요청처럼 단일 준비 완료 이벤트 내에 전체가 도착하지 않는 요청 본문은 조용히 폐기되고 응답 없이 연결이 닫힙니다. 이 대기는 많은 연결을 처리하며 절대 차단되어서는 안 되는 EPOLL 스레드에서는 실행되지 않고, 위에서 설명한 워커 스레드 풀에서 실행되며 이 풀은 필요에 따라 고정된 최대값까지 늘어나므로, 느리거나 응답이 없는 클라이언트가 이 풀을 고갈시켜 다른 연결을 지연시킬 수 없습니다.

TCPKeepAlive를 사용하면 운영체제가 유휴 상태의 연결을 주기적으로 확인하여, 아무런 응답 없이 조용히 사라진 피어를 감지할 수 있습니다(기본적으로 비활성화됨). TCPKeepAlive.Enabled를 True로 설정하면 운영체제는 연결이 TCPKeepAlive.Time초(기본값 60초) 동안 유휴 상태였을 때부터 해당 연결을 확인하기 시작하며, 피어가 응답하거나 연결이 끊어질 때까지 TCPKeepAlive.Interval초(기본값 10초)마다 이를 반복합니다.

KeepAliveTimeout은 지정한 초(기본값 0, 즉 비활성화됨) 이상 유휴 상태였던 모든 연결을 닫습니다. 유휴 상태인 연결에만 영향을 미치며, 읽는 중인 요청이나 쓰는 중인 응답은 이 타임아웃에 의해 중단되지 않습니다. 이는 기본적으로 사용되는 스레드당 연결(thread-per-connection) 방식의 IOHandler가 응답이 없는 연결을 해제하는 방식과 가장 유사하며, 운영체제나 피어의 협조 여부에 의존하지 않습니다.

 

수천 개의 연결을 처리해야 하는 경우 Linux 서버에 EPOLL을 활성화하는 것이 권장됩니다. 서버가 최대 100개의 동시 연결만 처리하는 경우, 기본 Indy 스레드 모델을 유지할 수 있습니다.

 

 

OnDisconnect 이벤트가 발생하지 않음

 

EPOLL은 기본 indy IOHandler와 다르게 작동합니다. 기본 indy IOHandler에서는 모든 연결이 스레드에서 실행되며 이러한 스레드는 항상 실행되어 연결이 활성 상태인지 확인하므로, 연결이 해제되면 짧은 시간 안에 알림을 받습니다.

 

EPOLL은 다르게 작동합니다. indy가 기본적으로 하는 것처럼 1개 스레드 = 1개 연결이 아니라, 모든 연결을 처리하는 스레드 풀이 있습니다. EPOLL의 경우 연결이 여전히 살아 있는지 감지하는 유일한 방법은 소켓에 쓰기를 시도하는 것이며, 오류가 있으면 연결이 닫혔음을 의미합니다. 연결 해제를 감지하는 세 가지 옵션이 있습니다:

 

1. TsgcWebSocketClient를 사용하는 경우 Options 속성에서 CleanDisconnect := True로 활성화할 수 있습니다(기본적으로 비활성화됨). 활성화되면 클라이언트가 연결을 끊기 전에 연결 해제에 대해 서버에 알리는 메시지를 보내므로, 서버가 이 메시지를 수신하고 OnDisconnect 이벤트가 발생합니다.

2. 서버 측에서 heartbeat를 활성화할 수 있습니다. 예를 들어 60초마다 연결된 모든 클라이언트에 ping을 보내려고 시도하며, 연결이 끊긴 클라이언트가 있으면 OnDisconnect가 호출됩니다.

3. 서버의 IOHandlerOptions에서 TCPKeepAlive를 활성화하거나 KeepAliveTimeout을 설정할 수 있습니다. 이를 통해 서버는 클라이언트가 비정상 종료되거나 종료 메시지 없이 네트워크 연결이 끊어지는 등의 이유로 조용히 응답이 없어진 피어를 스스로 감지하여, 클라이언트가 아무것도 보내지 않더라도 연결을 닫을 수 있습니다.

 

Linux Connections Limit

 

동시 열린 연결 수를 늘리려면 다음 명령을 사용하십시오.

 

ulimit -n 10000

 

이전 명령은 열린 파일 디스크립터의 최대 수를 10000으로 설정합니다