Compare commits
	
		
			5 commits
		
	
	
		
			8b8463cd6a
			...
			abc26837a0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| abc26837a0 | |||
| 6f1e37b391 | |||
| 500847f571 | |||
| 46d73f3983 | |||
| f697e69d45 | 
					 5 changed files with 41 additions and 17 deletions
				
			
		
							
								
								
									
										38
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										38
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -26,13 +26,33 @@ library can be found in src/main-lib.zig.
 | 
				
			||||||
Architecture
 | 
					Architecture
 | 
				
			||||||
------------
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TODO:
 | 
					This library assumes the use of Linux as a host. While the primary engine is not
 | 
				
			||||||
 | 
					tied to Linux, the file watcher module uses inotify and friends and will not
 | 
				
			||||||
 | 
					work outside that OS. PRs are welcome.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
We assume Linux.
 | 
					The system is built with a pre-release version of zig, currently zig version
 | 
				
			||||||
 | 
					[0.11.0-dev.3312+ab37ab33c](https://github.com/marler8997/zig-unofficial-releases#0110-dev3312ab37ab33c-summary).
 | 
				
			||||||
 | 
					This version has web server in the standard library, so it is useful.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Built with zig 0.11.0-dev.3312+ab37ab33c (provide permalink). Explain lock to 0.11 when released.
 | 
					To achieve the lowest latency possible, this server loads dynamic libraries
 | 
				
			||||||
 | 
					using [dlopen(3)](https://linux.die.net/man/3/dlopen) based on a configuration
 | 
				
			||||||
 | 
					file in the current working directory called `proxy.ini`. An example of the
 | 
				
			||||||
 | 
					configuration is in this directory, and it is relatively simple string prefix
 | 
				
			||||||
 | 
					matching, again, for speed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To achieve the lowest latency possible and eliminate the proliferation, The architecture of this server is setup 
 | 
					On startup, a thread pool will be created. Request paths and header matching
 | 
				
			||||||
 | 
					is loaded from the configuration file, and file watches are initiated on all
 | 
				
			||||||
 | 
					libraries mentioned in the configuration file. Libraries are loaded on demand
 | 
				
			||||||
 | 
					when a request arrives that needs the library. When a library changes for a new
 | 
				
			||||||
 | 
					version, the file watcher will take note and unload the previous version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Changes to the configuration file are not watched, relying instead on a HUP
 | 
				
			||||||
 | 
					signal to force a reload. At that point, all libraries ("executors") are
 | 
				
			||||||
 | 
					unloaded, and configuration is re-read.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As libraries are loaded directly into main process space, bugs in the libraries
 | 
				
			||||||
 | 
					can and will crash the engine. As such, some supervisory process (dockerd,
 | 
				
			||||||
 | 
					systemd, etc) should monitor and restart if necessary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Security
 | 
					Security
 | 
				
			||||||
--------
 | 
					--------
 | 
				
			||||||
| 
						 | 
					@ -53,11 +73,13 @@ reported by the system (although thread count is limited to 4 threads when
 | 
				
			||||||
compiled in debug mode). This can be controlled with the environment variable
 | 
					compiled in debug mode). This can be controlled with the environment variable
 | 
				
			||||||
`SERVER_THREAD_COUNT`.
 | 
					`SERVER_THREAD_COUNT`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Future plans include an environment variable for IP address and port to listen
 | 
					The port by default is 8069, although this can be set with the `PORT`
 | 
				
			||||||
on, as well as the amount of pre-allocated memory for response data (currently
 | 
					environment variable. Future plans include an environment variable for IP
 | 
				
			||||||
hardcoded to 1k/thread). Pre-allocated memory reduces the number of system
 | 
					address as well as the amount of pre-allocated memory for response data (currently
 | 
				
			||||||
 | 
					hardcoded to 8k/thread). Pre-allocated memory reduces the number of system
 | 
				
			||||||
calls required for memory allocation, and pre-allocation/allocation statistics
 | 
					calls required for memory allocation, and pre-allocation/allocation statistics
 | 
				
			||||||
per request are reported in the logs.
 | 
					per request are reported in the logs. The current pre-allocation provides
 | 
				
			||||||
 | 
					approximately 4k per request without requiring system calls.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Logs
 | 
					Logs
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,7 @@ pub fn build(b: *std.Build) void {
 | 
				
			||||||
    const optimize = b.standardOptimizeOption(.{});
 | 
					    const optimize = b.standardOptimizeOption(.{});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const exe = b.addExecutable(.{
 | 
					    const exe = b.addExecutable(.{
 | 
				
			||||||
        .name = "faas-proxy",
 | 
					        .name = "flexilib",
 | 
				
			||||||
        // In this case the main source file is merely a path, however, in more
 | 
					        // In this case the main source file is merely a path, however, in more
 | 
				
			||||||
        // complicated build scripts, this could be a generated file.
 | 
					        // complicated build scripts, this could be a generated file.
 | 
				
			||||||
        .root_source_file = .{ .path = "src/main.zig" },
 | 
					        .root_source_file = .{ .path = "src/main.zig" },
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ pub fn build(b: *std.Build) void {
 | 
				
			||||||
    exe.linkLibC();
 | 
					    exe.linkLibC();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const lib = b.addSharedLibrary(.{
 | 
					    const lib = b.addSharedLibrary(.{
 | 
				
			||||||
        .name = "faas-proxy-sample-lib",
 | 
					        .name = "flexilib-sample-lib",
 | 
				
			||||||
        // In this case the main source file is merely a path, however, in more
 | 
					        // In this case the main source file is merely a path, however, in more
 | 
				
			||||||
        // complicated build scripts, this could be a generated file.
 | 
					        // complicated build scripts, this could be a generated file.
 | 
				
			||||||
        .root_source_file = .{ .path = "src/main-lib.zig" },
 | 
					        .root_source_file = .{ .path = "src/main-lib.zig" },
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,7 @@ pub fn build(b: *std.Build) void {
 | 
				
			||||||
    lib.linkLibC();
 | 
					    lib.linkLibC();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const interface_lib = b.addStaticLibrary(.{
 | 
					    const interface_lib = b.addStaticLibrary(.{
 | 
				
			||||||
        .name = "libfaasproxy",
 | 
					        .name = "flexilib",
 | 
				
			||||||
        // In this case the main source file is merely a path, however, in more
 | 
					        // In this case the main source file is merely a path, however, in more
 | 
				
			||||||
        // complicated build scripts, this could be a generated file.
 | 
					        // complicated build scripts, this could be a generated file.
 | 
				
			||||||
        .root_source_file = .{ .path = "src/interface.zig" },
 | 
					        .root_source_file = .{ .path = "src/interface.zig" },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Example of match based on an HTTP header. The key is space-delimited:
 | 
					# Example of match based on an HTTP header. The key is space-delimited:
 | 
				
			||||||
# <http header key>: <header match prefix> <path match prefix>
 | 
					# <http header key>: <header match prefix> <path match prefix>
 | 
				
			||||||
Host: iam / = zig-out/lib/libfaas-proxy-sample-lib.so
 | 
					Host: iam / = zig-out/lib/libflexilib-sample-lib.so
 | 
				
			||||||
/c = zig-out/lib/libfaas-proxy-sample-lib-in-c.so
 | 
					/c = zig-out/lib/libflexilib-in-c.so
 | 
				
			||||||
/ = zig-out/lib/libfaas-proxy-sample-lib.so
 | 
					/ = zig-out/lib/libflexilib-sample-lib.so
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ pub const Request = extern struct {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// If the library is Zig, we can use these helpers
 | 
					// If the library is Zig, we can use these helpers
 | 
				
			||||||
var allocator: ?*std.mem.Allocator = null;
 | 
					threadlocal var allocator: ?*std.mem.Allocator = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const log = std.log.scoped(.interface);
 | 
					const log = std.log.scoped(.interface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,7 +120,6 @@ pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?*
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    log.debug("response ptr: {*}", .{response.items.ptr});
 | 
					 | 
				
			||||||
    // Marshall data back for handling by server
 | 
					    // Marshall data back for handling by server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var rc = alloc.create(Response) catch {
 | 
					    var rc = alloc.create(Response) catch {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -362,7 +362,10 @@ pub fn main() !void {
 | 
				
			||||||
    var server = std.http.Server.init(allocator, .{ .reuse_address = true });
 | 
					    var server = std.http.Server.init(allocator, .{ .reuse_address = true });
 | 
				
			||||||
    defer server.deinit();
 | 
					    defer server.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const address = try std.net.Address.parseIp("0.0.0.0", PORT);
 | 
					    const address = try std.net.Address.parseIp(
 | 
				
			||||||
 | 
					        "0.0.0.0",
 | 
				
			||||||
 | 
					        if (std.os.getenv("PORT")) |p| try std.fmt.parseInt(u16, p, 10) else PORT,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    try server.listen(address);
 | 
					    try server.listen(address);
 | 
				
			||||||
    const server_port = server.socket.listen_address.in.getPort();
 | 
					    const server_port = server.socket.listen_address.in.getPort();
 | 
				
			||||||
    log.info("listening on port: {d}", .{server_port});
 | 
					    log.info("listening on port: {d}", .{server_port});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue