You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Previously, we had evaluated use of tokio within the modules. The results weren't reassuring:
nginx is optimized to be a multi-process single-threaded application. None of the internal APIs are thread safe, and it's extremely dangerous to call some methods from another thread (anything that deals with IO scheduling, timers or other globals). Rare cases of thread interaction (thread pools in aio threads) are not cross-platform and have bottlenecks. Additionally, the notification method from the thread pools (ngx_notify) is a private detail, not reusable without changing the API.
Any data sent to the tokio runtime should be fully copied and detached from the nginx internal structures (ngx_http_request_t). That is expensive.
Any events, including incoming body, generated response bytes, abnormal termination of the request, etc, must be passed between threads through a synchronized event queue. Said event queue should integrate with the nginx main loop using platform-dependent methods (eventfd, kevent, etc) or risk degrading performance even more.
Thread synchronization may cause delayed or blocking reaction on the nginx events. E.g. task cancellation when the request is aborted and the cleanup handler is running, must be synchronous.
Threads mess up CPU affinities, data locality, etc. That adds to the already non-negligible costs of copying the data.
Ideally, we want to have everything in the main thread of a worker process, unless it's a blocking task that should be offloaded to the thread pool.
Considering all of the above, it appears to be safer and simpler for us to implement our own task executor running on top of the nginx event loop. The Rust ecosystem offers enough components and examples for that.
The MVP goal for this task is to be able to run hyper/client as an upstream implementation; that is a sufficiently complex use case for an async runtime.
The text was updated successfully, but these errors were encountered:
Previously, we had evaluated use of
tokio
within the modules. The results weren't reassuring:nginx is optimized to be a multi-process single-threaded application. None of the internal APIs are thread safe, and it's extremely dangerous to call some methods from another thread (anything that deals with IO scheduling, timers or other globals). Rare cases of thread interaction (thread pools in
aio threads
) are not cross-platform and have bottlenecks. Additionally, the notification method from the thread pools (ngx_notify
) is a private detail, not reusable without changing the API.ngx_http_request_t
). That is expensive.eventfd
,kevent
, etc) or risk degrading performance even more.Ideally, we want to have everything in the main thread of a worker process, unless it's a blocking task that should be offloaded to the thread pool.
Considering all of the above, it appears to be safer and simpler for us to implement our own task executor running on top of the nginx event loop. The Rust ecosystem offers enough components and examples for that.
The MVP goal for this task is to be able to run
hyper/client
as an upstream implementation; that is a sufficiently complex use case for an async runtime.The text was updated successfully, but these errors were encountered: