Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unix Domain Socket support #163

Merged
merged 9 commits into from Dec 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
64 changes: 64 additions & 0 deletions SQLite3/Samples/36 - Simple REST Benchmark/README.md
@@ -0,0 +1,64 @@
# Simple mORMot server for REST benchmark

## Socket based server

- compile and run RESTBenchmark
- test it with browser:
- http://localhost:8888/root/abc
- http://localhost:8888/root/xyz
- test it with Apache Bench
```
ab -n 10000 -c 1000 http://localhost:8888/root/abc
```

## Keep alive
By default mROMot HTTP server runs in KeepAlive mode.

To disable KeepAlive run `RESTBenchmark` with secont parameter `false`
```
./RESTBenchmark 8888 false
```

Disabling KeepAlive make sence in case mORMotserver is behind the reverse proxy.
In this case reverse proxy cares about KeepAlive connection pool and mormot can
operate with fixed thread pool size.

## Unix Domain Socket (Linux)

### When to use
In case mORMot is behind a local reverse proxy on the environment with a
huge number of incoming connection it's make sence to use a UDS to minimize
unnecessary TCP handshakes between mORMot and reverse proxy.

To emulate such environment on the syntetic test we can disable keep alive
in RESTBEnchmark by passing `false` to then second parameter
```
./RESTBenchmark unix false
./RESTBenchmark 8888 false
```

### How to run

- compile program and run with `unix` parameter
```
./RESTBenchmark unix
```

Benchmark will listen on Unix Domain Socket `/tmp/rest-bench.socket`

- test it with curl
```
curl --unix-socket /tmp/rest-bench.socket http://localhost/root/abc
```

- setup nginx as a reverse proxy
```
sudo ln -s "$(pwd)/mormot-rest-nginx.conf" /etc/nginx/sites-available
sudo ln -s /etc/nginx/sites-available/mormot-rest-nginx.conf /etc/nginx/sites-enabled
sudo nginx -s reload
```

- test it using ab (or better - wrk)
```
wrk http://localhost:8888/root/abc
```
35 changes: 30 additions & 5 deletions SQLite3/Samples/36 - Simple REST Benchmark/RESTBenchmark.dpr
Expand Up @@ -8,13 +8,15 @@ program RESTBenchmark;
- ab -n 1000 -c 100 http://localhost:8888/root/xyz
for bandwidth measure (returns some ORM query as 77KB of JSON)
}

{$ifndef UNIX}
{$APPTYPE CONSOLE}
{$endif}

uses
{$I SynDprUses.inc} // use FastMM4 on older Delphi, or set FPC threads
SysUtils,
SynCommons, // framework core
SynCrtSock, // direct access to HTTP server
SynLog, // logging features
mORMot, // RESTful server & ORM
mORMotSQLite3, // SQLite3 engine as ORM core
Expand Down Expand Up @@ -99,7 +101,7 @@ begin
ctxt.Returns(s);
end;

procedure DoTest;
procedure DoTest(const url: AnsiString; keepAlive: boolean);
var
aRestServer: TSQLRestServerDB;
aHttpServer: TSQLHttpServer;
Expand All @@ -114,10 +116,15 @@ begin
aServices := TMyServices.Create(aRestServer);
try
// serve aRestServer data over HTTP
aHttpServer := TSQLHttpServer.Create('8888',[aRestServer]);
aHttpServer := TSQLHttpServer.Create(url,[aRestServer]);
if not keepAlive and (aHttpServer.HttpServer is THttpServer) then
THttpServer(aHttpServer.HttpServer).ServerKeepAliveTimeOut := 0;
try
aHttpServer.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries
writeln('Background server is running.'#10);
write('Background server is running on ', url, ' keepAlive ');
if (keepAlive) then
writeLn('is enabled') else
writeLn('is disabled');
write('Press [Enter] to close the server.');
readln;
finally
Expand All @@ -131,12 +138,30 @@ begin
end;
end;

const
UNIX_SOCK_PATH = '/tmp/rest-bench.socket';

var
url: AnsiString;
keepAlive: boolean;

begin
// set logging abilities
SQLite3Log.Family.Level := LOG_VERBOSE;
//SQLite3Log.Family.EchoToConsole := LOG_VERBOSE;
SQLite3Log.Family.PerThreadLog := ptIdentifiedInOnFile;
DoTest;
SQLite3Log.Family.NoFile := true; // do not create log files for benchmark
{$ifdef UNIX}
if (ParamCount>0) and (ParamStr(1)='unix') then begin
url := 'unix:' + UNIX_SOCK_PATH;
if FileExists(UNIX_SOCK_PATH) then
DeleteFile(UNIX_SOCK_PATH); // remove socket file
end else
{$endif}
url := '8888';
if (ParamCount>1) and (ParamStr(2)='false') then
keepAlive := false else
keepAlive := true;
DoTest(url, keepAlive);
end.

54 changes: 54 additions & 0 deletions SQLite3/Samples/36 - Simple REST Benchmark/RESTBenchmark.lpi
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="11"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="RESTBenchmark"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
<Modes Count="0"/>
</RunParams>
<Units Count="1">
<Unit0>
<Filename Value="RESTBenchmark.dpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="RESTBenchmark"/>
</Target>
<SearchPaths>
<IncludeFiles Value="../..;../../..;$(ProjOutDir;$(ProjOutDir)"/>
<OtherUnitFiles Value="../..;../../.."/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
</CompilerOptions>
<Debugging>
<Exceptions Count="1">
<Item1>
<Name Value="Unknown"/>
<Enabled Value="False"/>
</Item1>
</Exceptions>
</Debugging>
</CONFIG>
59 changes: 59 additions & 0 deletions SQLite3/Samples/36 - Simple REST Benchmark/mormot-rest-nginx.conf
@@ -0,0 +1,59 @@
upstream mormot-uds {
server unix:/tmp/rest-bench.socket;
keepalive 32;
}

upstream mormot-sock {
server localhost:8888;
keepalive 32;
}

server {
listen 8889;

server_name localhost;

access_log /dev/null;
# prevent nginx version exposing in Server header
server_tokens off;

proxy_set_header Host $host;
# Tell upstream real IP address of client
proxy_set_header X-Real-IP $realip_remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Do not rewrite a URL while pass it to upstream
proxy_redirect off;
# Let's upstream handle errors
proxy_intercept_errors on;
tcp_nodelay on;

# proxy all requests to the beckend
location / {
proxy_pass http://mormot-sock;
}
}

server {
listen 8887;

server_name localhost;

access_log /dev/null;
# prevent nginx version exposing in Server header
server_tokens off;

proxy_set_header Host $host;
# Tell upstream real IP address of client
proxy_set_header X-Real-IP $realip_remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Do not rewrite a URL while pass it to upstream
proxy_redirect off;
# Let's upstream handle errors
proxy_intercept_errors on;
tcp_nodelay on;

# proxy all requests to the beckend
location / {
proxy_pass http://mormot-uds;
}
}