Re: HTTP/2 feedback/questions

On 25/07/2015 5:35 a.m., Valentin V. Bartenev wrote:
> Hello,
> 
> I've been working on HTTP/2 implementation in NGINX for the past few months.
> As a server-side developer I'd like to share some feedback about the protocol
> as well as take a chance to ask some question regarding the specification.
> 

Welcome to the circus. Its all fun and games...


> Here they are:
> 
>  1. The whole prioritization mechanism looks over-engineered.  The essential
>     thing it was designed to do is to determine what request need to be served
>     first.

Designed to cope with clients demanding that their content be served in
specific orders. In a spec largely driven by browser developers.

If you think about it carefully no one client is going to prioritize
another clients traffic over its own. So all clients will be demanding
top priority, their order, etc.

For servers prioritization is OPTIONAL. Dont mistake it for flow control
which is required, although they are related. Worst case you ignore the
demands and simply accept the sane-looking dependencies. Send whats
available as it becomes available. Then the things depending on those
come into focus as a set of more things to do. Weights make a bit more
sense at that point.

Dont whatever you do block sending something on due to priority while
the connectinon sits idle. Its preference priority, not a requirement.
Send whats ready to send.

Some of us server people will be prioritizing FIFO. Some a simple
dependency ordering. Some a weighting. Some might follow the spec.


... we got clowns and acrobats ...

> 
>     At the server side we have a few requests and a connection pipe, and all
>     we need is the order in which we should send response data.
> 
>     Instead we must maintain a dependency tree and support a bunch of
>     complicated operations over it, and the tree doesn't have any explicit
>     limitation.
> 
>     Seems like the KISS principle was forgotten.

Would you believe this *is* the simplest version the meets criteria from
both proponents of dependency and of weighting? no?


A lot of implementations are simply ignoring this section of the spec.
It is optional after all. Or implemented and tested only the parts that
are identical to SPDY (having had the already).


> 
>  2. A quote from the RFC:
> 
>    "an endpoint SHOULD retain stream prioritization state for a period after
>     streams become closed.  The longer state is retained, the lower the chance
>     that streams are assigned incorrect or default priority values."
> 
>     How long this period should be?

I was assured infinity was not quite long enough.

The original proposal was for immediate removals from a simple
dependency link from request N+1 to N. So one when data wanted to be
sent for some stream N+1 code could dereference its depndency and see
that N state was closed/missing and N+1 could go ahead. Or dereference
from N+1 and see N had data to push first in preference over the N+1 (or
not yet and N+1 could trickle some out). That N+1 or N could disappear
early was seamless, and no complex operations.

But adding weights and in particular weight redistribution means
everything pointing at N has to stay around so N weight could be
reassigned to them.

I suppose N could be removed after its weight has been reassigned. But
then it might have a prior dependency of its own that reassigns weight
to it later as well. Which would then need passing on, etc.

Keep in mind that no sender from which data is received is obliged to
obey the priority anyway. So streams all over the "tree" may finish
early or hang.

"Yuck" might be the word you are looking for.

> 
>     At first, a race condition was introduced, and then such a weak solution
>     was given.  It's another signal that the prioritization mechanism isn't in
>     a good shape.  Btw, there is no such problem in SPDY.
> 

Nod. SPDY also does not account for the levels of muliplexing that
middleware services have to deal with in HTTP/2. Sadly the text is just
mind-boggling. So it does not easily meet the needs that were put
forward as its case for being different from SPDY in the first place.

... swinging on trapeze  ...


>  3. Another quotes:
> 
>    "a relative weight, a number that is used to determine the relative
>     proportion of available resources that are assigned to streams dependent
>     on the same stream."
> 
>    "Streams with the same parent SHOULD be allocated resources proportionally
>     based on their weight."
> 
>    "Thus, if stream B depends on stream A with weight 4, stream C depends on
>     stream A with weight 12, and no progress can be made on stream A, stream B
>     ideally receives one-third of the resources allocated to stream C."
> 
>     ...there are also other mentions about "resource allocation" and
>     "available resources".
> 
>     What does it mean to allocate resources proportionally?  What kind of
>     resources?

The valuable resource of bandwith on the single TCP or TLS connection
being used by all these streams.


> 
>     The solution I've eventually come to is dividing the number of bytes
>     already sent in a response by these weights to determine the order of
>     following frames with the same dependency.
>     

Weights are weird. A weighting 20% vs 30% more than B makes little
difference when its a send/no-send choice being decided. As is common
for a server.

What both mean though is that if A and B are otherwise equal in priority
and dependencies, then A is more important than B so send it first. Then
divide A weight up and seen whats new highest weight fr sending next.
Might be B might be some other stream.


>  4. The compression ratio of Huffman encoding in HPACK varies between 1.6
>    (in the best case) and ~0.26..6 (in the worst case), and the spec doesn't
>     have requirement to avoid Huffman encoding when the ratio is 1 or lower.
> 
>     Also there's no number of uncompressed bytes stored, so to determine
>     the real length of field we need to decompress it first.  And we cannot
>     even have a good optimistic guess, because the ratio varies so much.

Expect infinity 'cause you have to add CONTINUATION frames decoded
payload if it turns out that was not even the end of the compressed bits.

>     
>     This creates a bunch of problems.  The most annoying of them is when
>     we actually reject a request due to some limitation and must use
>     as lower resources as possible, but we still need to decompress the
>     HPACK header block because of stateful nature of compression.

Welcome to the circus ... oh I said that already.

Reality is that the decompressor has to set a limit. The SETTINGS value
negotiates/adverties what that is. It can then limit its memory
allocation size. Any compressed headers exceeding that limit get an HTTP
headers-too-big error response. Same as big HTTP/1 messages do today.

The buffer already allocated for such messages can then be used as a
scratch area to complete the decode. But no worries about
loosing/overwriting decompressed data. Its all garbage at that point.

> 
>  5. What's the purpose of "Dynamic Table Size Update"?  Why does this thing
>     exist?  In what cases it should be used?

To update the size of the dynamic table. The often discussed use case is
when needing to completely change all or most of the contents of the
table. Sending an update to shrink its size to 0 then expanding again,
and starting to fill with new values.
 Lets both ends do a massive memory release and reset instead of
incremental replacing each header stored already.

The other use is for systems with limited resources who dont want to
allocate the default table size, to send a smaller (or larger maybe)
size for use on the rest of the connection. Messages recieved have to be
discarded until both ends sync up.

> 
>  6. Why the header that doesn't fit into dynamic table can be transfered
>     with indexing?  What's the purpose of eviction of all fields of dynamic
>     table?

I recall KISS being involved there. Its simpler and faster overall to
add, evict, remove than to special-case check on every header.


HTH
Amos

Received on Friday, 24 July 2015 19:41:42 UTC