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


Reply via email to