[PHPUK16] Every Millisecond Counts: Performance & UX

Fee39f0c0ffb29d9ac21607ed188be6b?s=47 Davey Shafik
February 18, 2016

[PHPUK16] Every Millisecond Counts: Performance & UX

How do you lose 900 million dollars in 100ms? Or 8 million visits in just 4/10 of a second?

User expectations are higher than ever when it comes to web performance, so much so that we've created an entirely new application architecture just to make it feel like our websites are faster than they actually are.

This talk will look at how we can improve our users experience at any scale through performance optimizations at every layer of the stack, from backend to browser.

Fee39f0c0ffb29d9ac21607ed188be6b?s=128

Davey Shafik

February 18, 2016
Tweet

Transcript

  1. 1.

    E V E R Y M I L L I

    S E CO N D CO U N TS P E R F O R M A N C E A N D U S E R E X P E R I E N C E
  2. 2.

    D AV E Y S H A F I K

    • Author of Zend PHP 5 Certification Study Guide, O’Reillys Upgrading to PHP7, Sitepoints PHP Anthology: 101 Essential Tips, Tricks & Hacks & PHP Master: Write Cutting Edge Code • A contributor to Zend Framework 1 & 2, phpdoc, & PHP internals • Original creator of PHAR/ PHP_Archive • @dshafik
  3. 3.

    h tt p : / /d e v e l

    o p e r. a ka m a i .co m
  4. 5.

    W H Y P E R FO R M A

    N C E M AT T E RS CC-BY-ND 2.0: Raymond June
  5. 7.

    LO S E S 1 % O F R E

    V E N U E P E R 1 0 0 M S S O U R C E : H T T P : / / R A D A R . O R E I L LY. C O M / 2 0 0 8 / 0 8 / R A D A R - T H E M E - W E B - O P S . H T M L
  6. 8.

    £ 6 1 3 , 4 7 0 , 3

    3 6 2 0 1 4
  7. 9.

    8 P FO R E V E R Y S

    I N G L E P E RS O N O N E A RT H 2 0 1 4
  8. 10.

    £ 9 . 5 9 P E R U K

    C I T I Z E N 2 0 1 4
  9. 11.

    R E M I N D E R : P

    E R 1 0 0 M S S LO W E R !
  10. 13.

    0 . 5 S S LO W E R =

    2 0 % L E SS S E A R C H E S S O U R C E : H T T P : / / G L I N D E N . B L O G S P O T. C O M / 2 0 0 6 / 1 1 / M A R I S S A - M A Y E R - A T- W E B - 2 0 . H T M L
  11. 15.

    2 S S LO W E R = - 4

    . 3 % R E V E N U E / U S E R S O U R C E : H T T P : / / V E L O C I T Y C O N F. C O M / V E L O C I T Y 2 0 0 9 / P U B L I C / S C H E D U L E / D E TA I L / 8 5 2 3
  12. 17.

    CU T LOA D T I M E BY 8

    0 % : T R A F F I C + 8 0 % & T I M E S P E N T + 3 2 % S O U R C E : H T T P : / / D I G I D AY. CO M / P U B L I S H E RS /G Q - CO M - CU T- PA G E - LOA D -T I M E - 8 0 - P E R C E N T/
  13. 18.
  14. 19.

    • WALMART: 1s improvement = 2% increase in conversions •

    ETSY: +160KB of images mobile site = 12% increase in bounce rate • STAPLES: 1s improvement = 10% increase in conversions S O U R C E : H T T P : / / W W W. S L I D E S H A R E . N E T/C L I F FC R O C K E R / V E LO C I TY- N Y- H O W-TO - M E A S U R E - R E V E N U E - I N - M I L L I S E CO N D S S O U R C E : H T T P : / / R A D A R . O R E I L LY. CO M / 2 0 1 4 / 0 1 / W E B - P E R FO R M A N C E - I S - US E R- E X P E R I E N C E . H T M L S O U R C E : H T T P : / / W W W. S L I D E S H A R E . N E T/ D E VO N AU E RS W A L D/ W A L M A RT- PA G E S P E E D S L I D E
  15. 21.

    US E RS C A N P E R C

    E I V E T I N Y C H A N G E S I N P E R F O R M A N C E A S L I T T L E A S 1 0 0 M S
  16. 22.

    S LO W E R S I T E S

    M A K E CUSTO M E RS L E SS H A P P Y
  17. 23.

    L E SS H A P PY = P O

    O R US E R E X P E R I E N C E
  18. 24.

    YO U P R O B A B LY N

    OT I C E D I T YO U RS E L F…
  19. 25.

    1 0 S E CO N D S I S

    A N E T E R N I TY
  20. 26.

    W H O I S R E S P O

    N S I B L E FO R P E R FO R M A N C E ? CC-BY 2.0: davetoaster
  21. 27.
  22. 28.

    E V E R YO N E ! • Designers

    • Sysadmins/Devops • Backend Developers • Frontend Developers • Browser Vendors
  23. 29.

    W H AT M A K E S A W

    E B PA G E ? CC-BY-SA 2.0: Susanne Nilsson
  24. 30.

    TOTA L PA G E W E I G H

    T D I ST R I B U T I O N HTTP Archive – September 2015 http://httparchive.org/trends.php Fonts 5% CSS 3% JS 17% HTML 3% Images 63% Other 9%
  25. 31.

    TOTA L PA G E W E I G H

    T ( M B ) 0-1MB 1-2MB 2-3MB 3-4MB 4-5MB 5-6MB 6-8MB 3% 2% 4% 8% 15% 28% 36%
  26. 32.

    TOTA L R E Q U E STS P E

    R PA G E 1-25 26-50 51-75 76-100 101-125 126-150 > 150 15% 8% 12% 16% 18% 16% 11%
  27. 33.
  28. 34.
  29. 35.

    CO M P R E SS YO U R I

    M AG E S ( O R W E ’ L L D O I T FO R YO U ! )
  30. 36.

    SYS A D M I N S / D E

    V O P S CC-BY-SA 2.0: Bjorn Watland
  31. 38.

    L E T ’ S E N C R Y

    PT ! CC-BY: Jason Baker
  32. 39.

    L E TS E N C R Y PT. O

    R G Attribution
  33. 40.

    L E TS E N C R Y PT. O

    R G • Free (as in beer) • Automatic • Secure • Transparent • Open • Cooperative
  34. 41.

    U S E T H E C LO U D

    TO S C A L E B A S E D 
 O N P E R C E I V E D P E R F O R M A N C E CC-BY 2.0: Steve Jurvetson
  35. 42.

    S C A L E D B A S E

    D O N P E R C E I V E D P E R F O R M A N C E • Resource usage doesn’t tell you the whole story • Use SpeedIndex scores as an additional metric to determine scaling thresholds • Use marcelduran / webpagetest-api (node)
  36. 43.

    var WebPageTest = require('webpagetest'); var http = require('http'); var wpt

    = new WebPageTest('www.webpagetest.org', ‘KEY HERE'); wpt.runTest('https://daveyshafik.com', {pageSpeed: true}, function(err, data) { console.log("Test results at: " + data.data.jsonUrl); checkResponse(data.data.jsonUrl); }); function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = ''; response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData); if (data.statusCode == 200) { console.log("First view: " + data.data.average.firstView.SpeedIndex); console.log("Repeat view: " + data.data.average.repeatView.SpeedIndex); } else { console.log(data.statusText); setTimeout(function () { checkResponse(reportUrl); }, 5000); } }); }); }
  37. 44.

    var WebPageTest = require('webpagetest'); var http = require('http'); var wpt

    = new WebPageTest('www.webpagetest.org', ‘KEY HERE'); wpt.runTest('https://daveyshafik.com', {pageSpeed: true}, function(err, data) { console.log("Test results at: " + data.data.jsonUrl); checkResponse(data.data.jsonUrl); }); function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = ''; response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData);
  38. 45.

    var WebPageTest = require('webpagetest'); var http = require('http'); var wpt

    = new WebPageTest('www.webpagetest.org', ‘KEY HERE'); wpt.runTest('https://daveyshafik.com', {pageSpeed: true}, function(err, data) { console.log("Test results at: " + data.data.jsonUrl); checkResponse(data.data.jsonUrl); }); function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = ''; response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData);
  39. 46.

    var WebPageTest = require('webpagetest'); var http = require('http'); var wpt

    = new WebPageTest('www.webpagetest.org', ‘KEY HERE'); wpt.runTest('https://daveyshafik.com', {pageSpeed: true}, function(err, data) { console.log("Test results at: " + data.data.jsonUrl); checkResponse(data.data.jsonUrl); }); function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = ''; response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData);
  40. 47.

    var WebPageTest = require('webpagetest'); var http = require('http'); var wpt

    = new WebPageTest('www.webpagetest.org', ‘KEY HERE'); wpt.runTest('https://daveyshafik.com', {pageSpeed: true}, function(err, data) { console.log("Test results at: " + data.data.jsonUrl); checkResponse(data.data.jsonUrl); }); function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = ''; response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData);
  41. 48.

    function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = '';

    response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData); if (data.statusCode == 200) { console.log("First view: " + data.data.average.firstView.SpeedIndex); console.log("Repeat view: " + data.data.average.repeatView.SpeedIndex); } else { console.log(data.statusText); setTimeout(function () { checkResponse(reportUrl); }, 5000); } }); }); }
  42. 49.

    function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = '';

    response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData); if (data.statusCode == 200) { console.log("First view: " + data.data.average.firstView.SpeedIndex); console.log("Repeat view: " + data.data.average.repeatView.SpeedIndex); } else { console.log(data.statusText); setTimeout(function () { checkResponse(reportUrl); }, 5000); } }); }); }
  43. 50.

    function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = '';

    response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData); if (data.statusCode == 200) { console.log("First view: " + data.data.average.firstView.SpeedIndex); console.log("Repeat view: " + data.data.average.repeatView.SpeedIndex); } else { console.log(data.statusText); setTimeout(function () { checkResponse(reportUrl); }, 5000); } }); }); }
  44. 51.

    function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = '';

    response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData); if (data.statusCode == 200) { console.log("First view: " + data.data.average.firstView.SpeedIndex); console.log("Repeat view: " + data.data.average.repeatView.SpeedIndex); } else { console.log(data.statusText); setTimeout(function () { checkResponse(reportUrl); }, 5000); } }); }); }
  45. 52.

    function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = '';

    response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData); if (data.statusCode == 200) { console.log("First view: " + data.data.average.firstView.SpeedIndex); console.log("Repeat view: " + data.data.average.repeatView.SpeedIndex); } else { console.log(data.statusText); setTimeout(function () { checkResponse(reportUrl); }, 5000); } }); }); }
  46. 53.

    function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = '';

    response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData); if (data.statusCode == 200) { console.log("First view: " + data.data.average.firstView.SpeedIndex); console.log("Repeat view: " + data.data.average.repeatView.SpeedIndex); } else { console.log(data.statusText); setTimeout(function () { checkResponse(reportUrl); }, 5000); } }); }); }
  47. 54.

    function checkResponse(reportUrl) { http.get(reportUrl, function(response) { var responseData = '';

    response.on('data', function(data) { responseData += data; }); response.on('end', function() { var data = JSON.parse(responseData); if (data.statusCode == 200) { console.log("First view: " + data.data.average.firstView.SpeedIndex); console.log("Repeat view: " + data.data.average.repeatView.SpeedIndex); } else { console.log(data.statusText); setTimeout(function () { checkResponse(reportUrl); }, 5000); } }); }); }
  48. 55.
  49. 56.

    B A C K E N D D E V

    E LO P E RS CC-BY 2.0: Bobo Boom
  50. 57.

    C A C H E A G G R E

    S S I V E LY CC-BY: Travis Wise
  51. 59.

    D ATA B A S E C AC H I

    N G • Memcache • Cassandra
  52. 61.

    F U L L PA G E C A C

    H I N G • Memcache • Cassandra • Varnish • Squid
  53. 62.

    E D G E S I D E I N

    C LU D E S ( E S I )
  54. 63.

    E D G E S I D E I N

    C LU D E S • Created by Akamai (and some other companies) • Partially supported by Varnish, Squid, and others • Uses special HTML tags to cache fragments of pages differently than rest of the page • e.g. no caching, different TTL, per user session, or per geographic area
  55. 64.

    E X A M P L E E D G

    E S I D E I N C LU D E : LO G I N <esi:include src="view/esi/login.phtml"/> <esi:remove> <?php // ESI Fallback include('view/esi/login.fallback.phtml'); ?> </esi:remove>
  56. 65.

    E X A M P L E E D G

    E S I D E I N C LU D E : LO G I N <esi:include src="view/esi/login.phtml"/> <esi:remove> <?php // ESI Fallback include('view/esi/login.fallback.phtml'); ?> </esi:remove>
  57. 66.

    E X A M P L E E D G

    E S I D E I N C LU D E : LO G I N <esi:include src="view/esi/login.phtml"/> <esi:remove> <?php // ESI Fallback include('view/esi/login.fallback.phtml'); ?> </esi:remove>
  58. 67.

    E X A M P L E E D G

    E S I D E I N C LU D E : LO G I N <esi:include src="view/esi/login.phtml"/> <esi:remove> <?php // ESI Fallback include('view/esi/login.fallback.phtml'); ?> </esi:remove>
  59. 69.
  60. 70.
  61. 72.

    J P E G L E V E LS :

    0 - 1 0 0 T H E Y ’ R E W H AT E V E R T H E E N CO D E R W A N TS T H E M TO M E A N
  62. 73.
  63. 74.

    Q UA L I TY H U M A N

    S C A N S E E P E R C E I V E D Q UA L I TY
  64. 75.
  65. 76.
  66. 77.
  67. 89.

    0

  68. 90.

    SS I M S T R U CT U R

    A L S I M I L A R I TY I M AG E
  69. 91.

    E M M Y A W A R D W

    I N N I N G A LG O R I T H M Zhou Wang, Alan C. Bovik, Hamid R. Sheikh, and Eero P. Simoncelli
  70. 92.

    SS I M A LG O R I T H

    M • Brightness • Contrast • Structure • Fast
  71. 93.

    D SS I M ST R U CT U R

    A L D I SS I M I L A R I TY: D I STA N C E M E T R I C D E R I V E D F R O M SS I M
  72. 94.

    9 0 : 0 . 0 0 9 2 7

    3 5 . 8 M B
  73. 95.

    8 0 : 0 . 0 0 8 1 3

    6 4 . 2 M B
  74. 96.

    7 0 : 0 . 0 0 9 0 0

    7 3 . 2 M B
  75. 97.

    6 0 : 0 . 0 1 0 2 8

    7 2 . 5 M B
  76. 98.

    5 0 : 0 . 0 1 2 0 7

    8 1 . 9 M B
  77. 99.

    4 0 : 0 . 0 1 4 7 6

    8 1 . 4 M B
  78. 100.

    3 0 : 0 . 0 1 7 4 1

    3 1 . 2 M B
  79. 101.

    2 0 : 0 . 0 2 0 7 1

    2 9 4 8 K B
  80. 102.

    1 0 : 0 . 0 2 8 6 4

    2 5 9 2 K B
  81. 103.
  82. 104.

    0.009273 /images/90.png 0.008136 /images/80.png 0.009007 /images/70.png 0.010287 /images/60.png 0.012078 /images/50.png

    0.014768 /images/40.png 0.017413 /images/30.png 0.020712 /images/20.png 0.028642 /images/10.png 0.038585 /images/0.png
  83. 105.

    P E R C E PT I V E Q

    UA L I TY T H R E S H O L D
  84. 107.
  85. 108.

    F R O N T E N D D E

    V E LO P E RS CC-BY 2.0: Bill Jacobus
  86. 109.

    P R E D I CT I V E B

    R O W S I N G
  87. 111.

    P R E B R O W S I N

    G 1. DNS Prefetch 2. TCP Preconnect 3. Prefetch 4. Prerender
  88. 112.
  89. 113.

    D N S P R E F E TC H

    ɐ Ɇ ɂ 10.0.0.1 127.0.0.1
  90. 114.

    TC P P R E CO N N E CT

    ɐ Ɇ Ȑ ɂ 10.0.0.1 127.0.0.1
  91. 116.

    P R E R E N D E R ɐ

    Ɇ Ȑ  ɂ 10.0.0.1 127.0.0.1
  92. 127.

    W A R N I N G ! CC-BY 2.0:

    Robert Couse-Baker
  93. 128.

    1-25 26-50 51-75 76-100 101-125 126-150 > 150 15% 8%

    12% 16% 18% 16% 11% 0-1MB 1-2MB 2-3MB 3-4MB 4-5MB 5-6MB 6-8MB 3% 2% 4% 8% 15% 28% 36% Fonts 5% CSS 3% JS 17% HTML 3% Images 63% Other 9% YO U H AV E TO R E N D E R T H E E N T I R E PAG E !
  94. 130.
  95. 131.

    P R E LOA D V S P R E

    F E TC H • prefetch is an optional and low-priority fetch for a resource that might be used by a subsequent navigation • preload is a mandatory and high-priority fetch for a resource that is necessary for the current navigation • preload is typically sent as a header, rather than a <link> tag
  96. 132.

    L I N K H E A D E R

    Link: /resource; rel=preload
  97. 133.

    N E W A R C H I T E

    CT U R E S
  98. 134.

    H T T P/ 1 . X S U C

    K S CC-BY: Flóra Soós
  99. 135.

    H T T P/ 1 . X S U C

    K S • Minify + Concat JavaScript and CSS • Inlining small JavaScript and CSS • Using image sprites • Using data: URIs • Domain sharding
  100. 136.

    T H E S E T H I N G

    S A R E A L L " C L E V E R " H AC K S CC-BY: Matt Biddulph
  101. 137.

    M U LT I P L E X I N

    G CC-BY: Alosh Bennett C A N U S E O N E C O N N E C T I O N F O R P A R A L L E L R E Q U E S T S
  102. 138.
  103. 139.
  104. 143.
  105. 144.

    PAG E A SS E TS Ɇ Ȑ ɂ GET

    /index.html 200 OK text/html
  106. 145.

    PAG E A SS E TS Ɇ Ȑ ɂ GET

    /index.html 200 OK text/html critical-path.css critical-path.js logo.svg
  107. 146.

    PAG E A SS E TS Ɇ Ȑ ɂ GET

    /index.html 200 OK text/html critical-path.css critical-path.js logo.svg font.eot
  108. 147.

    PAG E A SS E TS Ɇ Ȑ ɂ GET

    /index.html 200 OK text/html critical-path.css critical-path.js logo.svg font.eot main.js
  109. 148.

    PAG E A SS E TS Ɇ Ȑ ɂ GET

    /index.html 200 OK text/html critical-path.css critical-path.js logo.svg font.eot main.js splash.jpg
  110. 149.

    PAG E A SS E TS Ɇ Ȑ ɂ GET

    /index.html 200 OK text/html critical-path.css critical-path.js logo.svg font.eot styles.css main.js splash.jpg
  111. 151.

    P E R F O R M A N C

    E M AT T E RS
  112. 153.

    T I M E = U S E R S

    AT I S FA CT I O N = M O N E Y
  113. 154.

    P E R F O R M A N C

    E = US E R E X P E R I E N C E
  114. 155.

    F E E D B AC K & Q U

    E ST I O N S Feedback: Twitter: Email: Slides: https://joind.in/ @dshafik dshafik@akamai.com http://daveyshafik.com/slides 16379