sgcWebSockets 2026.5 — 속도 제한기, 서킷 브레이커, API 키, MCP OAuth 및 더 빨라진 IOCP

· 릴리스

sgcWebSockets 2026.5는 알찬 릴리스입니다. 세 가지 새로운 인프라 구성 요소가 WebSocket / HTTP 서버를 프로덕션 등급의 API 게이트웨이로 변모시킵니다. 완전한 기능의 속도 제한기, 클라이언트 측 서킷 브레이커, 그리고 전체 라이프사이클을 지원하는 API 키 관리자가 그것입니다. 프로토콜 측면에서는 일반 Lightstreamer TLCP 2.5 구현 위에 구축된 새로운 Forex.com 클라이언트가 있고, MCP Serverclaude.ai와 같은 브라우저 기반 MCP 클라이언트에 직접 연결할 수 있도록 기본 제공 OAuth 2.1 흐름을 얻었으며, IOCP(Windows) 및 EPOLL(Linux) I/O 엔진은 측정 가능한 6가지 성능 개선을 거두었습니다. 또한 초기 포스트 양자 프리미티브도 포함되어 있습니다. ML-KEM-768 키 쌍 생성을 위한 sgcKEM_CreateMLKEM768Keys입니다.

이 게시물은 새 구성 요소에 대해 붙여넣기 가능한 Delphi 스니펫과 함께 주요 사항을 살펴봅니다.

TsgcWSRateLimiter — 즉시 사용 가능한 API 속도 제한

서버 옆에 TsgcWSRateLimiter를 드롭하면 IP별, API 키별, 사용자별 또는 엔드포인트 패턴별로 토큰 버킷, 슬라이딩 윈도우 또는 고정 윈도우 속도 제한을 적용할 수 있으며, 일별/월별 할당량과 버스트 보호도 포함됩니다. 이 구성 요소는 스레드 안전하며 상태를 디스크에 유지합니다(따라서 서버 재시작 시 모든 클라이언트에게 새로운 할당량이 부여되지 않습니다).

uses
  sgcWebSocket_Server_RateLimiter;

var
  oRL: TsgcWSRateLimiter;
  oResult: TsgcRateLimitResult;
begin
  oRL := TsgcWSRateLimiter.Create(nil);
  try
    oRL.TokenBucket.Enabled    := True;
    oRL.TokenBucket.Capacity   := 100;     // burst size
    oRL.TokenBucket.RefillRate := 10;      // tokens / interval
    oRL.TokenBucket.RefillIntervalMs := 1000;

    oRL.PerIP.Enabled       := True;
    oRL.PerIP.MaxRequests   := 60;
    oRL.PerIP.WindowSec     := 60;

    // Consume one token for the current request
    oResult := oRL.Consume('ip:' + vClientIP);
    if not oResult.Allowed then
      RespondHTTP(429, 'Retry-After: ' + IntToStr(oResult.RetryAfterSec));
  finally
    oRL.Free;
  end;
end;

규칙 리졸버는 PerEndpoint(와일드카드 매칭), 그 다음 PerAPIKey, PerUser, 마지막으로 PerIP 순으로 검사합니다. OnThrottled, OnQuotaExceededOnStateChange 이벤트를 통해 모든 결정을 로깅하거나 재정의할 수 있습니다.

데모: Demos\04.WebSocket_Other_Samples\14.RateLimiter — 실시간 통계와 거부 사유를 게시하는 서버에 대해 플러드를 생성하는 클라이언트를 실행합니다.

TsgcWSCircuitBreaker — 클라이언트 측 오류 격리

업스트림 API(api.openai.com, 결제 게이트웨이, 내부 마이크로서비스)가 실패하거나 느려지기 시작할 때, TCP 타임아웃에 매달리면 연결, 스레드, 비용을 잃게 됩니다. TsgcWSCircuitBreaker는 어떤 TsgcHTTPAPI_client 서브클래스 위에도 클래식한 3상태 패턴(닫힘 / 열림 / 반쯤 열림)을 구현하며, 롤링 시간 윈도우, 느린 호출 감지, 선택적 폴백 응답 및 엔드포인트별 재정의를 지원합니다.

uses
  sgcWebSocket_CircuitBreaker;

var
  oCB: TsgcWSCircuitBreaker;
begin
  oCB := TsgcWSCircuitBreaker.Create(nil);
  try
    oCB.Thresholds.FailureCount        := 5;
    oCB.Thresholds.FailureRatePercent  := 50;
    oCB.Thresholds.SlowCallDurationMs  := 2000;
    oCB.Thresholds.SlowCallRatePercent := 80;
    oCB.TimeWindow.RollingWindowSec    := 60;
    oCB.Recovery.CooldownSec           := 30;
    oCB.Recovery.HalfOpenTrialCalls    := 3;

    oCB.Fallback.Enabled        := True;
    oCB.Fallback.UseLastSuccess := True;

    if oCB.IsCallAllowed('openai') then
    try
      vResponse := oOpenAI.ChatCompletion(...);
      oCB.RecordSuccess('openai');
    except
      on E: Exception do
      begin
        oCB.RecordFailure('openai', E.ClassName);
        raise;
      end;
    end
    else
      vResponse := 'service temporarily unavailable';
  finally
    oCB.Free;
  end;
