Contenu connexe Similaire à Promise of Push (HTTP/2 Web Performance) (20) Promise of Push (HTTP/2 Web Performance)1. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2 Web Performance
Promise of Push
@ColinBendell
Director, CTO Office
5. ©2016 AKAMAI | FASTER FORWARD™
Time-To-First-Byte
25% of Perf. Budget is waiting
Many causes: User (Network, Device,
CPU), App Server, etc
6. ©2016 AKAMAI | FASTER FORWARD™
Introducing
Network Waste
1.48s (full
throughput)
87.6% WASTE
7. ©2016 AKAMAI | FASTER FORWARD™
Network Waste
An opportunity to PUSH content
Move the
experience
87.6% WASTE
9. ©2016 AKAMAI | FASTER FORWARD™
Direct TCP
Poll/Long Poll
Pushlets
SSE
Hasn't Push
been solved?
10. How to PUSH
TCP/IP Socket (eg: XMPP)
<stream:stream
to='example.com'
xmlns='jabber:client'
version='1.0'>
<stream:stream
from='example.com'
id='someid'
xmlns='jabber:client'
version='1.0'>
<message from='juliet@capulet.com'
to='romeo@montague.net'>
<body>Art thou not Romeo,
and a Montague?</body>
</message> <message from='romeo@montague.net'
to='juliet@capulet.com'>
<body>Neither, fair saint,
if either thee dislike.</body>
</message>
<message from='juliet@capulet.com'
to='romeo@montague.net'>
<body>How camest thou hither,
tell me, and wherefore? </body>
</message>
11. ©2016 AKAMAI | FASTER FORWARD™
How to PUSH
TCP/IP Socket (eg: XMPP)
• Proprietary & efficient
• Any content could be sent
• But requires app logic to encode/decode
• Likely ports blocked by firewall rules
12. How to PUSH
Polling / Long Polling
GET /messages HTTP/1.1
Host: queue.example.com
Authorization: ...
HTTP/1.1 200 OK
Content-Length: 100
{ "from": "adbram@montague.net",
"to": "sampson@capulet.com",
"message: "Do you bite your
thumb at us, sir?
}
13. ©2016 AKAMAI | FASTER FORWARD™
How to PUSH
Polling / Long Polling
• Ports 80/443
• Polling is chatty; has battery impacts
• Custom protocol: requires app logic
• Connection timeouts
• Must manually handle disconnect & resume
14. ©2016 AKAMAI | FASTER FORWARD™
How to PUSH
Pushlet
GET /messages HTTP/1.1
Host: queue.example.com
Authorization: ... HTTP/1.1 200 OK
Transfer-Encoding: Chunked
Connection: keep-alive
Content-Type: text/html
<html><head/><body>
<h1>Messages</h1>
<p>From: sampson@capulet.com</p>
<p>To: adbram@montague.net</p>
<p>I do bite my thumb, sir.</p>
<p>From: sampson@capulet.com</p>
<p>To: adbram@montague.net</p>
<p>No, sir, I do not bite my thumb at
you, sir, but I bite my thumb, sir.<p>
15. ©2016 AKAMAI | FASTER FORWARD™
How to PUSH
Pushlet
• No app logic required
• Continuously "loading" UX
• CPU/Network/Battery impacts?
• Text only
• Client must must detect connection loss
16. ©2016 AKAMAI | FASTER FORWARD™
How to PUSH
Server-Side-Events
GET /messages HTTP/1.1
Host: api.example.com
Accept: text/event-stream
Authorization: ...
Last-Event-ID: 41
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: text/event-stream
Transfer-Encoding: chunked
id: 42
event: receiveMessage
data: { "from": "adbram@montague.net",
"to": "sampson@capulet.com",
"message: "Do you bite your
thumb at us, sir?}
id: 43
event: stageAction
data: { "from": "adbram@montague.net",
"to": "sampson@capulet.com",
"message: "Do you bite your
thumb at us, sir?}
17. ©2016 AKAMAI | FASTER FORWARD™
How to PUSH
Server-Side-Events
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: text/event-stream
Transfer-Encoding: chunked
id: 42
event: recieveMessage
data: { "from": "adbram@montague.net",
"to": "sampson@capulet.com",
"message: "Do you bite your
thumb at us, sir?}
id: 43
event: stageAction
data: { "from": "adbram@montague.net",
"to": "sampson@capulet.com",
"message: "Do you bite your
thumb at us, sir?}
<script type="text/javascript">
var evtSource = new EventSource(
"//api.example.com/messages",
{ withCredentials: true } );
evtSource.addEventListener("receiveMessage",
function(e) {
var newElement = document.createElement("p");
var obj = JSON.parse(e.data);
newElement.innerHTML = "Message: " + obj.message;
eventList.appendChild(newElement);
}, false);
</script>
18. ©2016 AKAMAI | FASTER FORWARD™
How to PUSH
Server-Side-Events
• HTML5 browsers or Polyfill
• Standard APIs
• Text only messages
• Intermediates must support flushing
19. ©2016 AKAMAI | FASTER FORWARD™
HTTP/1.1
State of Push
• Build it yourself
• Requires app logic to be loaded
• (generally) Text only
• Messaging focused, not performance
20. ©2016 AKAMAI | FASTER FORWARD™
WebRTC
WebSocket
HTTP/2 Push
(Do we need yet
another technology?)
Wait!
What about:
21. ©2016 AKAMAI | FASTER FORWARD™
Peer-to-Peer with
WebRTC
• Peer to Peer
• UDP (+FlowControl)
• Web APIs
• BYOA (bring your own app)
• Usually: Audio/Video
Flexibility: High
RealTime: High
Complexity: High
22. ©2016 AKAMAI | FASTER FORWARD™
One-to-One with
WebSockets
• One-to-One (User to Server)
• Bidirectional socket
• Web APIs
• BYOA (bring your own app)
• Can by binary or text
• Not cacheable
Flexibility: Medium
RealTime: High
Complexity: Medium-High
var ws = new WebSocket('wss://example.com/socket');
ws.onerror = function (error) { }
ws.onclose = function () { }
ws.onopen = function () { }
ws.onmessage = function(msg) {
if(msg.data instanceof Blob) {
processBlob(msg.data);
} else {
processText(msg.data);
}
}
Function sendMessage(msgText) {
ws.send(msgText);
}
23. ©2016 AKAMAI | FASTER FORWARD™
One-to-Many with
HTTP/2 Push
• Many-to-One (Users to Server)
• H2 standard
• Cacheable
• Transparent to app
Flexibility: Medium
RealTime: Low
Complexity: Low
[ 0.270] recv (stream_id=13) :method: GET
[ 0.270] recv (stream_id=13) :path: /demo/h2/push.css
[ 0.271] recv (stream_id=13) accept: */*
[ 0.271] recv PUSH_PROMISE frame <length=72,
flags=0x04, stream_id=13>
; END_HEADERS
(padlen=0, promised_stream_id=2)
25. ©2016 AKAMAI | FASTER FORWARD™
Overview
HTTP/2 Basics
Fix HTTP/1.1 Performance Other?
├ Head of Line Blocking
├ Parallelism
├ Header compression
└ Backward Compatible
├ Prioritization
├ Flow Control
└ Binary Protocol
└ Server Push
28. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2
Reading the Matrix
$ nghttp https://www.colinbendell.com/demo/h2/pushtest.html -vv
[ 0.135] Connected
The negotiated protocol: h2
[ 0.230] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0.230] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
(dep_stream_id=0, weight=201, exclusive=0)
[ 0.230] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
(dep_stream_id=0, weight=101, exclusive=0)
[ 0.230] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
(dep_stream_id=0, weight=1, exclusive=0)
Frame Name Bytes
Odd = Client
Initiated
29. ©2016 AKAMAI | FASTER FORWARD™
[ 0.230] send HEADERS frame <length=60, flags=0x25, stream_id=13>
; END_STREAM | END_HEADERS | PRIORITY
(padlen=0, dep_stream_id=11, weight=16, exclusive=0)
; Open new stream
:method: GET
:path: /demo/h2/pushtest.html
:scheme: https
:authority: www.colinbendell.com
accept: */*
accept-encoding: gzip, deflate
user-agent: nghttp2/1.6.0
Familiar
HTTP Request
Pseudo
Headers
30. ©2016 AKAMAI | FASTER FORWARD™
[ 0.267] recv SETTINGS frame <length=30, flags=0x00, stream_id=0>
(niv=5)
[SETTINGS_HEADER_TABLE_SIZE(0x01):4096]
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[SETTINGS_MAX_FRAME_SIZE(0x05):16384]
[SETTINGS_MAX_HEADER_LIST_SIZE(0x06):16384]
[ 0.267] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.267] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
Flow Control
31. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2
PUSH_PROMISE
[ 0.270] recv (stream_id=13) :method: GET
[ 0.270] recv (stream_id=13) :path: /demo/h2/push.css
[ 0.270] recv (stream_id=13) :authority: www.colinbendell.com
[ 0.270] recv (stream_id=13) :scheme: https
[ 0.270] recv (stream_id=13) host: www.colinbendell.com
[ 0.271] recv (stream_id=13) accept: */*
[ 0.271] recv (stream_id=13) user-agent: nghttp2/1.6.0
[ 0.271] recv (stream_id=13) accept-encoding: gzip, deflate
[ 0.271] recv PUSH_PROMISE frame <length=72, flags=0x04, stream_id=13>
; END_HEADERS
(padlen=0, promised_stream_id=2)
Existing Stream
Even: Server Initiated
32. ©2016 AKAMAI | FASTER FORWARD™
[ 0.313] recv (stream_id=2, sensitive) :status: 200
[ 0.313] recv (stream_id=2, sensitive) server: Apache
[ 0.313] recv (stream_id=2, sensitive) etag: "e00af44aba37028e02014b684
[ 0.313] recv (stream_id=2, sensitive) last-modified: Fri, 22 Apr 2016
[ 0.313] recv (stream_id=2, sensitive) accept-ranges: bytes
[ 0.313] recv (stream_id=2, sensitive) content-length: 64
[ 0.313] recv (stream_id=2, sensitive) content-type: text/css
[ 0.313] recv (stream_id=2, sensitive) cache-control: max-age=3571
[ 0.313] recv (stream_id=2, sensitive) expires: Sun, 24 Apr 2016 16:22:
[ 0.313] recv (stream_id=2, sensitive) date: Sun, 24 Apr 2016 15:23:02
[ 0.313] recv HEADERS frame <length=469, flags=0x04, stream_id=2>
; END_HEADERS
(padlen=0)
[ 0.313] recv (stream_id=2, length=64, srecv=64, crecv=621) DATA
Lorem;ipsum
[ 0.313] recv DATA frame <length=64, flags=0x00, stream_id=2>
[ 0.313] recv DATA frame <length=0, flags=0x01, stream_id=2>
; END_STREAM
Delay, Push Response
33. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2
PUSH_PROMISE
$ nghttp https://www.colinbendell.com/demo/h2/pushtest.html -vv --no-push
[ 0.123] Connected
The negotiated protocol: h2
[ 0.518] send SETTINGS frame <length=18, flags=0x00, stream_id=0>
(niv=3)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[SETTINGS_ENABLE_PUSH(0x02):0]
Push Not Supported
[ 0.230] send RST_STREAM frame <length=5, flags=0x07, stream_id=4>
Push not accepted
36. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2 PUSH
How do I enable?
HTTP/1.1 200 OK
Content-Type: text/html
Link: /jquery.js; rel=preload; as=script
Link: /global.css; rel=preload; as=style
1. Use the ` Link: <URL>; rel=preload; as=style` notation
Pros:
• Easy to implement
• H2O / nginX support
Cons:
• Too-Late; Is TTFB
• Status & headers committed
• Interferes with Browser's Pre-Loader
37. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2 PUSH
How do I enable?
public class MyServlet extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String uri = request.getRequestURI();
if ("/index.html".equals(uri))
{
String resourceToPush = "/js/jquery.js";
RequestDispatcher dispatcher =
request.getRequestDispatcher(resourceToPush);
dispatcher.push(request);
}
}
}
2. Manually Instrument
38. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2 PUSH
How do I enable?
2. Manually Instrument
Pros:
• Before TTFB
• Not impacted by page
• Can extend to Next Page
Cons:
• Another layer to maintain
46. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2 (Chrome)
Adopted Push Stream
chrome://net-internals to find unclaimed pushes
Adopted pushes are logged (not a frame)
* PUSH is kept in memory for 5 minutes and then get deleted if unclaimed
47. ©2016 AKAMAI | FASTER FORWARD™
Debugging PUSH
• Terminal: nghttp
• Chrome: look for provisional header
or use net-internals
• Firefox: enabling logging
• PUSHed content isn't added to cache until
used in the page
50. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2
Connection Coalescing
Coalescing is ignored by Chrome/FF
51. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2 Chrome
Connection coalescing not avail
if (!HostPortPair::FromURL(gurl).Equals(host_port_pair())) {
if (proxy_delegate_ &&
proxy_delegate_->IsTrustedSpdyProxy(
ProxyServer(ProxyServer::SCHEME_HTTPS, host_port_pair()))) {
if (gurl.SchemeIs("https")) {
EnqueueResetStreamFrame(
stream_id, request_priority, RST_STREAM_REFUSED_STREAM,
base::StringPrintf("Rejected push of cross origin HTTPS
content %d "
"from trusted proxy",
associated_stream_id));
return false;
}
Only Host + Port considered! Boo!
52. ©2016 AKAMAI | FASTER FORWARD™
Browser Support
Implementation notes
• PUSHed content from different hosts are
rejected instead of coalescing
• Only used PUSHes hit cache
• FF uses init flow control of 64kb
54. ©2016 AKAMAI | FASTER FORWARD™
www.rakuten.co.uk
TTFB: Network Waste
TTFB: 330ms
95.9% Waste
55. ©2016 AKAMAI | FASTER FORWARD™
www.rakuten.co.uk
Time-to-First-Resource
TTFR: 762ms
91.1% Waste
56. ©2016 AKAMAI | FASTER FORWARD™
www.rakuten.co.uk
33.7% Perf Waste
1.48s (full
throughput)
87.6% WASTE Vis. Complete:
4.38s
57. ©2016 AKAMAI | FASTER FORWARD™
www.forever21.com
WPT: Network Waste
81.7%
0.6s (full
throughput)
58. ©2016 AKAMAI | FASTER FORWARD™
Browser Support
Implementation notes
• Measures opportunity to use the network
ahead of DOM/Browser load
• Indicator metric – NOT silver bullet
• Examines WPT results
• Tool to be released later this month
60. ©2016 AKAMAI | FASTER FORWARD™
PUSH Results
Insurance Site
Original CSS/JSOriginal
Everything Images
61. ©2016 AKAMAI | FASTER FORWARD™
PUSH Results
Cosmetics Site
Original
CSS/JS Everything
Images
62. ©2016 AKAMAI | FASTER FORWARD™
Automatic PUSH_PROMISE
But when you get it Right:
5.27s 8.59s
63. ©2016 AKAMAI | FASTER FORWARD™
PUSH Results
Conclusions
• Bad: too much, slows DOM complete
• Bad: too much can compete with preloader
• Bad: Wrong order congests network
• Good: Critical CSS & JS (& some images)
• Awesome: Network + Resource Timing
64. ©2016 AKAMAI | FASTER FORWARD™
PUSH Results
Implementation questions
• Impact on Set-Cookie session tracking?
• REsponsive ServerSide?
• Client Hints?
66. ©2016 AKAMAI | FASTER FORWARD™
HTTP/2 PUSH_PROMISE
Programmatic accept
<?php
$transfers = 1;
$callback = function() use (&$transfers) {
$transfers++;
return CURL_PUSH_OK;
};
$mh = curl_multi_init();
curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, $callback);
$ch = curl_init();
curl_setopt($ch, CURLOPT_VERBOSE, 1);
67. ©2016 AKAMAI | FASTER FORWARD™
PUSH
What's Next:
• Browser & OS Support
• Automated PUSH using analytics
• Next page resources
• Host coalescing
68. ©2016 AKAMAI | FASTER FORWARD™
PUSH
What about?
• Javascript / CSS / Image early processing?
• 3rd Party Content & Link=PreConnect ?
• PUSH to surrogate but not client?
• Delay & FlowControl: PUSH + Priorities
• Cache Management / Invalidation