hyper v0.11
The async release of hyper is here, version 0.11.0. There’s an updated website, and new guides to try to help you get up to speed with all the changes.
hyper is an HTTP library built in Rust, providing fast and safe client and server implementations.
v0.11
This release marks a form of stability for async hyper. This isn’t saying hyper’s API won’t continue to evolve (and break), but that when such a break happens, it will happen in a v0.12, and the changes will be concentrated. It should be possible to start building frameworks and tools using v0.11.
Even before v0.11 was tagged, many were so excited by the prospects of async hyper, they already are using it. Some examples:
- sccache has been using hyper’s
Client
to manage resources in S3. - npm uses hyper for their Registry change stream
Async
The biggest deal here, of course, is the switch to non-blocking (or “async”) IO. This has been the push for this release for a long time, and the landscape in the Rust community changed a lot while we were working on this. Last year, a framework for building asynchronous network protocols was released, Tokio. There a lot of great things to say about it, and hyper has embraced it fully.
This means a big change in API.
For instance, Request
and Response
bodies are no longer used via the std::io::{Read, Write}
traits. Instead, bodies are Stream
s of bytes. Streams are essentially a Future
that can resolve multiple times, which matches how an async connection works: bunches of bytes are received at different times.
By integrating with Tokio, hyper and the community gain a lot. Adding in Transport Layer Security is just combining hyper::server::Http
with something like tokio_tls::TlsServer
. That same TlsServer
can be plugged into any protocol, and Http
can be wrapped in any other community piece implementing the right trait. The same can be done with other concepts, like generic timeouts.
Hop over to the guides if you’d like to see how to get working examples.
Headers
Being a large breaking change release, an opportunity was taken to refine the headers system in hyper. Some standout changes:
- A
Raw
type was added, and theset_raw
,get_raw
, etc methods now use it. It allows for a more ergonomic way of adding raw header values, and it’s also faster when aRaw
in most cases. - The
HeaderFormat
trait has been merged into theHeader
trait. They were previously separate due to trait object safety rules, but now that trait methods can have awhere Self: Sized
added, there is no need to separate them. - The semantics of
Header::fmt_header
were clarified. Most of the time, headers can be written on one line. There is the rare exception (technically onlySet-Cookie
is specified) where each “value” must be on a separate line. Now,fmt_header
receives ahyper::header::Formatter
, with only afmt_line
method. Pretty much every header can just implementstd::fmt::Display
, and callf.fmt_line(self)
, but nowSet-Cookie
doesn’t need to use a hack to format itself.
Performance
hyper v0.10 was no slouch. It can churn through requests and pump out responses. However, as it uses blocking IO, it hits a problem when you have tons of connections to your server at the same time. Blocking IO means it needs to use multiple threads, only being able to deal with 1 connection per thread. Threads, when you have a lot, get to be expensive.1 So, switching to non-blocking IO means that we keep going fast, but each additional connection isn’t nearly as expensive.
hyper v0.11 is fast2, and handles thousands of connections like a champ.
Changelog
The changes are big. There is a changelog if you want to see all of them. The changelog tries to only contain changes from v0.10, but it’s not exhaustive.
Thanks
There are a lot of people to thank for getting this release out the door. This really is a fantastic community.
Next
hyper is now tracking the Futures and Tokio crates. Work is happening in there as well, as we find patterns and problems that aren’t unique to hyper, and should be available for any async protocol.
There has been community desire (and on the hyper team too!) to stabilize some sort of http
crate. This would contain types for handle statuses, methods, versions, and headers, but without client or server or protocol version implementations. We’re trying to find a good design that supports all the possible use cases, and HTTP1 and HTTP2, without sacrificing any performance. Once such a thing exists, hyper would likely replace the types it uses with those.
In doing the above, that may mean that hyper’s current headers system won’t fit. It might make sense to break that out into its own crate, so that people who want typed headers can have them, while a bare bones server could live without them. This would also help reqwest in its road to 1.0, since it publicly exports hyper::headers
, but hyper likely won’t reach v1.0 before it.
And of course, we always want to go faster. That will never stop!
v0.11.0
Again, go get it! Read the new guides. Tell us what you think!
-
hyper uses a set number of threads, not growing as more connections are made. It’s a different trade off, but not too relevant for explaining why non-blocking IO is better. ↩
-
hyper doesn’t lead the pack in benchmarks (yet), but it’s not in the back either. The last benchmark put it at 58% requests per second of the fastest. Since that benchmark was published, some significant low-hanging improvements were made. A new preview should be available soon. And we’ll keep going! ↩