Net-Base Maġazin

06.06.2026

Prestazzjoni Għolja REST Server f'Delphi: Limiti tat-Talbiet, pool ta' threads u imġieba nadifa waqt sovraccarigu (snippet tas-sors)

Server ta' Prestazzjoni Għolja REST f'Delphi mhux biss ikun mgħaġġel minħabba 'JSON mgħaġġel', iżda minħabba parallelità kkontrollata, timeouts stretti u imġiba nadifa fil-każ ta' sovraccarigu. Dan l-artiklu juri Concurrency-Gate prattiku b'Semaphore, risposti 429/503...

06.06.2026

Minn suġġett tar-rivista għall-prattika tal-proġett

Paġni ta' servizz u paġni tekniċi relevanti għall-artiklu

Għaliex „High Performance“ f’REST fi Delphi spiss jispiċċa minħabba parallelità

F’praxxi server High Performance REST Delphi rari jkun limitat biss mill-ħin CPU għal kull Request; minflok ikun limitat mill-parallelità mhux ikkontrollata: wisq Requests simultanji, wisq queries tal-bażi tad-dejta simultanji jew I/O li jibbloċka (fajl, netwerk, bażi tad-dejta). Ir-riżultat mhux sempliċement „ftit iżjed bil-mod“, iżda reazzjoni kaskata: aktar Threads, aktar saffijiet ta‘ stennija, kollass tal-connection-pool, latenzi li jiżdiedu, Timeouts fuq in-naħa tal-klijent u fl-aħħar server li għadu „ħaj“ iżda ma jipprovdi risposti stabbli.

Ir-rimedju m’huwiex trik wieħed, imma imġieba deliberata ta‘ sovraccariku: meta s-server jilħaq il-limiti tiegħu, għandu jirrifjuta bikri u b’mod deterministiku (tipikament HTTP 429 jew 503), minflok jħallih Requests jidħlu f’saff ta‘ stennija bla tmiem. Dan il-fragment tas-source hu maħsub eżattament għal dak: Concurrency-Gate ħafif (Semaphore) plus Timeouts, li jista‘ jintegra ma‘ endpoints eżistenti ta‘ REST — indipendentament jekk tuża Indy, WebBroker, Horse jew saff HTTP proprju.

Architekturidee: Concurrency-Gate vor dem „teuren Teil“

L-idea bażika hija sempliċi: qabel il-parti kostli (aċċess għall-bażi tad-dejta, rapporti kumplessi, risposti JSON kbar) jiġi rriżervat token minn Semaphore. Jekk m’hemmx token liberu, tingħata risposta ikkontrollata immedjatament. Importanti: dan il-Gate irid jiġi rilaxxat b’mod affidabbli (try/finally), u għandu jkun fil-path tal-kodiċi li tassew hu kostli — mhux biss fil-bidu tal-request-handler, meta wara jkun hemm parser/router/awtentikazzjoni.

Billi jsir hekk, il-kariga ma tinkisebx jew „tneħħiet“, imma tinġibed fi kanali: is-server iwieġeb inqas Requests fl-istess ħin, iżda b’latenzi aktar stabbli. F’applikazzjonijiet ta‘ intrapriża individwali dan spiss ikun aktar valurjuż mill-aqwa żminijiet sporadiċi f’benchmarks sintetiċi.

Source-Schnipsel: Request-Limiter mit Timeout, 429/503 und Telemetrie-Hooks

Il-kodiċi ta‘ Delphi li ġej jimplimenta Concurrency-Gate bħala klassi TRestRequestGate. Hu ibbażat fuq TSemaphore (minn System.SyncObjs; semaphore huwa kontatur għal aċċessi simultanji limitati). Il-sejħa tal-Gate tipprovdi jew oġġett „Lease“ (simili għal RAII: rilaxx fil-Destructor) jew tiddeċiedi għal risposta ta‘ sovraccariku immedjata. Bħala addizzjoni hemm hooks għal logging/monitoring, sabiex fil-produzzjoni tara għaliex Requests ġew irrifjutati.