end;

Delphi 2009+에서는 한 줄짜리 래퍼도 사용할 수 있습니다. oCB.Execute('openai', procedure begin oOpenAI.ChatCompletion(...) end); — 성공 / 실패 기록이 자동으로 이루어집니다.

데모: Demos\04.WebSocket_Other_Samples\15.CircuitBreaker.

TsgcWSAPIKeyManager — 하나의 구성 요소에서 키 라이프사이클 관리

대부분의 "WebSocket API" 서버에는 API 키가 필요합니다. 발급, 검증, 폐기, 회전이 그것입니다. TsgcWSAPIKeyManager는 스코프 기반 권한 부여, 선택적 저장 시 해싱, 만료, 감사 로그, 그리고 회전 후 구성 가능한 기간 동안 이전 키가 계속 작동하도록 하는 기본 제공 회전 유예 기간으로 전체 라이프사이클을 래핑합니다.

uses
  sgcWebSocket_Server_APIKeyManager;

var
  oKM: TsgcWSAPIKeyManager;
  vKey, vNewKey: string;
begin
  oKM := TsgcWSAPIKeyManager.Create(nil);
  try
    oKM.Generation.Length := 40;
    oKM.Generation.Prefix := 'sgc_';
    oKM.Hashing.Enabled   := True;        // store SHA-256 hash, not the plaintext
    oKM.Rotation.GracePeriodSec := 86400; // old key valid for 24h after rotation
    oKM.Expiration.DefaultTTLSec := 30 * 86400;

    // Issue a key for tenant "acme" with read+write scopes, expiring in 7 days
    vKey := oKM.IssueKey('acme', ['read', 'write'], 7 * 86400);

    // Validate the key on each request, optionally requiring a scope
    if not oKM.ValidateKey(vKey, 'read', vClientIP) then
      RespondHTTP(401, 'invalid api key');

    // Rotate a key (returns the new plaintext; old key remains valid for GracePeriodSec)
    oKM.RotateKey(vKey, vNewKey);
  finally
    oKM.Free;
  end;
end;

이 구성 요소는 IsRequestAuthorized로 인바운드 HTTP 헤더 또는 쿼리 문자열에서 직접 키를 읽을 수 있으므로 추출 로직을 직접 연결할 필요가 없습니다.

데모: Demos\04.WebSocket_Other_Samples\16.APIKeyManager.

Forex.com 클라이언트 + 일반 Lightstreamer

새로운 TsgcWSAPI_Forex 클라이언트는 Forex.com에 대한 통합 REST + 스트리밍 액세스(로그인, 핑, 시장 감시, 포지션, 주문, 거래 내역, 거래 시뮬레이션)를 제공합니다. 이는 create_session, bind_session, control(구독 / 구독 해제) 및 재연결 후 LOOP 자동 재바인딩 + 구독 재생을 구현하는 일반 Lightstreamer TLCP 2.5 클라이언트인 완전히 새로운 TsgcWSPClient_Lightstreamer 구성 요소 위에 구축되었습니다. Lightstreamer 클라이언트는 자체적으로도 재사용 가능하므로 동일한 코드 베이스가 IG Markets 및 기타 모든 Lightstreamer 기반 피드와 함께 작동합니다.

uses sgcHTTP_API_Forex;

var oFX: TsgcWSAPI_Forex;
begin
  oFX := TsgcWSAPI_Forex.Create(nil);
  oFX.UserName  := 'demo-user';
  oFX.Password  := 'secret';
  oFX.AppKey    := 'your-app-key';
  oFX.Login;
  oFX.SubscribePrices(['EUR/USD', 'GBP/USD', 'XAU/USD']);
  oFX.OnPriceUpdate := procedure(const aSymbol: string; aBid, aAsk: Double)
                      begin
                        ShowMessage(Format('%s %.5f / %.5f', [aSymbol, aBid, aAsk]));
                      end;
end;

완전한 GUI 데모는 Demos\05.Crypto\22.Forex에 있습니다 — 로그인, 연결성 핑, 실시간 시장 감시, 포지션, 활성 주문, 거래 내역, 손절 / 한도 내역 및 거래 시뮬레이션을 제공하며, 자격 증명은 sgcForexDemo.ini에 유지됩니다.

MCP Server — 브라우저 기반 MCP 클라이언트용 OAuth 2.1

이제 MCP Server는 외부 권한 부여 서버 없이 브라우저 기반 MCP 커넥터(예: claude.ai)와 직접 통신할 수 있습니다. MCP 브라우저 커넥터 사양에 필요한 네 가지 OAuth 검색 / 등록 엔드포인트를 자동으로 게시하고, HTML 동의 화면이 있는 PKCE-S256 권한 부여 흐름을 실행하며, 새로 고침 토큰을 발급합니다.

