httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stefan Eissing <stefan.eiss...@greenbytes.de>
Subject state of h2 (long)
Date Fri, 26 Feb 2016 17:06:24 GMT
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



Mime
View raw message