Delphi
unit RESTRequestGate;

interface

uses
  System.SysUtils,
  System.Classes,
  System.SyncObjs,
  System.Diagnostics;

type
  // Kontest minimu għall-logging/tracing; jista' jiżdied pereżempju b'User/Route.
  TRESTGateContext = record
    RequestId: string;
    Route: string;
    RemoteIp: string;
  end;

  TRESTOverloadDecision = (odAccepted, odRejectedBusy, odRejectedTimeout);

  // Hook għal telemetrija tal-operat (pereżempju f'fajl, Syslog, Prometheus-Exporter, eċċ.)
  TRESTGateEvent = reference to procedure(const Ctx: TRESTGateContext;
                                         Decision: TRESTOverloadDecision;
                                         WaitedMs: Integer;
                                         InFlight: Integer);

  // Lease-objett: rilaxx tat-token fil-Destructor.
  TRESTGateLease = class
  private
    FSemaphore: TSemaphore;
    FInFlightCounter: PInteger;
    FReleased: Boolean;
  public
    constructor Create(ASem: TSemaphore; ACounter: PInteger);
    destructor Destroy; override;
    procedure Release;
  end;

  TRESTRequestGate = class
  private
    FSem: TSemaphore;
    FMaxInFlight: Integer;
    FInFlight: Integer;
    FOnEvent: TRESTGateEvent;
  public
    constructor Create(AMaxInFlight: Integer);
    destructor Destroy; override;

    // TimeoutMs = 0: ebda żmien stennija, immedjatament 429/503
    function TryAcquire(const Ctx: TRESTGateContext; TimeoutMs: Cardinal;
                        out Lease: TRESTGateLease;
                        out WaitedMs: Integer;
                        out Decision: TRESTOverloadDecision): Boolean;

    property OnEvent: TRESTGateEvent read FOnEvent write FOnEvent;
    property MaxInFlight: Integer read FMaxInFlight;
    function InFlight: Integer;
  end;

implementation

uses
  System.Math;

{ TRESTGateLease }

constructor TRESTGateLease.Create(ASem: TSemaphore; ACounter: PInteger);
begin
  inherited Create;
  FSemaphore := ASem;
  FInFlightCounter := ACounter;
  FReleased := False;
end;

destructor TRESTGateLease.Destroy;
begin
  Release;
  inherited;
end;

procedure TRESTGateLease.Release;
begin
  if FReleased then
    Exit;
  FReleased := True;

  // L-ewwel naqqas il-counter, imbagħad irrilaxxa s-semaphore.
  TInterlocked.Decrement(FInFlightCounter^);
  FSemaphore.Release;
end;

{ TRESTRequestGate }

constructor TRESTRequestGate.Create(AMaxInFlight: Integer);
begin
  inherited Create;
  if AMaxInFlight <= 0 then
    raise EArgumentException.Create('AMaxInFlight għandu jkun > 0');

  FMaxInFlight := AMaxInFlight;
  FInFlight := 0;

  // InitialCount = MaxCount = AMaxInFlight
  FSem := TSemaphore.Create(nil, AMaxInFlight, AMaxInFlight, '');
end;

destructor TRESTRequestGate.Destroy;
begin
  FSem.Free;
  inherited;
end;

function TRESTRequestGate.InFlight: Integer;
begin
  Result := TInterlocked.CompareExchange(FInFlight, 0, 0);
end;

function TRESTRequestGate.TryAcquire(const Ctx: TRESTGateContext; TimeoutMs: Cardinal;
  out Lease: TRESTGateLease; out WaitedMs: Integer; out Decision: TRESTOverloadDecision): Boolean;
var
  Sw: TStopwatch;
  WaitRes: TWaitResult;
  CurrentInFlight: Integer;
