Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Promise of Push (HTTP/2 Web Performance)

1,611 views

Published on

HTTP/2 Push

Published in: Software
  • Be the first to comment

Promise of Push (HTTP/2 Web Performance)

  1. 1. ©2016 AKAMAI | FASTER FORWARD™ HTTP/2 Web Performance Promise of Push @ColinBendell Director, CTO Office
  2. 2. ©2016 AKAMAI | FASTER FORWARD™ Desktop 90th50thBudget Mobile
  3. 3. ©2016 AKAMAI | FASTER FORWARD™ Improving Perf: Blame the content
  4. 4. ©2016 AKAMAI | FASTER FORWARD™ WebPageTest Looking for culprits
  5. 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. 6. ©2016 AKAMAI | FASTER FORWARD™ Introducing Network Waste 1.48s (full throughput) 87.6% WASTE
  7. 7. ©2016 AKAMAI | FASTER FORWARD™ Network Waste An opportunity to PUSH content Move the experience 87.6% WASTE
  8. 8. ©2016 AKAMAI | FASTER FORWARD™ Chapter 1: PUSH on the Web
  9. 9. ©2016 AKAMAI | FASTER FORWARD™ Direct TCP Poll/Long Poll Pushlets SSE Hasn't Push been solved?
  10. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 20. ©2016 AKAMAI | FASTER FORWARD™ WebRTC WebSocket HTTP/2 Push (Do we need yet another technology?) Wait! What about:
  21. 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. 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. 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)
  24. 24. ©2016 AKAMAI | FASTER FORWARD™ 9 (8+)6+ (4.4)
  25. 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
  26. 26. ©2016 AKAMAI | FASTER FORWARD™ Chapter 2: PUSH_PROMISE
  27. 27. HTTP/2 PUSH_PROMISE Frame Basics PUSH_PROMISE :url: /push.css user-agent: chrome RST_STREAM DATA promised-stream-id: 2 a:hover {color: blue} … 2 2 … or ... 13
  28. 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. 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. 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. 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. 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. 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
  34. 34. chrome://net-internals
  35. 35. ©2016 AKAMAI | FASTER FORWARD™ Invoking
  36. 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. 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. 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
  39. 39. ©2016 AKAMAI | FASTER FORWARD™ Visualizing & Debug
  40. 40. ©2016 AKAMAI | FASTER FORWARD™ Visualizing Results
  41. 41. ©2016 AKAMAI | FASTER FORWARD™ Delayed Push with Link=preload
  42. 42. ©2016 AKAMAI | FASTER FORWARD™ Manual Instrument (Jetty)
  43. 43. ©2016 AKAMAI | FASTER FORWARD™ Push headers are 'provisional'
  44. 44. ©2016 AKAMAI | FASTER FORWARD™ Timeline not helpful (Chrome 50)
  45. 45. ©2016 AKAMAI | FASTER FORWARD™ Canary (52) shows PUSH in Timeline
  46. 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. 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
  48. 48. ©2016 AKAMAI | FASTER FORWARD™ Browser Behavior
  49. 49. Browser support Testing PUSH
  50. 50. ©2016 AKAMAI | FASTER FORWARD™ HTTP/2 Connection Coalescing Coalescing is ignored by Chrome/FF
  51. 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. 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
  53. 53. ©2016 AKAMAI | FASTER FORWARD™ Chapter 3: PUSH opportunity
  54. 54. ©2016 AKAMAI | FASTER FORWARD™ www.rakuten.co.uk TTFB: Network Waste TTFB: 330ms 95.9% Waste
  55. 55. ©2016 AKAMAI | FASTER FORWARD™ www.rakuten.co.uk Time-to-First-Resource TTFR: 762ms 91.1% Waste
  56. 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. 57. ©2016 AKAMAI | FASTER FORWARD™ www.forever21.com WPT: Network Waste 81.7% 0.6s (full throughput)
  58. 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
  59. 59. ©2016 AKAMAI | FASTER FORWARD™ Chapter 4: Results
  60. 60. ©2016 AKAMAI | FASTER FORWARD™ PUSH Results Insurance Site Original CSS/JSOriginal Everything Images
  61. 61. ©2016 AKAMAI | FASTER FORWARD™ PUSH Results Cosmetics Site Original CSS/JS Everything Images
  62. 62. ©2016 AKAMAI | FASTER FORWARD™ Automatic PUSH_PROMISE But when you get it Right: 5.27s 8.59s
  63. 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. 64. ©2016 AKAMAI | FASTER FORWARD™ PUSH Results Implementation questions • Impact on Set-Cookie session tracking? • REsponsive ServerSide? • Client Hints?
  65. 65. ©2016 AKAMAI | FASTER FORWARD™ Chapter 5: Epilogue
  66. 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. 67. ©2016 AKAMAI | FASTER FORWARD™ PUSH What's Next: • Browser & OS Support • Automated PUSH using analytics • Next page resources • Host coalescing
  68. 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
  69. 69. ©2016 AKAMAI | FASTER FORWARD™ PUSH 10? 10?7??
  70. 70. ©2016 AKAMAI | FASTER FORWARD™ Thanks! @ColinBendell

×