Maximum number of concurrent requests per Zap process
Hello,
I am trying to see how many concurrent requests can be served by Zap at a time and conducted the following test. However I am receiving connection reset by peer errors on the load generation tool. I am using hey (https://github.com/rakyll/hey) as the load generation tool. I followed the following steps:
- Copied https://github.com/zigzap/zap/tree/master/examples/hello_json example (modified the program following https://github.com/zigzap/zap/blob/master/blazingly-fast.md) into a src folder. Added following
build.zigandbuild.zig.zonfiles.
const std = @import("std");
const zap = @import("zap");
const User = struct {
first_name: ?[]const u8 = null,
last_name: ?[]const u8 = null,
};
fn on_request(r: zap.Request) void {
if (r.methodAsEnum() != .GET) return;
// /user/n
if (r.path) |the_path| {
if (the_path.len < 7 or !std.mem.startsWith(u8, the_path, "/user/"))
return;
const user_id: usize = @as(usize, @intCast(the_path[6] - 0x30));
const user = users.get(user_id);
var buf: [100]u8 = undefined;
var json_to_send: []const u8 = undefined;
if (zap.stringifyBuf(&buf, user, .{})) |json| {
json_to_send = json;
} else {
json_to_send = "null";
}
//std.debug.print("<< json: {s}\n", .{json_to_send}); // turn off debugging for now
r.setContentType(.JSON) catch return;
r.setContentTypeFromFilename("test.json") catch return;
r.sendBody(json_to_send) catch return;
}
}
const UserMap = std.AutoHashMap(usize, User);
var users: UserMap = undefined;
fn setupUserData(a: std.mem.Allocator) !void {
users = UserMap.init(a);
try users.put(1, .{ .first_name = "renerocksai" });
try users.put(2, .{ .first_name = "Your", .last_name = "Mom" });
}
pub fn main() !void {
const a = std.heap.page_allocator;
try setupUserData(a);
var listener = zap.HttpListener.init(.{
.port = 3000,
.on_request = on_request,
.log = false,
.max_clients = 100000,
});
try listener.listen();
std.debug.print(
\\ Listening on 0.0.0.0:3000
\\
\\ Check out:
\\ http://localhost:3000/user/1 # -- first user
\\ http://localhost:3000/user/2 # -- second user
\\ http://localhost:3000/user/3 # -- non-existing user
\\
, .{});
// start worker threads
zap.start(.{
.threads = 4,
.workers = 4, // although I have 8 cores, keep it for 4 cores for now.
});
}
const std = @import("std");
const CFlags = &.{};
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false,
});
const exe = b.addExecutable(.{
.name = "bootstrap",
.root_source_file = .{ .path = "src/hello_json.zig" },
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zap", zap.module("zap"));
exe.linkLibrary(zap.artifact("facil.io"));
b.installArtifact(exe);
}
.{
.name = "hello-world",
.paths = .{""},
.version = "0.1.0",
.minimum_zig_version = "0.12.0",
.dependencies = .{
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.7.0.tar.gz",
.hash = "12203126ff24e8018655eb7444c91f0d527d1213af16fcf2a578281abc994d01cc46",
},
},
}
-
Compiled the sample using:
zig build --summary all -
Started the program using:
./zig-out/bin/bootstrap
INFO: Listening on port 3000
Listening on 0.0.0.0:3000
Check out:
http://localhost:3000/user/1 # -- first user
http://localhost:3000/user/2 # -- second user
http://localhost:3000/user/3 # -- non-existing user
INFO: Server is running 8 workers X 8 threads with facil.io 0.7.4 (kqueue)
* Detected capacity: 131056 open file limit
* Root pid: 15403
* Press ^C to stop
INFO: 15417 is running.
INFO: 15415 is running.
INFO: 15413 is running.
INFO: 15414 is running.
INFO: 15416 is running.
INFO: 15419 is running.
INFO: 15418 is running.
INFO: 15420 is running.
- Ran the load generation tool and experienced connection resets by peer errors on the load generation tool:
hey -n 5000 -c 250 -m GET http://localhost:3000/user/1
hey -n 5000 -c 250 -m GET http://localhost:3000/user/1
Summary:
Total: 0.1737 secs
Slowest: 0.0395 secs
Fastest: 0.0001 secs
Average: 0.0078 secs
Requests/sec: 28785.3794
Total data: 222840 bytes
Size/request: 45 bytes
Response time histogram:
0.000 [1] |
0.004 [1804] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.008 [1409] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.012 [842] |■■■■■■■■■■■■■■■■■■■
0.016 [465] |■■■■■■■■■■
0.020 [235] |■■■■■
0.024 [57] |■
0.028 [43] |■
0.032 [79] |■■
0.036 [15] |
0.040 [2] |
Latency distribution:
10% in 0.0032 secs
25% in 0.0035 secs
50% in 0.0067 secs
75% in 0.0095 secs
90% in 0.0153 secs
95% in 0.0183 secs
99% in 0.0310 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0003 secs, 0.0001 secs, 0.0395 secs
DNS-lookup: 0.0002 secs, 0.0000 secs, 0.0084 secs
req write: 0.0000 secs, 0.0000 secs, 0.0081 secs
resp wait: 0.0065 secs, 0.0001 secs, 0.0208 secs
resp read: 0.0005 secs, 0.0000 secs, 0.0099 secs
Status code distribution:
[200] 4952 responses
Error distribution:
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51177->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51178->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51179->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51180->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51181->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51182->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51183->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51184->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51185->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51186->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51187->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51188->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51189->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51190->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51191->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51192->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51193->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51194->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51195->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51196->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51197->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51198->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51199->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51200->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51201->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51202->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51203->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51205->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51206->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51207->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51208->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51209->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51210->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51211->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51212->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51213->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51215->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51216->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51217->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51218->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51219->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51220->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51221->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51222->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51224->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51225->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51226->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000/user/1": read tcp [::1]:51228->[::1]:3000: read: connection reset by peer
I am trying to understand what would be the maximum number of concurrent connection supported by a single instance of Zap. If you would like me to post the question elsewhere, I am happy to do so. Thanks!
How do you think the UserMap is shared among 4 worker processes? I just checked. I, too, had 2 worker processes in the example. That is wrong. If you need to share state (zig variables), you can only have 1 worker.
Hello, I would think given we are only reading from the data structure (after initial write) sharing among multiple workers should be fine. Any way I tried with load testing example https://github.com/zigzap/zap/blob/master/wrk/zig/main.zig (4 threads, 4 workers) and getting same connection reset errors.
hey -n 5000 -c 250 -m GET http://localhost:3000
Summary:
Total: 0.1385 secs
Slowest: 0.0319 secs
Fastest: 0.0001 secs
Average: 0.0062 secs
Requests/sec: 36104.0699
Total data: 83436 bytes
Size/request: 17 bytes
Response time histogram:
0.000 [1] |
0.003 [1166] |■■■■■■■■■■■■■■■■■■■■■■
0.006 [2101] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.010 [850] |■■■■■■■■■■■■■■■■
0.013 [387] |■■■■■■■
0.016 [194] |■■■■
0.019 [60] |■
0.022 [45] |■
0.026 [78] |■
0.029 [2] |
0.032 [24] |
Latency distribution:
10% in 0.0026 secs
25% in 0.0034 secs
50% in 0.0043 secs
75% in 0.0077 secs
90% in 0.0117 secs
95% in 0.0154 secs
99% in 0.0247 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0002 secs, 0.0001 secs, 0.0319 secs
DNS-lookup: 0.0001 secs, 0.0000 secs, 0.0073 secs
req write: 0.0000 secs, 0.0000 secs, 0.0050 secs
resp wait: 0.0051 secs, 0.0001 secs, 0.0207 secs
resp read: 0.0003 secs, 0.0000 secs, 0.0058 secs
Status code distribution:
[200] 4908 responses
Error distribution:
[1] Get "http://localhost:3000": read tcp [::1]:49935->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49936->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49937->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49939->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49940->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49941->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49942->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49943->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49944->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49945->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49946->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49947->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49948->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49949->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49950->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49951->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49952->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49953->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49954->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49955->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49956->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49957->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49958->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49959->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49960->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49961->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49962->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49963->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49964->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49965->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49966->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49967->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49968->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49969->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49970->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49971->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49972->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49974->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49976->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49977->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49979->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49981->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49983->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49984->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49987->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49988->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49989->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49990->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49992->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49993->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49994->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49995->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49996->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49997->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49998->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:49999->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50001->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50002->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50004->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50005->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50006->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50008->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50009->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50010->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50011->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50015->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50020->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50021->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50022->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50025->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50027->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50028->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50029->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50030->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50032->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50033->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50034->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50036->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50037->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50039->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50040->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50041->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50042->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50043->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50044->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50045->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50046->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50047->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50048->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50049->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50051->[::1]:3000: read: connection reset by peer
[1] Get "http://localhost:3000": read tcp [::1]:50052->[::1]:3000: read: connection reset by peer
I checked https://github.com/zigzap/zap/blob/master/blazingly-fast.md and see it was able to handle 400 concurrent requests.
I re-ran the same test with wrk and I see some socket read errors -- so not all requests were successful ( similar behavior to hey).
wrk -t4 -c250 -d10s http://localhost:3000 --latency
Running 10s test @ http://localhost:3000
4 threads and 250 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 8.52ms 4.22ms 24.78ms 63.79%
Req/Sec 5.96k 2.14k 16.51k 81.06%
Latency Distribution
50% 8.54ms
75% 11.49ms
90% 14.09ms
99% 17.95ms
237279 requests in 10.02s, 35.98MB read
Socket errors: connect 0, read 117, write 0, timeout 0
Requests/sec: 23680.16
Transfer/sec: 3.59MB