Subject: Concerns about HTTP/2 Priority

From: Chad Austin <[email-masked]>
Date: Sun, 2 Nov 2014 22:19:37 -0800

Hi!

Sorry if you're tired of hearing about priority.  :)  Having spent some
time working out the pros, cons, and implications of the tree-based
priority model, I have serious concerns that shipping HTTP/2 priority as it
stands would be harmful.

In this email I will enumerate the disadvantages of the HTTP/2 priority
model that I see and propose a couple options.

*# The Advantage of a Stream Dependency Model for Prioritization*

There is an advantage to using a DAG to specify priority: a DAG is a
natural and direct way to specify a partial ordering and does not require
the selection of arbitrary numeric values.  (e.g. HTML at priority 100, CSS
at priority 80, images at priority 20, etc.)

*# The Problems with HTTP/2 Priority*

*1. A tree cannot express some common priority schedules*

While the original SPDY/4 priority proposal [
https://groups.google.com/forum/#!topic/spdy-dev/-d9Auoun4HU/discussion ]
was a DAG, what got adopted in HTTP/2 is a tree.  A tree is not sufficient
to express some common priority schedules, like "all CSS and JS before any
images".

In HTTP/2, the only way to express "All JS/CSS before all images" is a
linked list [
http://lists.w3.org/Archives/Public/ietf-http-wg/2014OctDec/0164.html ],
which has the side effect of defining a strict ordering within the JS/CSS
group, implying that individual JS and CSS responses should be serialized
relative to each other.  For JS and CSS, finishing one response before
beginning the next is probably the right call* but there are asset types
where parallel transfer is beneficial (e.g. progressive images, VIPM 3D
meshes).  Thus, a linked list is less expressive than numeric priorities
here.

* though Ilya Grigorik argued for parallel high-priority resource transfer
here:
http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Oct/0180.html
 I suppose the argument is that, given an unknown distribution of response
sizes (e.g. 100 KB JS, 1 KB CSS), it's better to transfer in parallel so
that small responses reliably complete before larger responses, avoiding
the scenario where a small CSS file is blocked by a much larger JS file.

*_Prebuttal: Weights do not solve for prioritization_*

A common misconception is that weights can be used to fine-tune
priorities.  In fact, the WIP Firefox implementation of HTTP/2 simply maps
Firefox's internal numeric priority values to HTTP/2 weights.  However,
weights and priorities are different concepts, and an accurate and complete
server-side implementation of HTTP/2 as drafted would allocate some
resources to low-weighted streams if they're at the same priority as
high-weighted streams.

Recently someone pushed this argument further, and said that if HTML/JS/CSS
had weight 256 and images had weight 1, then negligible bandwidth is
allocated to images until HTML/JS/CSS are complete...  for a small number
of images, that's true.  But, then, let's say you had high-priority images
and low-priority images?  You'd have to give HTML/JS/CSS weight=256,
medium-priority images weight=16, and low-priority images weight=1.
 (256/16 = 16/1).  If there are 16 times as many medium-priority images as
HTML/CSS/JS, fully half of the bandwidth will be allocated to the
medium-priority images as the high-priority HTML/JS/CSS.

My point is that using weights as priorities doesn't really work for
anything but the simplest scenarios.

*_Prebuttal: "Well, you can use a custom prioritization scheme with an
HTTP/2 protocol extension"_*

But, then, what's the point of shipping a standard if it requires, in some
common cases, a protocol extension?  Ideally applications, browsers,
akamai, nginx, varnish, etc. would all interoperate and requiring a
protocol extension makes that a lot harder.  This working group is the
appropriate place to solve for priority, and now is the appropriate time.

*2. Reprioritization is O(depth) and thus can be O(n)*

In HTTP/2, reprioritization is O(depth(new_parent) - depth(stream)) due to
the cycle check.  Thus, reprioritizing N nodes in a linked list is O(N^2).

While not the worst problem in the world, it's another subtle bit of
complexity that must be managed and protected against denial of service.

*3. I'm not sure HTTP/2 even solves the proxy use case*

When I asked why HTTP/2 specifies priority with tree dependencies, the
answer I was given was that it allows fairly multiplexing incoming HTTP/2
connections across a single backend HTTP/2 connection.  But does it?  [
http://lists.w3.org/Archives/Public/ietf-http-wg/2014OctDec/0309.html ]

Since HTTP/2 does not support dummy nodes in the priority tree (and I'll
explain later why that wouldn't even help), multiple top-level nodes in
each inbound stream would have to become a top-level weighted stream on the
outbound connection.  The weights ought to be allocated fairly, which means
any *additional* inbound stream has to fairly reweight other streams from
that connection.

Visually:

Inbound connection A: {A1, A2, A3} -> 0
Inbound connection B: {B1, B2} -> 0
Outbound connection: {A1[w=1/6],A2[w=1/6],A3[w=1/6],B1[w=1/4],B2[w=1/4]} ->
0

Now consider what happens when a new stream arrives from A.  Outbound A1,
A2, and A3 have to be reweighted.  Now consider what happens when B1
completes.  The proxy would have to notice that B1 is done, and B2 should
be reweighted to 1/2.  In the meantime, A is given a larger allocation of
backend resources.

I question whether stream dependencies is a realistic solution to the proxy
use case.  I suspect a more direct protocol for specifying stream groups
and weights would be simpler, more accurate, and more expressive.

In the *very least*, I would love somebody on this list to explain in
detail how the proxy use case is supposed to work.  I don't see it yet.
Osama Mazahir's explicit stream groups proposal is a more direct solution.

*4. There's no production implementation experience with stream dependency
priorities*

I think the issues I've enumerated above would be discovered when trying to
implement and profile HTTP/2 across browsers, CDNs, proxies, and so on.
But if HTTP/2 is destined to be a widespread standard, it might be too late
by then.

Was the theory that SPDY/4 would be the testing ground for these ideas, but
instead they got adopted in a limited form into HTTP/2?  Hard to say - I
haven't heard anything from Googlers since I started looking into this.

*# What now?*

I don't think HTTP/2 priority should ship as it is currently drafted.  What
are the other options?

*1. Ship HTTP/2 without priority and evolve priority as an extension.*

I'm not a fan of this option because priority is critically important.
Multiplexed streams without priority are slower than HTTP across N
connections.

*2. Replace the tree model with a DAG (multiple parents)*

A DAG, that is, allowing streams to have multiple parents, would solve the
"all HTML/JS/CSS in parallel, then all images in parallel" use case.
However, allowing multiple parents introduces a great deal of complexity
and chattiness into the protocol, including a potentially quadratic number
of bytes sent over the connection.  I don't recommend this path forward.

*3. Write a document describing how all of these use cases are supposed to
work*

Maybe I'm missing some key detail and my analysis above is completely
wrong.  If so, I'd love to see something that precisely describes how these
use cases are supposed to work.  How are browsers supposed to initiate
stream requests given existing pageload prioritization algorithms?  How
exactly are proxies supposed to work?

4. *Adopt Osama Mazahir's proposal*

In February, Osama Mazahir proposed an implementation of HTTP/2 priorities
that solves all of the use cases above.
http://lists.w3.org/Archives/Public/ietf-http-wg/2014JanMar/0396.html  For
a reason I haven't yet heard, it wasn't considered obviously better than
stream dependencies, and it lost in a coin flip in London:
http://msopentech.com/blog/2014/03/19/http2-nearing-completion/

I've heard one concern about numeric priorities: switching browser tabs
ought to reprioritize all existing requests.  This would cause N
reprioritization requests to be sent, where N is the number of active
requests.  However, I think that concern may be minor.  For almost all
realistic values of N, the frame(s?) to reprioritize N active streams could
fit in a single Ethernet MTU.

My preferred solution to fixing HTTP/2 priority is to adopt Osama's
Mazahir's proposal.  It's simple, direct, and browsers and SPDY currently
use numeric priorities anyway.

*# Why Priority is Critical*

Page load optimization is hitting diminishing returns.  Bandwidth is going
up, but connection latency is not really going down over time.  Priority is
a huge lever for improving page load experience by reducing round-trips and
making full use of the network pipe.  Getting priority right is critical --
HTTP/2 will rapidly become one of the most popular protocols in the world,
and getting priority right has enormous potential upside in latency and
efficiency.  I just don't see how the tree dependency model meets even
current use cases, which makes me think it's a bad idea to ship a protocol
based on it.

Thanks for reading,
Chad

--
Chad Austin
Technical Director, IMVU
http://chadaustin.me

---

From: Mark Nottingham <[email-masked]>
Date: Tue, 4 Nov 2014 09:16:12 +1100

Chad,

Thanks for the detailed summary. Unfortunately, this feedback comes when we’re post-WLGC - a point in the protocol’s development where we’re only considering certain kinds of issues: basically, those that affect interoperability or security. 

While I see a lot of questions about the capabilities of priorities in HTTP/2, I don’t see any fundamental interop issues below. Making the change you suggest below (to Osama’s proposal) would require extensive discussion and possibly wire format changes; as with other discussions recently, the bar for getting that sort of thing in at this point is “popular acclaim” — i.e., it’s uncontroversially a good idea, and given that we had to resort to a coin toss last time this issue came up, that’s not likely.

For what it’s worth — I think many share your concerns about the overall shape of priorities; we’ve discussed its attributes extensively, and came to a place where we decided that we couldn’t evolve the scheme more without data from wide deployment over a long period of time. 

Also, it’s important to note that priorities are hints to the server, not directives; it is expected that servers will use local knowledge (e.g., “serve JS and CSS before images”) in combination with priorities, rather than being strict slaves to them.

If you (or anyone else) can suggest smaller changes (i.e. ones that don’t affect the wire format or greatly change semantics) that can gain popular acclaim in a reasonable amount of time, that may be a useful way forward; I’d encourage folks to consider what can be done within that scope. Having said that, we have one remaining issue from WGLC, and it’s not going to be open much longer.

Cheers,

> On 3 Nov 2014, at 5:19 pm, Chad Austin <[email-masked]> wrote:
> 
> Hi!
> 
> Sorry if you're tired of hearing about priority.  :)  Having spent some time working out the pros, cons, and implications of the tree-based priority model, I have serious concerns that shipping HTTP/2 priority as it stands would be harmful.
> 
> In this email I will enumerate the disadvantages of the HTTP/2 priority model that I see and propose a couple options.
> 
> # The Advantage of a Stream Dependency Model for Prioritization
> 
> There is an advantage to using a DAG to specify priority: a DAG is a natural and direct way to specify a partial ordering and does not require the selection of arbitrary numeric values.  (e.g. HTML at priority 100, CSS at priority 80, images at priority 20, etc.)
> 
> # The Problems with HTTP/2 Priority
> 
> 1. A tree cannot express some common priority schedules
> 
> While the original SPDY/4 priority proposal [ https://groups.google.com/forum/#!topic/spdy-dev/-d9Auoun4HU/discussion ] was a DAG, what got adopted in HTTP/2 is a tree.  A tree is not sufficient to express some common priority schedules, like "all CSS and JS before any images".
> 
> In HTTP/2, the only way to express "All JS/CSS before all images" is a linked list [ http://lists.w3.org/Archives/Public/ietf-http-wg/2014OctDec/0164.html ], which has the side effect of defining a strict ordering within the JS/CSS group, implying that individual JS and CSS responses should be serialized relative to each other.  For JS and CSS, finishing one response before beginning the next is probably the right call* but there are asset types where parallel transfer is beneficial (e.g. progressive images, VIPM 3D meshes).  Thus, a linked list is less expressive than numeric priorities here.
> 
> * though Ilya Grigorik argued for parallel high-priority resource transfer here: http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Oct/0180.html  I suppose the argument is that, given an unknown distribution of response sizes (e.g. 100 KB JS, 1 KB CSS), it's better to transfer in parallel so that small responses reliably complete before larger responses, avoiding the scenario where a small CSS file is blocked by a much larger JS file.
> 
> _Prebuttal: Weights do not solve for prioritization_
> 
> A common misconception is that weights can be used to fine-tune priorities.  In fact, the WIP Firefox implementation of HTTP/2 simply maps Firefox's internal numeric priority values to HTTP/2 weights.  However, weights and priorities are different concepts, and an accurate and complete server-side implementation of HTTP/2 as drafted would allocate some resources to low-weighted streams if they're at the same priority as high-weighted streams.
> 
> Recently someone pushed this argument further, and said that if HTML/JS/CSS had weight 256 and images had weight 1, then negligible bandwidth is allocated to images until HTML/JS/CSS are complete...  for a small number of images, that's true.  But, then, let's say you had high-priority images and low-priority images?  You'd have to give HTML/JS/CSS weight=256, medium-priority images weight=16, and low-priority images weight=1.  (256/16 = 16/1).  If there are 16 times as many medium-priority images as HTML/CSS/JS, fully half of the bandwidth will be allocated to the medium-priority images as the high-priority HTML/JS/CSS.
> 
> My point is that using weights as priorities doesn't really work for anything but the simplest scenarios.
> 
> _Prebuttal: "Well, you can use a custom prioritization scheme with an HTTP/2 protocol extension"_
> 
> But, then, what's the point of shipping a standard if it requires, in some common cases, a protocol extension?  Ideally applications, browsers, akamai, nginx, varnish, etc. would all interoperate and requiring a protocol extension makes that a lot harder.  This working group is the appropriate place to solve for priority, and now is the appropriate time.
> 
> 2. Reprioritization is O(depth) and thus can be O(n)
> 
> In HTTP/2, reprioritization is O(depth(new_parent) - depth(stream)) due to the cycle check.  Thus, reprioritizing N nodes in a linked list is O(N^2).
> 
> While not the worst problem in the world, it's another subtle bit of complexity that must be managed and protected against denial of service.
> 
> 3. I'm not sure HTTP/2 even solves the proxy use case
> 
> When I asked why HTTP/2 specifies priority with tree dependencies, the answer I was given was that it allows fairly multiplexing incoming HTTP/2 connections across a single backend HTTP/2 connection.  But does it?  [ http://lists.w3.org/Archives/Public/ietf-http-wg/2014OctDec/0309.html ]
> 
> Since HTTP/2 does not support dummy nodes in the priority tree (and I'll explain later why that wouldn't even help), multiple top-level nodes in each inbound stream would have to become a top-level weighted stream on the outbound connection.  The weights ought to be allocated fairly, which means any additional inbound stream has to fairly reweight other streams from that connection.
> 
> Visually:
> 
> Outbound connection: {A1[w=1/6],A2[w=1/6],A3[w=1/6],B1[w=1/4],B2[w=1/4]} -> 0
> 
> Now consider what happens when a new stream arrives from A.  Outbound A1, A2, and A3 have to be reweighted.  Now consider what happens when B1 completes.  The proxy would have to notice that B1 is done, and B2 should be reweighted to 1/2.  In the meantime, A is given a larger allocation of backend resources.
> 
> I question whether stream dependencies is a realistic solution to the proxy use case.  I suspect a more direct protocol for specifying stream groups and weights would be simpler, more accurate, and more expressive.
> 
> In the very least, I would love somebody on this list to explain in detail how the proxy use case is supposed to work.  I don't see it yet.  Osama Mazahir's explicit stream groups proposal is a more direct solution.
> 
> 4. There's no production implementation experience with stream dependency priorities
> 
> I think the issues I've enumerated above would be discovered when trying to implement and profile HTTP/2 across browsers, CDNs, proxies, and so on.  But if HTTP/2 is destined to be a widespread standard, it might be too late by then.
> 
> Was the theory that SPDY/4 would be the testing ground for these ideas, but instead they got adopted in a limited form into HTTP/2?  Hard to say - I haven't heard anything from Googlers since I started looking into this.
> 
> # What now?
> 
> I don't think HTTP/2 priority should ship as it is currently drafted.  What are the other options?
> 
> 1. Ship HTTP/2 without priority and evolve priority as an extension.
> 
> I'm not a fan of this option because priority is critically important.  Multiplexed streams without priority are slower than HTTP across N connections.
> 
> 2. Replace the tree model with a DAG (multiple parents)
> 
> A DAG, that is, allowing streams to have multiple parents, would solve the "all HTML/JS/CSS in parallel, then all images in parallel" use case.  However, allowing multiple parents introduces a great deal of complexity and chattiness into the protocol, including a potentially quadratic number of bytes sent over the connection.  I don't recommend this path forward.
> 
> 3. Write a document describing how all of these use cases are supposed to work
> 
> Maybe I'm missing some key detail and my analysis above is completely wrong.  If so, I'd love to see something that precisely describes how these use cases are supposed to work.  How are browsers supposed to initiate stream requests given existing pageload prioritization algorithms?  How exactly are proxies supposed to work?
> 
> 4. Adopt Osama Mazahir's proposal
> 
> In February, Osama Mazahir proposed an implementation of HTTP/2 priorities that solves all of the use cases above.  http://lists.w3.org/Archives/Public/ietf-http-wg/2014JanMar/0396.html  For a reason I haven't yet heard, it wasn't considered obviously better than stream dependencies, and it lost in a coin flip in London: http://msopentech.com/blog/2014/03/19/http2-nearing-completion/
> 
> I've heard one concern about numeric priorities: switching browser tabs ought to reprioritize all existing requests.  This would cause N reprioritization requests to be sent, where N is the number of active requests.  However, I think that concern may be minor.  For almost all realistic values of N, the frame(s?) to reprioritize N active streams could fit in a single Ethernet MTU.
> 
> My preferred solution to fixing HTTP/2 priority is to adopt Osama's Mazahir's proposal.  It's simple, direct, and browsers and SPDY currently use numeric priorities anyway.
> 
> # Why Priority is Critical
> 
> Page load optimization is hitting diminishing returns.  Bandwidth is going up, but connection latency is not really going down over time.  Priority is a huge lever for improving page load experience by reducing round-trips and making full use of the network pipe.  Getting priority right is critical — HTTP/2 will rapidly become one of the most popular protocols in the world, and getting priority right has enormous potential upside in latency and efficiency.  I just don't see how the tree dependency model meets even current use cases, which makes me think it's a bad idea to ship a protocol based on it.
> 
> Thanks for reading,
> Chad
> 
> --
> Chad Austin
> Technical Director, IMVU
> http://chadaustin.me
> 

--
Mark Nottingham   http://www.mnot.net/

---

From: Martin Thomson <[email-masked]>
Date: Mon, 3 Nov 2014 15:06:45 -0800

> If you (or anyone else) can suggest smaller changes (i.e. ones that don’t affect the wire format or greatly change semantics) that can gain popular acclaim in a reasonable amount of time, that may…

In that spirit, here's a very modest change to the spec that I'll
suggest.  But first I'll note that if you are willing to live with a
kludge, this isn't necessary to address the intermediation case (see
below for kludge details).

The change:
  Make it so that PRIORITY can be sent on a stream in ANY state.
  i.e., change so that PRIORITY is permitted in the "idle" state.

One of the concerns that Chad raised was that the current scheme does
not perfectly address the intermediation case.  And that's true, and
it has bothered me on and off.  But only because I keep forgetting
that I was happy with the kludge.  The other concerns bother me much
less.

The kludge is this: you allow a single request from each client at
your intermediary to establish a node in the dependency tree that is
subsequently used as an anchor for all their requests in place of
stream 0.  Since this node will live for some time past the lifetime
of the initial request, you can treat this as a new root for that
client.  You can periodically shift which stream you use as an anchor
if you are concerned about an old stream being garbage collected for
being too old, even though it is still in use.

That could address the intermediation case, which I think was the
important one.  Being able to prioritized unused streams would of
course make it marginally easier.

If you allow the prioritization of unused streams, you can create
nodes in the dependency tree that can be used to form pseudo-groups.
These could easily address the intermediation concern.  It doesn't
perfectly address the "all the JS before all the CSS" scenario, but
Mark's note there about the server knowing things about priority
applies.  A robust scheme that properly addressed that case would not
be as trivial a change.

Here's a second kludge that relies (a little more) on unused streams
with priority: if JS has to come before all CSS and you have three of
each, then:  Send requests for all the JS with as high a weighting as
you feel you can use.  Then, prioritize a new unused stream with the
same dependency as all the JS, but with very low weight (i.e., 1).
CSS requests can hang off that low weight stream.  Any server with any
sense will then avoid spending cycles on the CSS unless it is blocked
on the JS.

As far as I can tell, this second kludge is more difficult to get
right without the change I suggest, but it's not impossible to get
something approximating it.

On balance, I'm not sure that we're going to get much without actual
experience with any scheme we propose, so I don't think that big
changes are going to be worthwhile.  Well, unless a well-researched
and extensive study suddenly manifests itself, that is.

I'm not even sure if the tweak above is worth doing, except that it
makes the scheme slightly more flexible, making the proxy case easier
to solve.

---

From: Chad Austin <[email-masked]>
Date: Tue, 4 Nov 2014 13:32:35 -0800

Hi Martin,

> sense will then avoid spending cycles on the CSS unless it is blocked

I like the idea.  I've gotten hung up in the past thinking about what
happens when all but the unused streams get closed.  Assume unused streams
X, Y, Z and active streams A, B, C:

{X,Y} -> 0
A -> X
Z -> Y
{B, C} -> Z

In the past I've assumed depth in the tree would somehow factor into
resource allocation, but as you pointed out, distribution of resources down
the tree would do the right thing.  50% of resources would be allocated to
A, 25% to B, and 25% to C, which is correct.  (This example is
approximately the intermediation case, where X and Y are created by the
proxy and Z is created by one of the clients.)

My current understanding (which is suspect - I'm sick and my head feels
like a cotton ball), one unused stream of weight 1 per priority level,
under the assumption that servers wouldn't bother spending any resources on
streams of weight 1, would almost perfectly solve both the proxy use case
and the group priorities use case.

Assuming garbage collection of unused streams is solved, I would support
this protocol tweak.  It's not as good as Osama's proposal, but it's better
than what's currently drafted.  :)

> makes the scheme slightly more flexible, making the proxy case easier

It's up to you and the working group to decide what the right path forward
is, of course, but the "group priority" use case isn't hypothetical to us:

We built our content pipeline architecture under the assumption that we can
efficiently make hundreds and sometimes thousands of HTTP requests to a
server (~Varnish) where the only contended resource is the customer's
bandwidth.  Having fine-grained control over stream priorities would give
us the ability to reduce actual load times from ~40 seconds to ~35 because
we could treat low-priority requests much less conservatively.

The importance of HTTP/2's priority extends beyond the protocol itself.

Ideally, an application would issue ALL of its requests right away.  Any
responses, even low-priority responses, that are cached by the browser
would be returned to the application right away.  But if there's no way to
specify priority at the web API level (and trust that it's mapped
accurately to the underlying protocol), then this is dangerous, because
low-priority responses might impede high-priority responses, increasing
overall load time.

To be honest, even SPDY's 3 bits of priority would be plenty sufficient for
our case, but WHATWG does not seem amenable to adding any priority API to
the web platform until HTTP/2's semantics are defined, as the web API
should be forward-looking.

Perhaps the right thing to do is adopt Martin's unused stream workaround
into HTTP/2, leave the option for adopting Osama's priority design as an
extension or HTTP/2.1 or HTTP/3 once there is sufficient production
experience, and base the WHATWG web API on numeric priorities and stream
groups.  Either way, I'll go back to them with the results from the
discussions on this list.

As always, I appreciate the discussion and how honest and forthcoming
participants on this list are.

Thanks,

-- 
Chad Austin
http://chadaustin.me

---

From: Mark Nottingham <[email-masked]>
Date: Wed, 5 Nov 2014 10:42:01 +1100

What do other people think about the general idea?

Martin, how difficult would it be to put together a pull?

> On 5 Nov 2014, at 8:32 am, Chad Austin <[email-masked]> wrote:
> 
> Hi Martin,
> 
> On Mon, Nov 3, 2014 at 3:06 PM, Martin Thomson <[email-masked]> wrote:
> I like the idea.  I've gotten hung up in the past thinking about what happens when all but the unused streams get closed.  Assume unused streams X, Y, Z and active streams A, B, C:
> 
> {X,Y} -> 0
> A -> X
> Z -> Y
> {B, C} -> Z
> 
> In the past I've assumed depth in the tree would somehow factor into resource allocation, but as you pointed out, distribution of resources down the tree would do the right thing.  50% of resources would be allocated to A, 25% to B, and 25% to C, which is correct.  (This example is approximately the intermediation case, where X and Y are created by the proxy and Z is created by one of the clients.)
> 
> My current understanding (which is suspect - I'm sick and my head feels like a cotton ball), one unused stream of weight 1 per priority level, under the assumption that servers wouldn't bother spending any resources on streams of weight 1, would almost perfectly solve both the proxy use case and the group priorities use case.
> 
> Assuming garbage collection of unused streams is solved, I would support this protocol tweak.  It's not as good as Osama's proposal, but it's better than what's currently drafted.  :)
> 
> It's up to you and the working group to decide what the right path forward is, of course, but the "group priority" use case isn't hypothetical to us:
> 
> We built our content pipeline architecture under the assumption that we can efficiently make hundreds and sometimes thousands of HTTP requests to a server (~Varnish) where the only contended resource is the customer's bandwidth.  Having fine-grained control over stream priorities would give us the ability to reduce actual load times from ~40 seconds to ~35 because we could treat low-priority requests much less conservatively.
> 
> Ideally, an application would issue ALL of its requests right away.  Any responses, even low-priority responses, that are cached by the browser would be returned to the application right away.  But if there's no way to specify priority at the web API level (and trust that it's mapped accurately to the underlying protocol), then this is dangerous, because low-priority responses might impede high-priority responses, increasing overall load time.
> 
> To be honest, even SPDY's 3 bits of priority would be plenty sufficient for our case, but WHATWG does not seem amenable to adding any priority API to the web platform until HTTP/2's semantics are defined, as the web API should be forward-looking.
> 
> Perhaps the right thing to do is adopt Martin's unused stream workaround into HTTP/2, leave the option for adopting Osama's priority design as an extension or HTTP/2.1 or HTTP/3 once there is sufficient production experience, and base the WHATWG web API on numeric priorities and stream groups.  Either way, I'll go back to them with the results from the discussions on this list.
> 
> As always, I appreciate the discussion and how honest and forthcoming participants on this list are.
> 
> Thanks,
> 
> -- 
> Chad Austin
> http://chadaustin.me

--
Mark Nottingham   https://www.mnot.net/

---

From: Martin Thomson <[email-masked]>
Date: Tue, 4 Nov 2014 16:02:07 -0800

> Martin, how difficult would it be to put together a pull?

Fairly straightforward.  Allow PRIORITY in the various places, plus a
note about unused streams in the priority section.

---

From: Ilya Grigorik <[email-masked]>
Date: Wed, 5 Nov 2014 09:40:50 +0900

> What do other people think about the general idea?

I like it. I think it moves the discussion from "you could bend the
protocol to do this assuming you have a cooperating client+server", which
is not something we can reasonably rely on as a browser, to a plausible
"PRIORITY is allowed on idle stream, treat such streams as 'group
anchors'"... i.e. allowing priority on idle stream means servers *must*
deal with this case, which makes using and deploying such mechanism much
more plausible.

ig

---

From: Roberto Peon <[email-masked]>
Date: Wed, 5 Nov 2014 07:35:04 -0800

SGTM-- moving this from unreliable to reliable behavior seems like a
definite win for intermediaries, and potentially others.
-=R

---

From: Mark Nottingham <[email-masked]>
Date: Thu, 6 Nov 2014 11:28:10 +1100

There seems to be some support for this, so I've created <https://github.com/http2/http2-spec/issues/642>.

As you all know, we need to see substantial support and little (if any) dissent to take this kind of change at this point in the process.

Anyone else care to comment?

>  i.e., change so that PRIORITY is permitted in the "idle" state.

Martin, please start work on a pull so people can take a look.

> On 6 Nov 2014, at 2:35 am, Roberto Peon <[email-masked]> wrote:
> 
> SGTM-- moving this from unreliable to reliable behavior seems like a definite win for intermediaries, and potentially others.
> -=R
> 
> I like it. I think it moves the discussion from "you could bend the protocol to do this assuming you have a cooperating client+server", which is not something we can reasonably rely on as a browser, to a plausible "PRIORITY is allowed on idle stream, treat such streams as 'group anchors'"... i.e. allowing priority on idle stream means servers *must* deal with this case, which makes using and deploying such mechanism much more plausible.
> 
> ig
>

---

From: Martin Thomson <[email-masked]>
Date: Wed, 5 Nov 2014 16:49:28 -0800

> Martin, please start work on a pull so people can take a look.

Yes, please take a look:
https://github.com/http2/http2-spec/pull/643

---

From: Greg Wilkins <[email-masked]>
Date: Thu, 6 Nov 2014 12:23:20 +1100

I am with Mark when he says: "many share your concerns about the overall
shape of priorities;"

We have not had the time or environment to even begin to experiment with
priorities and it scares me that we are at LC and there has been no
widespread testing of the proposed standard.

However, Mark does also indicate the get-out-goal card that will need to be
played:  "Also, it’s important to note that priorities are hints to the
server, not directives; it is expected that servers will use local
knowledge (e.g., “serve JS and CSS before images”) in combination with
priorities, rather than being strict slaves to them."

Specifically, I think that the server's view of priority will often be
entirely different to the clients and what is expressed by the Tree/or
Dag.  The currently priority mechanism is very much focused on how to
allocated network resources to frames from various streams.  A server is
going to be more focused on which streams to allocate CPU/memory resources
to in order to generate frames to send, and once generated those frames
have a higher priority to be sent so that memory can be freed to be used
for other frame generation.    Just because a high priority stream is
blocked does not mean that a server will wish to allocated more resources
to a connection to perhaps progress a low priority stream.   Maximising
fair allocation of CPU/memory/cache resources on the server will probably
trump any attempt to maximise network utilisation on the client end of a
connection.

My current guess is that the server is going to implement it's own
heuristic based priority mechanism that will use very little input from
client supplied priorities, specially not dynamically provided ones.
Hopefully I'm wrong and the current tree/weights will be useful to the
server side, but only experimentation will tell.

The jetty project is near to the point where we can experiment with http2
scheduling, push and priorities.  We intend to spend time on the
December/January time frame to come up with at least a basic
implementation.  It is a pity that we have lost the race with LC to be able
to well contribute the knowledge so learnt.    Hopefully whatever we do
learn will be able to be represented in some way by the current scheme, but
I find it of great concern that Chad has identified use-cases that cannot
be expressed.

cheers

-- 
Greg Wilkins <[email-masked]>  @  Webtide - *an Intalio subsidiary*
http://eclipse.org/jetty HTTP, SPDY, Websocket server and client that scales
http://www.webtide.com  advice and support for jetty and cometd.

---

From: Shigeki Ohtsu <[email-masked]>
Date: Thu, 06 Nov 2014 11:48:41 +0900

I have one question.

Can't we use just HEADERS with a priority flag and no header block as a 
group anchor
  instead of using PRIORITY for an idle stream?

This might work since the reference sets has gone and a stream timeout 
is not defined yet in the current spec.

I'm worrying about the idle stream in the priority tree is out of 
SETTINGS_MAX_CONCURRENT_STREAMS.

Regards.

---

From: Martin Thomson <[email-masked]>
Date: Wed, 5 Nov 2014 21:29:56 -0800

>  instead of using PRIORITY for an idle stream?

I'm concerned that will result in problems for servers.   There will
always be a header block, but it will just be empty.  If there are
missing header fields, then the server will reject the "request".

> This might work since the reference sets has gone and a stream timeout is
> not defined yet in the current spec.
>

There is already a need to maintain priority information that is
independent of the concurrent stream limit and to have nodes in the
tree that are not active.  See
http://http2.github.io/http2-spec/#priority-gc  This just makes that a
little bit more flexible.

---

From: Shigeki Ohtsu <[email-masked]>
Date: Thu, 06 Nov 2014 15:29:36 +0900

> missing header fields, then the server will reject the "request".

Empty header block in HEADES with END_HEADER flags is not explicitly 
prohibited
in the current draft and permitted in the past when we have the 
reference set.

I agree that there may be a server that checks empty header set emission 
and
rejects such a request.

> little bit more flexible.

This depends on the implementation design.

For me, maintaining closed streams in the tree is much easier as we can 
handle it
at the time  when the stream state is transited (half-closed->closed, 
reserved->closed).

PRIORITY for an idle stream leads no stream state transition and they 
can be increased
with no limits  and they are preserved in the tree until we trigger gc 
so I think this causes
  more complex than the case of HEADERS with priority and no header block.

Regards,

---

From: Shigeki Ohtsu <[email-masked]>
Date: Thu, 06 Nov 2014 16:08:46 +0900

One more thing we should consider when an idle stream is in the priority 
tree is that
in 5.1.1 Stream Identifiers says

The first use of a new stream identifier implicitly closes all streams 
in the "idle" state
that might have been initiated by that peer with a lower-valued stream 
identifier.

If this description is not changed, we should also change all idel 
streams in the priority tree
  into the closed state which has a timeout value when the stream of 
larger id is closed.

Regards,

On 2014/11/06 15:29, Shigeki Ohtsu wrote:
> I agree that there may be a server that checks empty header set 
> emission and
> rejects such a request.
>
> For me, maintaining closed streams in the tree is much easier as we 
> can handle it

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Thu, 06 Nov 2014 08:00:53 +0000

--------
In message <CAH_y2NGasMSx1C3kX66Ucvq=szNA-60tmfM6juhTZD=[email-masked]>

>server side, but only experimentation will tell.

+1

I'm still of the opinion that no significant loss of performance would
happen if the client just sent a single priority bit meaning:

  '0'
	The fetch is happening in a background context ie:
	  * outside of scroll-regions viewport
	  * in covered tab
	  * in hidden window
	  * screen-saver is running
	  * from a batch-job

  '1'
	The fetch is happening in a foreground context ie:
	  * in view
	  * user is tapping his fingers
	  * from a real-time transaction

And I think the entire priority verbiage should be replaced by
something like that and any more advanced priority communications/state
relegated to extensions.

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
[email-masked]         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe    
Never attribute to malice what can adequately be explained by incompetence.

---

From: Francesco Chemolli <[email-masked]>
Date: Thu, 6 Nov 2014 19:03:15 +0100

> something like that and any more advanced priority communications/state

It's a bit extreme, but it's the kind of simplicity that pays the
biggest returns on implementation complexity.
I like this; can we discuss the idea a bit, and maybe straw-hat it?

-- 
    Francesco Chemolli

---

From: Ilya Grigorik <[email-masked]>
Date: Thu, 6 Nov 2014 11:03:04 -0800

> I like this; can we discuss the idea a bit, and maybe straw-hat it?

Browsers need far more than a single bit. The dependency model is based on
direct feedback (and development experience) from a number of large,
existing apps, at Google and beyond -- no they're not unique, todays "large
apps" are tomorrow's everyday apps.

ig

---

From: Mark Nottingham <[email-masked]>
Date: Tue, 11 Nov 2014 15:33:16 -1000

This was discussed in the Honolulu meeting; it seemed reasonable to people in the room and there was no objection.

Any last thoughts on the list? Otherwise, I’ll mark as editor-ready so Martin can integrate the pull request.

Cheers,

> On 5 Nov 2014, at 2:28 pm, Mark Nottingham <[email-masked]> wrote:
>

---

From: Shigeki Ohtsu <[email-masked]>
Date: Wed, 12 Nov 2014 14:36:51 +0900

I have no objection but I think that it is better to add a description 
as below in #643 to  care
about a stream id of an idle stream in a dependency tree not to be the 
closed state accidentally.

````
Note that their stream identifiers need enough to be high since they 
transit to the closed
state when a stream with a higer-valued stream identifieris is sent or 
received (see Section 5.1.1).
````

---

From: Tatsuhiro Tsujikawa <[email-masked]>
Date: Wed, 12 Nov 2014 21:36:19 +0900

On Wed, Nov 12, 2014 at 10:33 AM, Mark Nottingham <[email-masked]> wrote:

> ​
I'm fine with this proposal in general.
My comments below.

At first read, I thought that we can only send PRIORITY to idle
stream and idle stream cannot be appeared in priority field
unless it was already in dependency tree.  But it seems I was
wrong.  It seems that PRIORITY or HEADERS can have priority field
to depend on idle stream which is not in a depedency tree yet,
including streams which were depedency tree once but was GC-ed.

For example, when stream A anb B are idle stream and are both not
in dependency tree, sending PRIORITY frame to stream A with
priority field { stream B and weight 20 } creates 2 nodes in
dependency tree.

0 <- B (16)
​ (default priority​ applied)
B <- A (20)

The following paragraph indicates this:

"""
Similarly, streams that are in the "idle" state can be assigned priority or
become a
dependency for other streams.  This allows for the creation of a grouping
node in the
dependency tree, which enables more flexible expressions of priority.  Idle
streams that
are made a dependency are assigned a <xref target="pri-default">default
priority</xref>.
"""

It seems to me that the last sentence "Idle streams that are made
a dependency are assigned a default priority" only applies to
idle stream in dependency field, which is not in dependency tree,
and it is not applied to idle stream that PRIORITY frame is sent
to.  If this sentence also applies to the idle stream which is
already in dependency tree, then everytime it is in priority
field its dependency is reset to default value, which is
undesirable and defeat the purpose of this proposal.  So I think
some texts are required to explicitly state that when this
applies.
​​

Best regards,
Tatsuhiro Tsujikawa​

​​

> > There seems to be some support for this, so I've created <
> https://github.com/http2/http2-spec/issues/642>.
> >
> > As you all know, we need to see substantial support and little (if any)
> dissent to take this kind of change at this point in the process.
> >

---

From: Mark Nottingham <[email-masked]>
Date: Mon, 17 Nov 2014 13:15:38 +1100

It sounds like we have consensus to do this, with some editorial input.

Marking editor-ready.

> On 12 Nov 2014, at 12:33 pm, Mark Nottingham <[email-masked]> wrote:
>