Hi Stefan,
I've had a real lack of time lately to do much on trunk's mod_http2 on
the windows side. The new mod_proxy_http2 requires a few functions from
mod_http2 and with what time I have had I have been unsuccessful
figuring out how to get these functions exported. So if you (or anyone
else) can figure this out, I'd appreciate it.
Gregg
On 2/26/2016 9:06 AM, Stefan Eissing wrote:
Things winding down here a bit before the weekend (at least I try) and I thought
I'd summarize a bit the state of HTTP/2 in our little project, because...well,
some
might be interested and certainly no one has the time to follow all my crazy
submits.
* trunk<-> 2.4.x
the version in 2.4.x has gathered a bit dust, as we made several tweaks in
trunk
in regard to async connection handling and scoreboard updates. These have
all been
backported, except one. Once that is through, I'll make a backport of
mod_http2,
so that 2.4.x gets all the nice new things.
* nice new things
in trunk we have the following additions:
- http/2 connections get queued properly when they become idle on the event
mpm.
that should be nice for people with many connections or long keepalives
configured.
- timeouts and keepalive timeouts are respected as for http/1 connections,
no extra
configuration.
- stability: with the interim releases in github and the help of nice
people, several
improvements have been made here and the 1.2.5 github has no reported open
blockers,
hanging connections or segfaults. All those changes are in trunk.
- server push: the module now remembers in each open connection which
resources
have already been pushed, using hash digests. This also implements an
outsketched
extension https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/
whereby
clients can send a highly compressed digest of the resources they have.
This is
very early and experimental and we'll see how/if browsers adapt this and
how
it will change over time.
- To offload worker threads, the module allows a number of file handles to
have
open. So, ideally, when serving static content, workers just lookup the
file,
return and the master connections streams them out. This number existed
before
as number per master connection. Now this number is multiplied by the
number of
workers and made a process wide pool where h2 connections can borrow
amounts.
Still, I am not totally satisfied with this. This should not be
configurable, but
httpd itself should check for ulimits of the process and configure itself,
I think.
- the scoreboard shows more information for h2 connections, such as its
connection
state and some stream statistics. Maybe the h2 workers should show up in a
separate
section on day...
127.0.0.1 http/1.1 test2.example.org:12345 wait, streams:
1/100/100/0/0 (open/recv/resp/push/rst)
- request engines! which leads us to:
* mod_proxy_http2
is configured just like other proxy modules with by using 'h2' or 'h2c' as
url prefix
in the configuration directives.
<IfModule proxy_http2_module>
<Proxy "balancer://h2-local">
BalancerMember "h2://test2.example.org:12346"
</Proxy>
ProxyPass "/h2proxy" "balancer://h2-local"
ProxyPassReverse "/h2proxy" "balancer://h2-local"
</IfModule>
Initially, it used one h2 connection for one request. The connection, and
the http2
session associated with it, was reused via the nice proxy infrastructure.
This is how things still are when the original connection is http/1.1
When this is http/2 itself, however, the first such request will register a
"request engine" that will accept more requests while the initial one is
still
being served and use the same backend connection for it. When the last
assigned
request is done, it unregisters and dissolves into fine mist.
The connection and h2 session stays as before, so a new request can reuse
the connection
in a new engine.
This works quite (but not 100%) reliable at the moment. There are still
some races when
requests are sent out while the backend is already shutting down and the
retry does
not catch all cases.
Important here is that requests for engines process all the usual hooks
and filters
and yaddayadda of our infrastructure, just like with http/1.1. This works
as follows:
- incoming request is handed to a worker thread as is done for all by
mod_http2
- httpd/proxy identifies the handler of mod_proxy_http2 as the responsible
- mod_proxy_http2 finds out what backend it shall talk to and ask from
mod_http2
(if present, the usual optionals) if there is already an engine for this
backend,
and that it is willing to host one if there is not.
- mod_http2, if it has one, *freezes* the task for this request (which
holds the
replacements for the core input/output filters on this slave connection)
and
returns that it will take care of it, once the handler is done. The
handler then
just returns as if it had processed the request.
Upon return of the worker, the mod_http2 sees a frozen task and makes it
ready
for processing in an engine. Next time the engine polls for more
requests, it is
forwarded.
- What is this freezing? Basically, an additional output filter that saves
all
incoming buckets for later. So, the EOR bucket is set aside here, for
example.
- Is it fast? No, not yet. Flow control handling is not optimal and I am
sure there
are lots of other places that can be improved.
- Then why? This way of handling proxy requests saves connections to the
backend
and threads in the server process. That should be motivation enough. If
httpd
is a reverse proxy, then doing the same work with 1-2 orders of
magnitude less
file handles and threads should be interesting.
- And: it could be done for mod_proxy_http, too! I see no reason why a
single
thread cannot use pollsets to juggle a couple of http/1.1 backend
connections
on top of a http/2 master connection.
Anyways, let me hear what you think. Anyone wants to help?
-Stefan