begin
  Lease := nil;
  WaitedMs := 0;
  Decision := odRejectedBusy;

  Sw := TStopwatch.StartNew;
  if TimeoutMs = 0 then
    WaitRes := FSem.WaitFor(0)
  else
    WaitRes := FSem.WaitFor(TimeoutMs);

  WaitedMs := Integer(Min(Sw.ElapsedMilliseconds, High(Integer)));

  case WaitRes of
    wrSignaled:
      begin
        CurrentInFlight := TInterlocked.Increment(FInFlight);
        Lease := TRESTGateLease.Create(FSem, @FInFlight);
        Decision := odAccepted;
        Result := True;

        if Assigned(FOnEvent) then
          FOnEvent(Ctx, Decision, WaitedMs, CurrentInFlight);
      end;

    wrTimeout:
      begin
        // wrTimeout jekk TimeoutMs > 0: stennija mmirata, iżda limitata.
        Decision := odRejectedTimeout;
        Result := False;
        if Assigned(FOnEvent) then
          FOnEvent(Ctx, Decision, WaitedMs, InFlight);
      end;
  else
    begin
      // wrAbandoned/każijiet ta' żball: tirrifjuta b'mod konservattiv
      Decision := odRejectedBusy;
      Result := False;
      if Assigned(FOnEvent) then
        FOnEvent(Ctx, Decision, WaitedMs, InFlight);
    end;
  end;
end;

end.

Għan: Stabbiltà taħt tagħbija minflok ‚kollox fl-istess ħin‘

Bil MaxInFlight tiddetermina kemm Requests jistgħu jidħlu simultanjament fil-«parti kostjuża». Dan mhux „in-numru ta‘ CPU-Kerne“, iżda daqs operattiv. Għal endpoints li huma bbażati fuq il-database spiss huwa sensat li tissettja MaxInFlight fir-relazzjoni mal-DB-Connection-Pool (per eżempju Pool = 20, MaxInFlight = 12 sa 16), sabiex mhux kull request jibbloċka konnessjoni u mbagħad threads oħra ikunu meħtieġa biex jsegwu.

Kundizzjonijiet u ostakli

  • Try/Finally ist Pflicht: Il-lease għandu jiġi rrilaxxat b’mod garantiti. Jekk għandek Exceptions fl-endpoint, il-gate jista‘ jitgħabba u s-server jibqa‘ b’mod permanenti ‚busy‘.
  • Timeout sinnvoll wählen: TimeoutMs=0 huwa limit strett (jiġi miċħud immedjatament). Timeout qasir (tipikament 50 sa 150 ms) jgħin jnaqqas il-piki mingħajr ma jinħolqu t-toroq ta‘ stennija veri.
  • Gate nicht zu früh: L-awtentikazzjoni (per eżempju Bearer/JWT) jew ir-routing jistgħu jkunu postijiet xierqa; is-semaphore għandha tista‘ tieħu sehem qabel il-parti tassew kostjuża. Min-naħa l-oħra: jekk l-awtentikazzjoni ssir kostjuża (pereżempju kontra sistema esterna ta‘ identity), trid tkun limitata wkoll.
  • 429 vs 503: HTTP 429 („Too Many Requests“) huwa adattat meta trid li clients jippruvaw jerġgħu jintentaw. 503 („Service Unavailable“) huwa adattat meta s-servizz temporanjament ma jkunx f’kważi l-abbiltà li jaċċetta anke sensatament il-requests. F’kull każ huwa rrakkomandat header Retry-After.

Integration in REST-Handler: Indy/WebBroker/Horse pragmatisch

  • Imla l-kuntest (RequestId, Route, RemoteIp)
  • TryAcquire bi timeout qasir
  • Fil-każ ta‘ rifjut: kirtu risposta immedjatament (429/503) u temm
  • Il-lease jibqa‘ fis-scope sakemm jitlesta l-parti kostjuża

F’Horse (Middleware) il-gate huwa viċin grupp ta‘ routes. F’WebBroker tista‘ taħdem fl-action-handler rispettiv. F’Indy jiddependi jekk għandek thread għal kull request; il-gate għadu effettiv sakemm il-partijiet kostjużi jkunu limitati b’mod nadif.

