- From: 陈智昌 <willchan@chromium.org>
- Date: Sun, 3 Nov 2013 15:23:40 -0800
- To: Peter Lepeska <bizzbyster@gmail.com>
- Cc: HTTP Working Group <ietf-http-wg@w3.org>, Martin Thomson <martin.thomson@gmail.com>
- Message-ID: <CAA4WUYhqC3GoqfN+PosqcDsk=c42kMzb7dqLSM=PbMy7YmkKbw@mail.gmail.com>
Also please consider a proxy. For example, a forward proxy that has multiple browsers connecting through it to a single HTTP/2 capable origin. On Sun, Nov 3, 2013 at 3:21 PM, Peter Lepeska <bizzbyster@gmail.com> wrote: > Yes I was assuming that. Let me think on the two tab example you give a > little more. > > Thanks, > > Peter > > > On Sun, Nov 3, 2013 at 1:30 PM, William Chan (陈智昌) <willchan@chromium.org>wrote: > >> I think you're assuming that all streams in a connection belong to a >> single webpage load. Let me know if not, and I can explain further. >> On Nov 3, 2013 9:04 AM, "Peter Lepeska" <bizzbyster@gmail.com> wrote: >> >>> Right. But my point is that an extremely simple scheme, where the >>> browser just indicates that an object is blocking or not, gets you to the >>> same place as the dependency scheme. >>> >>> Peter >>> >>> >>> On Sun, Nov 3, 2013 at 8:54 AM, Martin Thomson <martin.thomson@gmail.com >>> > wrote: >>> >>>> The intent would be to use ordering (i.e. dependencies) for this >>>> scenario, not "priorities" (aka weights). >>>> >>>> >>>> On 3 November 2013 07:37, <bizzbyster@gmail.com> wrote: >>>> >>>>> Going through your example, would the prioritization at any instant be >>>>> any different if you simply assigned two priorities -- high for resources >>>>> that are blocking (the .js and the .css in your example) and low for >>>>> resources that are non-blocking (the .jpgs)? >>>>> >>>>> Sorry if I'm missing something but it doesn't seem like it to me. >>>>> >>>>> Peter >>>>> >>>>> On Oct 28, 2013, at 3:45 PM, William Chan (陈智昌) <willchan@chromium.org> >>>>> wrote: >>>>> >>>>> On Mon, Oct 28, 2013 at 3:34 PM, Martin Thomson < >>>>> martin.thomson@gmail.com> wrote: >>>>> >>>>>> On 28 October 2013 14:32, William Chan (陈智昌) <willchan@chromium.org> >>>>>> wrote: >>>>>> > I think that the second point is far more controversial and >>>>>> requires more >>>>>> > discussion. >>>>>> >>>>>> It may be the case that you find the first issue compelling enough >>>>>> that a change of some form is justified regardless of what you think >>>>>> on the second :) >>>>>> >>>>>> Of course, I think that there are some significant problems with the >>>>>> proposal, most of which I think that you will find are easy to fix. >>>>>> >>>>>> The first is largely procedural. I've have people complain about the >>>>>> use of references to documents like the above for archival and IPR >>>>>> reasons. Maybe copying and pasting the entirety of that document to >>>>>> an email will address those concerns. Maybe it will also help you >>>>>> understand that it is a little wordy and that perhaps the essence of >>>>>> your proposal could be made more succinctly :) >>>>>> >>>>> >>>>> I have to confess that I heard complaints but never understood the >>>>> reasoning behind them. If it's archival/IPR, I'm perfectly happy to >>>>> copy/paste the document into email. These concerns aren't obvious to me as >>>>> I'm a relative newb to IETF stuff. >>>>> >>>>> As far as the proposal's wordiness, I mostly view it as a straw man to >>>>> ignite discussion. I'm completely expecting that it will be ripped apart :) >>>>> I'm hoping to rely heavily on editors to make it much more succinct once we >>>>> reach some rough consensus. Or perhaps this was a subtle play on your part >>>>> to get me to do better editorial work before sending it to the group :) >>>>> >>>>> I'll give others a chance to discuss other points first. I don't want >>>>> to yell more loudly than others anymore than I already do. >>>>> >>>>> >>>>>> >>>>>> The second is that the idea of prioritization between separate trees >>>>>> isn't really described as being prioritization. I think that what you >>>>>> want to do is a proportional allocation of resources between those >>>>>> trees, so a term like "weight" is probably more accurate. You even >>>>>> use that word later. (Oh crap, I just realized that this is a classic >>>>>> case of "the names aren't important, the standards committee always >>>>>> changes them anyway" scenario, sorry.) >>>>>> >>>>>> Probably more substantially, you need to be a little more concrete >>>>>> when it comes to requirements for managing placeholders and garbage >>>>>> collection. >>>>>> >>>>>> The settings seem like over-engineering to me. I'm sure that a server >>>>>> implementation can arrive at a reasonable set of behaviours that >>>>>> doesn't degrade too badly for their common workloads without settings >>>>>> being exchanged. When it comes to resource exhaustion, I think that >>>>>> it's probably more appropriate to deal with those in the DoS >>>>>> considerations than with settings. >>>>>> >>>>>> On the over-engineering theme, the idea that you can reprioritize >>>>>> multiple streams with a single PRIORITY frame concerns me. That's >>>>>> going to mess with intermediaries of all sorts. The cost of a >>>>>> PRIORITY frame for each stream is 4 bytes per stream, but then you >>>>>> weren't going to bother with that anyway. >>>>>> >>>>>> Please consider placing default values on priority. Since you are >>>>>> only going to be able to provide either a dependency or a weight, the >>>>>> complementary item is going to inherit a default. >>>>>> >>>>> >>>>> I'm copy/pasting the doc here: >>>>> Proposal for Stream Dependencies in SPDY >>>>> Draft 1 >>>>> Last Updated: 26 October 2012 >>>>> >>>>> This document proposes changes to the SPDY protocol to support stream >>>>> dependencies. During a pageload, the server uses dependencies to >>>>> improve performance by allocating bandwidth capacity to the most important >>>>> resource transfers first. >>>>> >>>>> The remainder of this document describes the motivation<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.dwzsju9gmwit>for dependencies, protocol >>>>> changes<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=kix.hiogy1u6j43a>to support them, and >>>>> examples<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.9awxmm9y20yn>of how those mechanisms can be used by the browser. We conclude with a >>>>> discussion of the client and server policies<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.6ii1fem7qsws>afforded by expressing dependency information in SPDY. >>>>> >>>>> (Note that flow control is the subject of a separate document and is >>>>> out of scope here.) >>>>> Motivation >>>>> In SPDY today, each stream has a priority (0–7) chosen by the client >>>>> upon stream creation. Push streams are >>>>> an exception. The server policy today is to assume push streams are >>>>> all low priority. Push or pull, the priority of a stream cannot be changed >>>>> once created. >>>>> >>>>> Priorities provide hints to the server about which streams are most >>>>> important to the client, but they are poorly suited to several common >>>>> use-cases. >>>>> >>>>> >>>>> - Specifying an ordering of resource transfers >>>>> Sharing bandwidth between resource transfers may degrade >>>>> performance as measured by page-load time, e.g., when transferring two >>>>> Javascript resources that cannot be executed until transfer is complete, or >>>>> two video chunks that will be played back-to-back. In these circumstances, >>>>> the browser may wish to specify an ordering --- HTML before script1.js >>>>> before script2.js before image.png, for example, or video_chunk1 before >>>>> video_chunk2 and so on. (Moreover, changing the priority of the HTML >>>>> transfer itself may benefit performance; e.g., a large blocking script will >>>>> be interpreted and executed more quickly if it does not compete for >>>>> bandwidth capacity with a large HTML transfer.) >>>>> >>>>> With a small number of fixed priorities, the browser is simply >>>>> unable to express an ordering over many resource transfers, and with a >>>>> large number of priorities, reordering is costly. >>>>> - Reacting to document parsing >>>>> Because the browser's document parser blocks while waiting for >>>>> script and style resource transfers to complete, many resource requests >>>>> will be speculative. (For more background, see Tony Gentilcore's >>>>> excellent summary<http://gent.ilcore.com/2011/01/webkit-preloadscanner.html>of Chrome's implementation of speculative parsing, the preload scanner.) >>>>> These requests may need to be preempted as the document parser learns of >>>>> higher priority resources. For example, if a script a.js uses >>>>> document.write to embed another script, b.js, the transfer of b.jsshould preempt other in-flight resource transfers, as the receipt of >>>>> b.js blocks page layout. As another example, consider images >>>>> styled with display: none; once such styling is discovered during >>>>> parsing, associated image transfers should be deferred to prioritize >>>>> visible content. >>>>> - Reacting to user behavior >>>>> Suppose a SPDY proxy is servicing multiple users. In this case, >>>>> many tabs (and their associated streams) are multiplexed over the same SPDY >>>>> connection. Fixed priorities (i.e., unchanging over the lifetime of a >>>>> stream) preclude reacting to user behavior; e.g., a user may switch among >>>>> concurrently loading tabs. >>>>> - Server push >>>>> No single fixed priority is appropriate for server push. A stream >>>>> pushing a large image, for example, should have lower priority than JS/CSS. >>>>> But, when pushing JS/CSS that the browser needs, those stream should have >>>>> high priority. >>>>> >>>>> >>>>> In sum, for many common scenarios, fixed priorities are not sufficient >>>>> to optimize the allocation of bandwidth among competing requests. >>>>> >>>>> Protocol changes >>>>> To address the limitations of priorities, we propose expressingdependencies among streams. >>>>> Dependencies improve matters in two main ways: >>>>> >>>>> 1. Dependencies more accurately reflect the constraints of the >>>>> browser. >>>>> Rendering a page is a streaming process that naturally leads to a >>>>> series of dependencies among resource transfers. For example, a script may >>>>> block HTML parsing, and a final layout may depend on an external stylesheet. >>>>> 2. Dependencies can be updated efficiently. >>>>> The relative importance of streams may change as Javascript >>>>> executes or a user changes tabs, for example. Dependencies allow the >>>>> browser to express these changes compactly. If a user changes tabs, for >>>>> example, the browser may simply signal a change in priority of the tab's >>>>> dependency root, thereby reducing (or increasing) the bandwidth allocated >>>>> to all dependent transfers. >>>>> >>>>> >>>>> Dependencies are expressed in two ways: 1) a new dependency field in >>>>> the SYN_STREAM message, and 2) a new REPRI message that updates the >>>>> dependency pointers of existing streams. To allow servers to advertise >>>>> their support for scheduling transfers based on dependencies, we propose a >>>>> new SETTINGS id/value pair. We describe the layout and semantics of >>>>> each in turn. >>>>> >>>>> Note that these protocol changes are defined in terms of the latest >>>>> version of the SPDY draft specification<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html> >>>>> . >>>>> >>>>> SYN_STREAM: >>>>> 0 1 2 3 4 5 6 7 >>>>> >>>>> +--------+--------+--------+-|-------+--------+--------+--------+--------+ >>>>> | Length(16) |Flags(8)|1| Stream Id(31) | >>>>> 0x1 | -> >>>>> >>>>> +--------+--------+--------+-|-------+--------+--------+--------+--------+ >>>>> >>>>> 8 9 10 11 12,13,14..N >>>>> +-+-------+--------+--------+--------+=========================+ >>>>> |P| PriOrDep(31) | Name/Value Header Block | >>>>> +-+-------+--------+--------+--------+=========================+ >>>>> >>>>> Here, the first 8 bytes are the standard control frame header (§2.2.2<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#ControlFrames>). >>>>> A new 32 bit field replaces the existing SYN_STREAM priority bits ( >>>>> §2.6.1<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#SYN_STREAM>) >>>>> with: >>>>> >>>>> >>>>> - P: A bit indicating whether the following PriOrDep bits specify >>>>> a priority (P = 1) or a stream ID (P = 0) on which this new stream >>>>> depends. >>>>> - PriOrDep: Depending on the value of P, either the priority of >>>>> the new stream or a stream ID on which this new stream depends. >>>>> - The structure and semantics of the Name/Value header block ( >>>>> §2.6.11<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#HeaderBlock>) >>>>> are unchanged. >>>>> >>>>> >>>>> P is exclusive; a stream may be assigned a priority or a parent >>>>> dependency upon creation, but not both. There are no constraints of the >>>>> value of PriOrDep; any 31 bit value is valid. Thus, a stream may >>>>> refer to a dependency identifier that does not correspond to any current or >>>>> previous stream ID. This is a deliberate design choice that increases >>>>> flexibility for clients when structuring dependencies, a topic we expand >>>>> upon in the policies section<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.6ii1fem7qsws> >>>>> . >>>>> >>>>> Server push streams are assigned an initial parent at the discretion >>>>> of the server. A conformant implementation SHOULD create a dependency on >>>>> the push stream's associated-to-stream-id (§3.3.1<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#anchor20> >>>>> ). >>>>> >>>>> REPRI: >>>>> 0 1 2 3 4 5 6 7 >>>>> >>>>> +--------+--------+--------+-|-------+--------+--------+--------+--------+ >>>>> | Length(16) |Flags(8)|1| Dependency Id(31) | >>>>> 0xc | -> >>>>> >>>>> +--------+--------+--------+-|-------+--------+--------+--------+--------+ >>>>> >>>>> 8 9 10 11 >>>>> +-+-------+--------+--------+--------+ >>>>> |P| PriOrDep(31) | optionally followed by: >>>>> +-+-------+--------+--------+--------+ >>>>> >>>>> DependencyPriOrDep pairs, where a DependencyPriOrDep pair is: >>>>> >>>>> >>>>> +-|-------+--------+--------+--------+-|-------+--------+--------+--------+ >>>>> |X| Dependency Id (31) |P| PriOrDep(31) >>>>> | >>>>> >>>>> +-|-------+--------+--------+--------+-|-------+--------+--------+--------+ >>>>> >>>>> As in SYN_STREAM, the control frame header is standard, followed by a >>>>> P/PriOrDep label indicating an update to the 31 bit Dependency Id specified >>>>> in the header. We relabel the typical Stream Id here as Dependency Idsince a dependency need not correspond to an actual stream. (Recall that >>>>> any 31 bit value is a valid dependency identifier.) >>>>> >>>>> To support batched updates of dependencies, an optional list of >>>>> DependencyPriOrDep pairs with identical semantics may follow. The >>>>> number of such pairs is determined by examining the frame length. >>>>> number-of-pairs = ((length - 12) / 8). (12 required bytes, 8 bytes >>>>> from len(stream_id) + len(PriOrDep)) >>>>> >>>>> We expect most streams to have at most a single dependency, but this >>>>> is not a protocol requirement. (Later, we describe scenarios where multiple >>>>> parents may improve efficiency.) If a stream is referenced more than once >>>>> in a single frame, this indicates multiple parents. A server implementation >>>>> which does not support multiple parents MUST use the last referenced >>>>> parent. Clients which send multiple parents thus SHOULD put the most >>>>> important parent last. >>>>> >>>>> SETTINGS: >>>>> Recall that dependencies and priorities are advisory. While servers >>>>> must accept the messages, they are not required to incorporate them into >>>>> scheduling decisions. A client may benefit from knowing a server's level of >>>>> support; e.g., a client may specify priorities only if it knows a server >>>>> will ignore dependencies. To communicate this, we propose a new >>>>> SETTINGS ID/value pair (§2.6.4<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#SETTINGS> >>>>> ), >>>>> >>>>> >>>>> - ID 9 - SETTINGS_MAX_CONCURRENT_DEPENDENCY_SCHEDULING_NODESallows the server to indicate resource limits for dependency scheduling, >>>>> e.g., to limit memory consumption. A value of 0 indicates that the server >>>>> does not support dependency scheduling. (We expect most implementations >>>>> will select a value greater than or equal to MAX_CONCURRENT_STREAMS >>>>> .) >>>>> - ID 10 - SETTINGS_DEPENDENCY_SCHEDULING_NODE_TIMEOUT indicates >>>>> how long the server will maintain dependency nodes after creation. The >>>>> value is an interval in milliseconds. This allows the client to estimate if >>>>> previously created dependency relationships are still available for >>>>> reference at the server. (We expect conformant implementations to maintain >>>>> dependencies for at least as long as associated streams are active, >>>>> although this is not a correctness requirement.) >>>>> >>>>> >>>>> Both of these values are advisory. Servers need not abide by their >>>>> stated values and clients may disregard them. Conformant clients should >>>>> respect the concurrency limit, but servers must be robust to a client that >>>>> exceeds it. Similarly, servers may drop dependency information at any time >>>>> regardless of previous statements made in SETTINGS. This is intended >>>>> to provide flexibility for service policies; e.g., a server may reduce the >>>>> timeout in response to memory pressure or abandon dependency scheduling >>>>> entirely. >>>>> >>>>> Examples / use-cases revisited >>>>> The combination of dependencies and priorities suffices to express >>>>> serialized as well as concurrent transfer schedules. (Both are necessary, >>>>> as we describe below.) But, how should the browser choose dependencies and >>>>> priorities when making requests? This question is best answered >>>>> quantitatively, but as a starting point, we consider the following policy >>>>> in our examples: >>>>> >>>>> >>>>> 1. Resource dependencies are (re)configured to reflect >>>>> parser-blocking order. The transfer of non-streaming resources is always >>>>> serialized; i.e., non-async scripts and styling. >>>>> 2. Resources that can be progressively rendered (e.g., images) are >>>>> transferred concurrently and (re)configured to depend on parser-blocking >>>>> resource transfers. >>>>> 3. To ensure that the speculative parser can maintain enough >>>>> in-flight requests to fill pipe between the client and server, page HTML is >>>>> always a top-level dependency, although it may have lower priority than a >>>>> resource transfer currently blocking document parsing. >>>>> >>>>> >>>>> When scheduling transfers, we consider a server that allocates >>>>> bandwidth hierarchically within dependency trees and splits equallyamong streams with the same parent. >>>>> >>>>> Concretely, suppose a SPDY connection is multiplexing multiple tabs >>>>> from a user connected to a SPDY proxy, with parent pointers and priorities >>>>> as shown below. (P6, for example, indicates a priority of 6.) >>>>> >>>>> To color in this example, suppose that Tab 1 is the foreground tab, >>>>> loading in parallel with Tab 2 in the background. Thus, its relatively >>>>> higher weight. a.js and b.js are scripts required for the first tab >>>>> and should be transferred serially (as scripts are executed in the order >>>>> they are declared in the document, and are not parsed until transfer >>>>> completes.) Thus, a.js depends on b.js depends on tab1.htm. In the >>>>> background tab, two image transfers share capacity as both can be rendered >>>>> progressively. Both image transfers have the same parent and hence transfer >>>>> concurrently. >>>>> >>>>> Because the streams associated with the transfers of tab1 and tab2 >>>>> have no parent, they are always scheduled before any lower level in their >>>>> trees. But, bandwidth allocation among trees remains proportional as >>>>> defined by the relative priority of roots. For example, if the transfer of >>>>> tab2.htm is in progress and tab1.htm (now complete) is selected, a.jswill be scheduled before >>>>> tab2.htm completes. This process proceeds until all transfers in a >>>>> tree have completed. >>>>> >>>>> As a practical matter, the timeout for pruning nodes in a tree should >>>>> be selected to allow transfers to complete and to allow clients to name >>>>> currently completed parents when defining transfer dependencies. >>>>> Concretely, on a high delay path, a small HTML transfer may be flushed >>>>> entirely by the server before the client receives any data and begins >>>>> making dependent requests for resources embedded in the page. >>>>> >>>>> With these client and server policies in mind, we revisit the >>>>> motivating use-cases described above in greater detail. >>>>> >>>>> - Specifying an ordering of resource transfers >>>>> - Reacting to document parsing >>>>> >>>>> We illustrate the need for both serial dependencies, concurrency, and >>>>> reprioritization in these cases with a simple example. >>>>> >>>>> Suppose site.com has index.htm: >>>>> <html> >>>>> <body> >>>>> <script src="a.js"></script> >>>>> <img src="a.jpg" width="100" height="100"/> >>>>> <img src="b.jpg" width="100" height="100"/> >>>>> <link rel="stylesheet" type="text/css" href="style.css"> >>>>> </body> >>>>> >>>>> with a.js: >>>>> document.write('<script src="b.js"></script>'); >>>>> >>>>> b.js: >>>>> document.write('<div>blocker</div>'); >>>>> >>>>> and style.css: >>>>> div { >>>>> border: 1px solid #000; >>>>> } >>>>> >>>>> How would this example page be transferred today? As the main HTML is >>>>> received and parsed, a request for a.js will be issued and block the >>>>> document parser. As the remaining HTML streams in, the speculative parser >>>>> will issue requests for a.jpg, b.jpg, and style.css in quick succession. >>>>> Once a.js is received and executed, a request for b.js will be issued, >>>>> which again blocks parsing until received. Visually: >>>>> >>>>> >>>>> This transfer schedule is suboptimal. Page rendering will complete >>>>> only when style.css and b.js have completed, but receiving each of those >>>>> critical resources is slowed by competition for bandwidth capacity with >>>>> bulk data that's not on the critical path (a.jpg and b.jpg). >>>>> >>>>> What we would like is serialized transfer that reflects the document >>>>> parse order with concurrency for nonblocking, streaming resources. More >>>>> specifically, we want to receive: 1) index.html, 2) a.js, 3) b.js, and 4) >>>>> style.css serialized (i.e., with no deliberate sharing of capacity among >>>>> the ordered transfers). After those critical transfers have completed, >>>>> a.jpg and b.jpg should be transferred concurrently (as they may be >>>>> displayed progressively.) >>>>> >>>>> Folding in the protocol mechanisms described above: >>>>> >>>>> >>>>> In the figure, each resource request corresponds to a new SPDY stream >>>>> with the form ID: reqest (PriOrDep). In more detail: >>>>> >>>>> >>>>> - The SYN_STREAM for the index.htm request has a parent indicating >>>>> a default priority (3) and a stream id of 1. >>>>> - The document parser is blocked once the external script a.js is >>>>> parsed. At this point, the speculative parser looks ahead and creates new >>>>> streams for a.jpg, b.jpg in parse order. a.jpg and b.jpg can be >>>>> progressively rendered, so their transfer is concurrent (same parent, 2, >>>>> corresponding to a.js). >>>>> - When the parser encounters style.css, back-to-back control >>>>> messages are sent to create the stream and update the dependencies of the >>>>> image transfers. Since stylesheets block rendering and cannot be streamed, >>>>> the image transfers are updated to depend on style.css (P5). >>>>> - Once a.js completes, the document parser continues, executing >>>>> a.js and inserting b.js via document.write(), again blocking >>>>> document parsing on the receipt of b.js. At this point, b.js should preempt >>>>> all other transfers since it's a non-streaming resource that is blocking >>>>> page rendering. To this end, the client creates the b.js stream with a.js >>>>> as its parent (or, equivalently, index.htm). Batched with this >>>>> SYN_STREAM is another REPRI message rewiring style.css to depend >>>>> on b.js. This serializes the transfers (modulo the delay associated with >>>>> message propagation and any transfer buffering delay at the server). >>>>> >>>>> >>>>> This transfer schedule may significantly improve performance. By >>>>> serializing the transfer of resources on the critical path, the browser can >>>>> ensure that resources needed immediately do not compete for bandwidth >>>>> capacity with less important transfers. Yet, the pipe remains full, as a >>>>> queue of requests is maintained in the scheduling tree ready to fill any >>>>> idle capacity with useful data. Where we cannot make an informed scheduling >>>>> decision, we hedge our bets with concurrent transfers by hinting that they >>>>> are peers and letting the server decide what makes the most sense --- as in >>>>> the case of two above the fold images that can be rendered progressively. >>>>> >>>>> Note that this sort of explicit scheduler hinting is not possible in >>>>> HTTP today. Requests, once issued, cannot be reprioritized or reordered on >>>>> a single connection. This results in suboptimal transfer schedules given >>>>> the limitations of HTML lookahead scanning. Yet, lookahead is essential for >>>>> ensuring the concurrency necessary to keep the client <-> server pipe full. >>>>> While the browser might serialize transfers itself, the many small >>>>> transfers typical of pageloads would significantly limit utilization. With >>>>> ordering and reprioritization in SPDY, browsers can jointly optimize both >>>>> the transfer pipeline and resource priority as desired, rather than >>>>> being forced to accept poor utilization or poor transfer schedules. >>>>> >>>>> - Servicing multiple tabs/users over a single SPDY session >>>>> As an illustration of this case, recall the example from our straw-man >>>>> design: >>>>> >>>>> >>>>> Suppose concurrent tabs are loading with a scheduling forest as shown. >>>>> When a user changes tabs, the browser simple sends a REPRI for the >>>>> stream associated with tab2.htm to, say, priority 8. (A batched message >>>>> might also reduce the priority of tab1.htm to weight 3.) Because bandwidth >>>>> allocation decisions are made tree-by-tree and level-by-level, increasing >>>>> the priority of tab2.htm effectively shifts capacity for all resource >>>>> transfers depending on tab1.htm to tab2.htm. >>>>> >>>>> - Server push >>>>> As in client SYN_STREAM messages, server push messages indicate the >>>>> priority and dependencies of a resource as chosen by the server. Much >>>>> like the client, the server is free to adopt prioritization policies to >>>>> improve performance, e.g., by prioritizing pushes of styles over images. >>>>> But, as in our example above, the browser may update the server's choices >>>>> as information about resources needed for parsing is learned. (Again, >>>>> expressed via REPRI messages.) >>>>> >>>>> Policy considerations >>>>> Both priorities and stream dependencies are advisory hints. Browsers >>>>> may adopt sophisticated policies or leave dependencies entirely >>>>> unspecified. Similarly, servers may incorporate dependency hints into very >>>>> sophisticated schedulers or ignore them entirely. The protocol >>>>> mechanisms for encoding dependencies are designed to be simple. But, >>>>> these mechanisms afford a very flexible set of policies depending on how >>>>> browsers and servers use them. This section expands on several policy >>>>> considerations. >>>>> >>>>> Assigning and updating dependencies. >>>>> Updates and overhead >>>>> In our examples, we consider a browser that configures dependencies to >>>>> reflect parser-blocking order for resources, updated as parsing continues. >>>>> We expect this to improve performance, but browsers are free to deviate >>>>> from this policy, and there may be good reasons to do so. For example, if >>>>> the parser-blocking order is highly dynamic (e.g., in response to many JS >>>>> events), the overhead of updating dependencies may not be worth the cost, >>>>> particularly for small transfers. A sophisticated client may base >>>>> dependency update decisions on content-length and/or RTT, restricting >>>>> updates to only those streams likely to benefit from it. Quantitative >>>>> implementation experience will be helpful here. >>>>> >>>>> The overhead of updating dependencies depends in part on the existing >>>>> structure of dependencies. In some scenarios, it may be more efficient to >>>>> introduce placeholder nodes to improve the efficiency of common update >>>>> operations. For example, consider a variant of our earlier example page: >>>>> >>>>> <html> >>>>> <body> >>>>> <script src="a.js"></script> <!-- containing: document.write('<script >>>>> src="b.js"></script>'); --> >>>>> <img src="1.jpg" width="100" height="100"/> >>>>> <img src="2.jpg" width="100" height="100"/> >>>>> <img src="3.jpg" width="100" height="100"/> >>>>> ... >>>>> <img src="10.jpg" width="100" height="100"/> >>>>> </body> >>>>> >>>>> In this example, the speculative parser might create 10 streams >>>>> depending on the JS transfer; i.e., >>>>> >>>>> But, once a.js is executed, the transfer of b.js should preempt all >>>>> image transfers; i.e., >>>>> >>>>> Transitioning between these dependency structures requires sending >>>>> REPRI messages for each image. Because updating the dependencies of >>>>> images is common, a client might create all image streams with a >>>>> placeholder dependency, yielding an initial configuration of: >>>>> With such an initial configuration, updating the dependencies of the >>>>> images to the stream associated with b.js can be accomplished with a single >>>>> REPRI message updating the placeholder. >>>>> >>>>> Multiple parents >>>>> >>>>> ... >> >> >
Received on Sunday, 3 November 2013 23:24:10 UTC