CORS는 인라인으로 처리됩니다. OPTIONS 프리플라이트는 인증 전에 전체 Access-Control-* 헤더와 함께 204를 반환하고, 모든 응답에는 요청 origin을 반영하는 Access-Control-Allow-OriginStrict-Transport-Security: max-age=31536000 HSTS 헤더가 포함됩니다.

IOCP 및 EPOLL: 여섯 가지 튜닝 개선

Windows IOCP 및 Linux EPOLL I/O 엔진은 집중적인 성능 및 튜닝 가능성 작업을 받았습니다.

IOCP (Windows)

oServer.Bindings.Add.Port := 443;
oServer.IOHandler := TsgcIndy_IOHandler_IO_IOCP.Create(oServer);
with TsgcIndy_IOHandler_IO_IOCP(oServer.IOHandler) do
begin
  SendBufferSize    := 256 * 1024;
  ReceiveBufferSize := 256 * 1024;
  TCPNoDelay        := True;
  Engine.ThreadAffinity := True;
end;

EPOLL (Linux)

공유

IOCP / EPOLL 워커 풀은 작업이 처리된 직후를 포함하여 모든 반복마다 sleep(1)을 호출했습니다 — 사실상 큐가 가득 차 있어도 각 워커를 ~1,000 ops/s로 제한했습니다. 이제 대기 중인 작업이 있을 때 sleep을 건너뛰어 제한이 제거되었습니다.

HTTP.sys: 옵트인 고성능 모드

HTTP.sys 서버는 OperatingMode 선택기가 있는 FineTune 속성을 얻습니다. 기본값 ompClassic은 기존 동작을 유지합니다. 새로운 ompHighPerf 모드는 MSDN의 N-워커 × M-사전 게시된 비동기 수신 패턴 — 고처리량 HTTP.sys 배포에 권장되는 아키텍처 — 를 단일 속성 뒤에서 구현합니다.

oServer := TsgcWebSocketHTTPServer.Create(nil);
oServer.HTTP2Options.SecureOptions.HTTPAPI := True;   // use HTTP.sys
oServer.FineTune.OperatingMode := ompHighPerf;
oServer.FineTune.WorkerCount   := 8;
oServer.FineTune.PrePostedReceivesPerWorker := 16;
oServer.Active := True;

THttpServerRequestTHttpServerResponse는 이전에는 수동 파싱을 통해서만 사용할 수 있었던 세부 정보를 다루는 추가 필드로 확장되었습니다.

포스트 양자 프리미티브: ML-KEM-768

작지만 미래 지향적인 추가입니다. sgcKEM_CreateMLKEM768Keys는 PEM 및 원시 바이트 형식 모두로 ML-KEM-768 (FIPS 203 / Kyber-768) 키 쌍을 생성합니다. ML-KEM은 NIST가 표준화한 포스트 양자 KEM이며 하이브리드 TLS 1.3 (X25519MLKEM768)에 대한 IETF 로드맵에 있습니다. 이는 곧 출시될 OpenSSL 3.5 / 3.6 기준선보다 앞서 PQ 지원 핸드셰이크를 실험할 수 있게 해줍니다.

uses sgcKEM;

var vPubPEM, vPrivPEM: string; vPubRaw, vPrivRaw: TBytes;
begin
  sgcKEM_CreateMLKEM768Keys(vPubPEM, vPrivPEM, vPubRaw, vPrivRaw);
  TFile.WriteAllText('mlkem768_pub.pem', vPubPEM);
  TFile.WriteAllText('mlkem768_priv.pem', vPrivPEM);
end;

안정성 및 적합성 수정

버그 수정 배치는 긴 MCP, HTTP.sys, IOCP 및 HTTP/2 문제 목록을 마무리합니다. 주요 사항:

업그레이드

2026.5는 기존 2026.4 프로젝트에 대한 즉시 사용 가능한 업그레이드입니다. 기존 구성 요소에 대한 인터페이스 변경은 없습니다. 새로운 속도 제한 / 서킷 브레이커 / API 키 구성 요소는 추가적이며 옵트인입니다. HTTP.sys 고성능 모드는 FineTune.OperatingMode := ompHighPerf 뒤에 게이트되어 있습니다 — 기존 코드는 클래식 경로에 머무릅니다.

활성 구독이 있는 고객은 고객 영역에서 새 빌드를 다운로드할 수 있습니다. 평가판 사용자는 esegece.com/products/sgcwebsockets/sgcwebsockets-download에서 업데이트된 설치 프로그램을 받을 수 있습니다.

질문, 피드백 또는 마이그레이션 도움이 필요하신가요? 문의하기 — 코드를 작성한 사람들로부터 직접 답변을 받게 됩니다.