High Performance REST Server Delphi: Overload-Antworten, die Clients nicht „vergiften“

Ir-risposti ta‘ sovraccarigu huma aktar minn kodiċijiet ta‘ status. Jekk il-clients jirritornaw immedjatament b’mod aggressiv wara 429/503, tkun qed toħloq storm ta‘ retries. F’ambjenti sistemi eterogeni (Mobile Apps, C# Services, clients legacy) jgħin li jkollok mġiba konsistenti:

  • Retry-After: pereżempju 1 sa 3 sekondi, skont l-endpoint. Huwa marcat ta‘ takt ċar.
  • Kurzer Body: JSON żgħir bħal {"error":"server_busy","requestId":"..."} jaqbeż. Oġġetti kbar ta‘ error jerġgħu jikkonsmaw CPU u bandwidth.
  • Health-Endpoint ungedrosselt: Il-monitoring għandu jipprovdi informazzjoni anki taħt tagħbija (possibilment bi flag „degraded“).

Jekk għandek reverse proxy bħal nginx quddiemu: aġġusta timeouts u buffering hemmhekk. Proxy jista‘ jnaqqas il-ħtieġa fuq l-app (TLS-Termination, Keep-Alive), iżda jista‘ wkoll jittrasferixxi l-tagħbija (pereżempju billi jbassar bodies kbar ta‘ request). Fil-operazzjoni hu kruċjali li l-limits ikunu konsistenti: Proxy-Timeout > App-Timeout, inkella il-clients jidherlu „Gateway Timeout“ minkejja li l-app kienet rrifjutat b’mod nadif.

Threading, DB-Pools u Keep-Alive: Fejn jinqalbu problemi fil-prattika

Il-Gate isolvi l-problema ta‘ “ħafna fl-istess ħin”, imma ma jipprevjenx awtomatikament li request wieħed jakkumula riżorsi b’mod eċċessiv. Tliet punti tipici ta‘ kriżi f’proġetti Delphi jseħħu eżatt fuq l-interface bejn threading, database u konnessjonijiet HTTP:

  • Request wieħed jibbloċka diversi riżorsi skarsi: L-ewwel konnessjoni DB, imbagħad sejħa HTTP esterna, imbagħad aċċess fajl. Jekk kollox iseħħ fil-istess Request-Thread, iż-żmien tal-blokka jiżdied b’mod multiplicattiv. Il-Gate jillimita l-parallelità, imma t-throughput jonqos b’mod drastiku. Hawn jiswa li tinqasmu d-dipendenzi (eż. sejħiet esterni asinkroni, pre-kalkulazzjoni permezz ta‘ Job-Queue).
  • BDE-Ablosung mit nativer Anbindung-Pooling und Transaktionen: BDE-Ablosung mit nativer Anbindung jista‘ jpoolja Connections, imma transazzjoni “twila” (eż., minħabba li tiġi ffurmata JSON jew hemm business-checks bejn StartTransaction u Commit) iżomm il-konnessjoni b’mod mhux meħtieġ. Praktika nadifa hi li tpoġġi t-transazzjoni kemm jista‘ jkun viċin l-istruzzjonijiet reali u timla jew tivverifika barra mit-transazzjoni, jekk huwiex possibbli mill-perspettiva tan-negozju.
  • HTTP Keep-Alive bħala konsumatur moħbi tal-memorja: Keep-Alive jonqos il-handshakes, imma jista‘ jwassal għal ħafna sockets miftuħa meta hemm bosta clients iddjitati. Speċjalment f‘Windows- u Linux-Services mhux se tara “CPU għolja” imma “Handles/FDs mimlija” jew RAM minħabba buffers. Hawn jgħinu Idle-Timeouts ċari fuq is-server u fuq il-reverse proxy kif ukoll limitu per Client-IP, jekk l-ambjent jippermetti.

Il-konsegwenza: MaxInFlight m’huwiex valur statiku. Tiddependi mill-aktar riżorsa bil-mod u skarsa tiegħek (DB, sistemi esterni, storage) u minn kemm request iġorr jew “jżomm” dawn ir-rižorsi.

Performance-Hebel neben dem Gate: JSON, DB und I/O nicht vermischen

Il-Gate jistabbilizza, imma ma jissostitwixxi l-ekonomija nadifa tal-endpoint. Tliet freni f’serveri Delphi REST jidhru ripetutament:

  • JSON-Building bil-katenati temporanji mhux meħtieġa: Spiss il-lasta tiġi minn ħafna Unicode-strings temporanji. Fejn possibbli, ibni b’mod orientat lejn streaming (Writer/Stream) minflok oġġetti temporanji kbar, speċjalment fuq endpoints tal-listi.
  • Aċċess għad-database „għal kull item“: N+1-Queries u per-row lookups huma klassika. Aħjar: joins mirquma, batch-queries, aggregazzjoni fuq in-naħa tas-server. Għal riżultati kbar ħafna, jiswa wkoll pagination b’sortjar stabbli (biex il-paġni ma ‚jibdlu‘).
  • I/O li jibbloċka fil-Request-Thread: Aċċessi fajl jew sejħiet HTTP esterni għandhom jiġu jew strettament limitati jew imqassma f’pipeline asinkrona. Inkella tibbloċkaw threads prezzjużi sabiex jistennew.

Għal soluzzjonijiet korporattivi diġitali li kibru, dan spiss huwa l-punt kritiku: endpoint ġie żdied “malajr” u jaħdem sakemm jaslu l-lasti reali u volumijiet tad-dejta. Imbagħad jidher jekk il-limiti tal-arkitettura ġew imdawra b’mod nadif (saff ta‘ aċċess tad-dejta, caching, strateġiji bulk, timeouts ċari).

Debugging und Betrieb: Was Sie messen sollten

Il-hook OnEvent huwa konxjament sempliċi. Fil-prattika għandek tirreġistra għall-inqas il-valuri li ġejjin:

  • InFlight (il-parallelità attwali fuq il-Gate)
  • WaitedMs (kemm “queueing” tippermetti)
  • Decision (accepted/busy/timeout)
  • Route/RemoteIp (analiżi inizjali tal-kawżi, mingħajr ma jinġeneraw injoranza lejn il-protezzjoni tad-dejta)

B’dan tieħu sinjal jekk il-limiti huma wisq stretti (troppi 429) jew wisq rilassati (WaitedMs għoljin, latenzi li jiżdiedu). U tara jekk ċerti routes individwali jiddominaw. Għal Windows- u Linux-Services dan hu deċiżiv fil-prattika: mingħajr telemetrija problema ta‘ prestazzjoni malajr issir logħba ta‘ stima bejn in-netwerk, id-database, il-proxy u l-applikazzjoni.

Mhux komuni, iżda estremament utli: „WaitedMs“ bħala indikatur ta‘ twissija bikrija

Bosta timijiet jiffokaw biss fuq il-Response-Time u l-CPU. WaitedMs spiss huwa indikatur aħjar, għax juri li r-requests diġà qed jistennaw qabel il-ħidma proprja. Jekk WaitedMs jiżdied filwaqt li l-CPU tibqa‘ moderata, ir-riżorsa limitata ħafna drabi mhix il-CPU, imma pool (konnessjonijiet DB), lock fil-business-logic jew servizz estern downstream. Dan jiffranka żmien fl-analiżi tal-kawżi, għax jippermettilek tiffoka aktar lejn «Pool/Lock/I/O» minflok «Compiler-Optimierung».

Varjanti: Pro-Route-Gates, Prioritajiet und „Fast Lane“

Gate wieħed għal kollox hu sempliċi, iżda mhux dejjem ideali. Varjanti sensati:

  • Gate pro Route-Gruppe: „/reports“ strett, „/api/orders“ moderat, „/health“ miftuħ. B’hekk tipprevjeni li r-requests tar-rapporti, li jsejħu riżorsi kbar, jipperikolu l-proċessi ewlenin.
  • Fast Lane għal Admin/Monitoring: Gate separat b’paralleliżmu żgħir, sabiex azzjonijiet tal-operazzjoni jkunu possibbli anke taħt load.
  • Limiti bbażati fuq baġit: Jekk id-daqsijiet tar-response jvarjaw b’mod sinifikanti, jista‘ jgħin baġit f’bytes addizzjonali (eż. massimu X MB fl-istess ħin fil-ġenerazzjoni). Dan hu aktar kumpless, iżda realistik meta jinqalgħu downloads kbar.

Importanti: il-prijoritizzazzjoni tista‘ malajr issir kwistjoni politika («il-endpoint tiegħi hu aktar importanti»). Teċnikament tibqa‘ stabbli meta l-prijoritajiet ikunu mqabbda ma‘ proċessi (eż. ir-reġistrazzjoni tal-ordnijiet qabel reporting) u mhux ma‘ rwoli jew dipartimenti.

Konklużjoni: Jiswa l-Gate – u fejn jonqos l-approċċ?

Gate ta‘ Concurrency huwa komponent pragmatiku għal server High Performance REST f’Delphi, peress li jagħmel l-overload kontrollabbli u jżomm is-sistemi tiegħek stabbli taħt peak-load. Jiswa speċjalment jekk għandek endpoints marbuta mad-database, jekk hemm Reverse Proxy quddiemhom jew jekk diversi klienti (Legacy, Portale, Services) joħolqu load f’mewġ.

Il-limiti huma ċari: jekk il-ħidma reali għal kull request tkun wisq għolja (queries ineffiċjenti, oġġetti JSON kbar, sistemi esterni li jibbloġġjaw), il-Gate jikkopri biss is-sintomi. F’dak il-każ trid tindirizza l-aċċess tad-data, strateġiji ta‘ caching, timeouts u, fejn applikabbli, proċessar asinkronu (Queue/Job-System). Bħala ċinturin ta‘ sigurtà fil-operazzjoni, il-Gate spiss huwa d-differenza bejn sistema li tibqa‘ tista‘ tieħu t-tensjoni u sistema li ssir kompletament mhux użabbli.

Jekk trid tintegra imġiba ta‘ overload f‘Delphi REST-API und REST-Server eżistenti jew tippjana li tibbilanċja l-limiti ma‘ database- u proxy-timeouts b’mod nadif: diskuti proġett jew skop ta‘ modernizzazzjoni ma‘ Net-Base.

Fil-kuntest professjonali ukoll Thread-Pool Delphi u Http 429 Too Many Requests għandhom rwol importanti, meta l-integrazzjonijiet, il-flussi tad-data u l-iżvilupp kontinwu għandhom jaħdmu flimkien b’mod koerenti.

Diskuti proġett jew skop ta‘ modernizzazzjoni ma‘ Net-Base.

Pass li jmiss

Meta suġġett jissarraf f’proġett reali, l-arkitettura, is-sistema eżistenti u l-operazzjoni għandhom jiġu kkunsidrati flimkien kmien.

Aħna nappoġġjaw mhux biss f'kwistjonijiet puntwali, iżda wkoll meta biċċiet ta' kodiċi sors, temi legacy jew ideat għal portali jridu jsiru proġett korporattiv stabbli u affidabbli.

  • L-istat attwali, l-istat tal-mira u r-riskji tekniċi jiġu vvalutati flimkien.
  • REST, aċċess għad-dejta, portali u Rollout mhux se jiġu posposti bħala konsegwenzi tardivi.
  • Tara kmieni liema triq hija sostenibbli kemm mill‑punt ta’ vista ekonomiku kif ukoll mill‑punt ta’ vista operattiv.

Aqsam il-post

Aqsam dan il-post direttament

LinkedIn, X, XING, Facebook, WhatsApp u E-Mail huma immedjatament disponibbli. Għal Instagram nippreparaw il-link u t-test qasir direttament.

Imejl

Instagram jiftaħ f'tab ġdid. Il-link u t-test qasir jiġu kkopjati qabel fil-clipboard.