Add ioxide.Kestrel: ASP.NET Core Kestrel transport on the io_uring reactor#84
Merged
Conversation
…actor Adds a Kestrel transport (UseIoxide()) that runs each connection on an ioxide reactor, with the whole HTTP request loop (recv -> parse -> handler -> send) pinned to the reactor thread. Core engine (additive, opt-in — 3 touch points): - New Reactor.ScheduleOnReactor(): run a continuation on the reactor loop thread, reusing the existing eventfd wake-queue (drained once per loop iteration via DrainPostQ). Native inline execution is unchanged: when nothing schedules, the drain is a no-op on an empty queue. New ioxide.Kestrel package: - HopDuplexPipe: two System.IO.Pipelines pipes whose reader schedulers route to the reactor (ReactorPipeScheduler), plus recv->inbound and outbound->send pumps that run on the reactor. - IConnectionListenerFactory/Listener/Context bridging ioxide's push Handle model to Kestrel's pull AcceptAsync model. Public surface: UseIoxide() + options. Plaintext (i9-14900K, 8 reactors on 4 P-cores, net11): ~1.4M rps, ~1.5x the stock sockets transport, with ~100% of request processing on the reactor thread.
Minimal ASP.NET Core app with GET / and /plaintext endpoints. Selects the transport via the TRANSPORT env var: 'ioxide' (default, via UseIoxide()) or 'sockets' (stock Kestrel sockets). Added to ioxide.slnx.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
ioxide.Kestrel— an ASP.NET Core Kestrel transport backed by ioxide. Each connection runs on an ioxide reactor, and Kestrel's whole request loop (recv → parse → handler → send) is pinned to the reactor thread — no ThreadPool hop on the hot path. Drop-in viabuilder.WebHost.UseIoxide().Engine impact: minimal and opt-in
Only 3 additive touch points in the engine, with no behavioral change to the native inline path:
Reactor/Reactor.Post.cs(new):ScheduleOnReactor(Action<object?>, object?)+OnReactorThread, built on the existing_remoteOps/WakeFdWritemachinery — a queue drained once per loop iteration.Reactor.csandReactor.Incremental.cs: oneDrainPostQ();per loop.When nothing uses the scheduler (the native runtime, GenHTTP engine, pg/redis/file clients),
DrainPostQis a singleTryDequeueon an always-empty queue — effectively free, and inline execution is byte-for-byte unchanged. If you don't referenceioxide.Kestrel, the engine behaves exactly as before.How the transport works
HopDuplexPipehands Kestrel twoSystem.IO.Pipelines.Pipes whose reader schedulers are aReactorPipeScheduler(overReactor.ScheduleOnReactor). A recv pump copies received bytes into the inbound pipe and a send pump drains the response into the connection's send slab — both on the reactor. Routing the pipe reader continuations to the reactor is what keeps Kestrel's loop there (it's the one Kestrel-sanctioned hook for loop placement).Usage
Options:
UseIoxide(o => { o.ReactorCount = …; o.ConfigureServer = cfg => cfg with { … }; }).Benchmarks (single box, plaintext)
i9-14900K, net11, server pinned to 4 P-cores / 8 reactors,
wrkon 16 E-cores, median of 3:~1.5× the stock sockets transport, with ~100% of request processing on the reactor thread (verified by thread sampling), 0 errors. Caveats: single-box (the load generator shares the machine), small messages, Linux/io_uring only.
Notes
net11.0, referencesMicrosoft.AspNetCore.App, added toioxide.slnx.UseIoxide()+IoxideTransportOptions; everything else isinternal.