hi, I like paste here a little unit helping coders to do scalable I/O http app
look, I did an apachebench in a I9 virtualized ubuntu, with 100 concurrent users, asking this text through webbroker and firedac postgres sql query:
«Tuttavia, perché voi intendiate da dove sia nato tutto questo errore, di quelli che incolpano il piacere ed esaltano il dolore, io spiegherò tutta la questione, e presenterò le idee espresse dal famoso esploratore della verità, vorrei quasi dire dal costruttore della felicità umana. Nessuno, infatti, detesta, odia, o rifugge il piacere in quanto tale, solo perché è piacere, ma perché grandi sofferenze colpiscono quelli che non sono capaci di raggiungere il piacere attraverso la ragione; e al contrario, non c'è nessuno che ami, insegua, voglia raggiungere il dolore in se stesso, soltanto perché è dolore, ma perché qualche volta accadono situazioni tali per cui attraverso la sofferenza o il dolore si cerca di raggiungere un qualche grande piacere. Concentrandoci su casi di piccola importanza: chi di noi intraprende un esercizio ginnico, se non per ottenerne un qualche vantaggio? E d'altra parte, chi avrebbe motivo di criticare colui che desidera provare un piacere cui non segua nessun fastidio, o colui che fugge un dolore che non produce nessun piacere? Al contrario, però, noi con indignazione denunciamo e riteniamo meritevoli di odio quelli che, rammolliti e corrotti dai piaceri del momento, accecati dal desiderio, non prevedono a quali dolori e a quali sofferenze andranno incontro, e uguale colpa hanno quelli che abbandonano i propri doveri per pigrizia d'animo, cioè per evitare le fatiche e i dolori. Certamente è facile e rapido distinguere questi casi. Infatti nel tempo libero, quando abbiamo tutta la nostra possibilità di scegliere e niente ci ostacola dal fare ciò che ci piace di più, bisogna accogliere ogni piacere e respingere ogni dolore. Ma in altri momenti, o nei doveri inevitabili o negli obblighi che ci vengono dalle circostanze, spesso accadrà che si debba respingere il piacere e accogliere il fastidio. E così il saggio si regola scegliendo tra questi atteggiamenti, facendo in modo che o – respingendo il piacere – ne ottenga di più grandi, o – sopportando il dolore – ne eviti di peggiori.»
calling an Apache2 module webbroker
the system raw performances are impressive, producing 18000 (18 thousands) sustained http requests for sec
pgsql local limits 1000, ssl off
put PhysPG with libpq.so in lib path over the datamodule
here the unit to use, before you can set this on webbroker source
begin
{$IFDEF MSWINDOWS}
CoInitFlags := COINIT_MULTITHREADED;
{$ENDIF}
Web.ApacheApp.InitApplication(@GModuleData);
Application.Initialize;
Application.MaxConnections:=1000;
Application.WebModuleClass := WebModuleClass;
Application.Run;
end.
the unit to interface pooled pg
unit PGPool;
interface
uses
{$IFDEF WINDOWS}
Windows,
FireDAC.VCLUI.Wait,
{$ENDIF}
Classes,
System.SysUtils,
// FireDAC.Phys.PG,
FireDAC.Stan.Intf,
FireDAC.Stan.Option,
FireDAC.Stan.Error,
FireDAC.UI.Intf,
FireDAC.Phys.Intf,
FireDAC.Stan.Def,
FireDAC.Stan.Pool,
FireDAC.Stan.Async,
FireDAC.Phys,
FireDAC.Stan.Param,
FireDAC.DatS,
FireDAC.DApt.Intf,
FireDAC.DApt,
FireDAC.Comp.DataSet,
FireDAC.Comp.Client;
type
TDB = class
public
DBC: TFDConnection;
DBQ: TFDQuery;
DBT: TFDTransaction;
constructor Create;
destructor Destroy; override;
end;
implementation
procedure InitPool;
var
oParams: TStrings;
begin
oParams := TStringList.Create;
oParams.Add('DriverID=PG');
oParams.Add('User_Name=USERNAME');
oParams.Add('Server=ADDRESS');
oParams.Add('Password=PASSWORD');
oParams.Add('Database=DBNAME');
// oParams.Add('CharacterSet=none');
oParams.Add('Pooled=True');
oParams.Add('POOL_CleanupTimeout=3600000');
oParams.Add('POOL_ExpireTimeout=600000');
oParams.Add('POOL_MaximumItems=1000');
FDManager.Close;
while FDManager.State <> dmsInactive do
Sleep(1);
FDManager.Open;
FDManager.AddConnectionDef('PG_Pooled', 'PG', oParams);
oParams.Free;
end;
constructor TDB.Create;
begin
inherited;
// init connection
DBC := TFDConnection.Create(nil);
DBC.ConnectionDefName := 'PG_Pooled';
DBC.LoginPrompt := False;
DBC.FetchOptions.Unidirectional := True;
DBC.UpdateOptions.RequestLive := False;
DBC.Transaction := DBT;
// init transaction
DBT := TFDTransaction.Create(nil);
DBT.Connection := DBC;
// init query
DBQ := TFDQuery.Create(nil);
DBQ.Connection := DBC;
DBQ.Transaction := DBT;
DBQ.FetchOptions.Unidirectional := True;
DBQ.UpdateOptions.RequestLive := False;
DBC.Connected := True;
end;
destructor TDB.Destroy;
begin
DBQ.Free;
DBT.Free;
DBC.Free;
inherited;
end;
initialization
InitPool;
end.
eg.
with TDB.Create do
begin
try
DBQ.SQL.Text := 'select * from table';
DBQ.Open;
while not DBQ.eof do
begin
S := S + DBQ.FieldByName('test').asString + '<br>' + FormatDateTime('ddmmyyyy hh:nn:ss', Now) + '<br>';
DBQ.Next;
end;
finally
Free;
end;
end;
kind regards
R.