Upgrade to Pro — share decks privately, control downloads, hide ads and more …

My site is slow, what can I do? - Profiling PHP applications

My site is slow, what can I do? - Profiling PHP applications

It's nothing new that speed is important for the success of any web application. Only a few hundred milliseconds may lie between a user leaving your site or staying. Unfortunately performance problems are oftentimes hard to fix and even harder to pinpoint.
In this talk I will show you how we at ResearchGate measure web application performance, which means not only timing how long the PHP backend took to deliver a page, but also tracking the speed the users actually perceives in the browser. After that you will see how you can track down and analyze any problems you found through measuring with the help of tools like Xdebug, XHProf, the Qafoo Profiler and the Symfony Debug Toolbar. And if you still need to get faster after optimizing and fixing all these issues, I'll introduce you to some tricks, techniques and patterns to even further decrease load times.

Bastian Hofmann

June 27, 2015
Tweet

More Decks by Bastian Hofmann

Other Decks in Programming

Transcript

  1. My site is slow, what can I do? Profiling PHP

    @BastianHofmann
  2. This talk is all about...

  3. None
  4. Speed of your web application

  5. We'll talk about...

  6. Why it matters

  7. How to measure it

  8. How to find out where the problems are

  9. Before we start

  10. A few words about me

  11. None
  12. None
  13. Questions? Ask

  14. http://speakerdeck.com/u/bastianhofmann

  15. None
  16. None
  17. None
  18. Why should you care?

  19. It is really important

  20. None
  21. None
  22. Every ms counts

  23. None
  24. None
  25. None
  26. So what is pagespeed?

  27. Server

  28. Your PHP application Request Response

  29. Your PHP application Request Response Load balancer

  30. Your PHP application Request Response Load balancer

  31. web server db http service http service cache user request

  32. But there is more

  33. None
  34. None
  35. None
  36. None
  37. http://www.stevesouders.com/blog/2012/02/10/the-performance-golden-rule/

  38. So what happens on your server is really important

  39. But the rest is as well

  40. Step 1

  41. Measuring

  42. None
  43. None
  44. None
  45. None
  46. None
  47. None
  48. None
  49. So you need to measure at your users side

  50. Navigation Timing API https://developer.mozilla.org/en-US/docs/ Navigation_timing

  51. None
  52. Resource Timing API http://www.w3.org/TR/resource-timing/

  53. None
  54. For older browsers you have to do it yourself

  55. https://github.com/lognormal/boomerang

  56. None
  57. Getting it back to the server

  58. Tracking request

  59. https://tracking.example.com/? page=profile&backend=123&co mplete=890&domReady=580

  60. logstash http://logstash.net/

  61. input filter output

  62. Very rich plugin system

  63. browser JS: boomerang logstash trackingServer access log requests tracking image

    with timing information as query parameters
  64. Graphing it

  65. Graphite http://graphite.wikidot.com/

  66. None
  67. browser JS: boomerang logstash trackingServer access log requests tracking image

    with timing information as query parameters graphite statsd
  68. input {
 file {
 type => "pagespeed-access"
 path => [

    "/var/log/nginx/ access_log/monitoring-access.log" ]
 }
 }
  69. filter{
 grok {
 type => "pagespeed-access"
 pattern => "^.*\s\"[A-Z]+\s[^\?\s]+ \?page=%{DATA:page}\&connectTime=%

    {NUMBER:connectTime}...)?\sHTTP\/\d\.\d\".* $"
 }
 grok {
 type => "pagespeed-access"
 match => ["page", "^(profile| home|...)\.logged(In|Out)$"]
 exclude_tags => ["_grokparsefailure"]
 }
 }
  70. output { statsd { type => "pagespeed-access" exclude_tags => ["_grokparsefailure"]

    host => "localhost" port => 8126 namespace => "pagespeed" sender => "" timing => [ "%{page}.connect", "% {connectTime}", ... ] } }
  71. None
  72. Can we measure more?

  73. Load balancer

  74. input {
 file {
 type => "haproxy-http-log"
 path => [

    "/var/log/ haproxy-http.log*" ]
 }
 }
  75. filter {
 grok {
 type => "haproxy-http-log"
 pattern => "%{HAPROXYHTTP}"

    
 }
 mutate {
 type => "haproxy-http-log"
 gsub => [
 "server_name", "\.", "_",
 "client_ip", "\.", "_"
 ]
 }
 }
  76. output {
 statsd {
 type => "haproxy-http-log"
 exclude_tags => ["_grokparsefailure"]


    host => "localhost"
 port => 8125
 namespace => "lb"
 sender => ""
 increment => [
 "haproxy.%{backend_name}.%{server_name}.% {client_ip}.hits",
 "haproxy.%{backend_name}.%{server_name}.% {client_ip}.responses.%{http_status_code}"
 ]
 timing => [
 "haproxy.%{backend_name}.%{server_name}.% {client_ip}.time_request", "%{time_request}",
 "haproxy.%{backend_name}.%{server_name}.% {client_ip}.time_backend_connect", "%{time_backend_connect}",
 "haproxy.%{backend_name}.%{server_name}.% {client_ip}.time_backend_response", "%{time_backend_response}",
 "haproxy.%{backend_name}.%{server_name}.% {client_ip}.time_queue", "%{time_queue}",
 "haproxy.%{backend_name}.%{server_name}.% {client_ip}.time_duration", "%{time_duration}"
 ]
 }

  77. browser JS: boomerang logstash trackingServer access log requests tracking image

    with timing information as query parameters graphite statsd logstash load balancer access log logstash service access log
  78. From within your PHP app

  79. From your JS frontend

  80. Slow query logs

  81. More fine grained metrics

  82. By pages

  83. By browser

  84. By country

  85. Logged in / out

  86. Heavy users

  87. Define goals

  88. Anomaly detection

  89. http://codeascraft.com/2013/06/11/introducing-kale/

  90. Step 2

  91. How to find out where the problems are

  92. Profiling

  93. None
  94. xdebug.profiler_enable_trigger = 1 http://url?XDEBUG_PROFILE

  95. Webgrind https://github.com/jokkedk/webgrind

  96. None
  97. Use it locally on your dev machine

  98. XHProf https://github.com/facebook/xhprof

  99. Use it in production for a subset of requests

  100. XHGUI https://github.com/perftools/xhgui

  101. None
  102. None
  103. None
  104. None
  105. php-meminfo https://github.com/BitOne/php-meminfo

  106. Blackfire https://blackfire.io/

  107. Tideways https://tidyways.io/

  108. None
  109. None
  110. New Relic http://newrelic.com/

  111. None
  112. Symfony Debug Toolbar

  113. None
  114. None
  115. Extend it http://symfony.com/doc/current/cookbook/profiler/ data_collector.html

  116. None
  117. None
  118. None
  119. None
  120. None
  121. None
  122. Aggregate it

  123. None
  124. Step 3

  125. Fix it

  126. That's something you have to do

  127. None
  128. Some hints on better performance

  129. GZIP

  130. CDNs

  131. DNS provider

  132. Test them

  133. DB Indexes

  134. Minify JS https://github.com/mishoo/UglifyJS

  135. Minify CSS http://sass-lang.com/

  136. Concatenate JS/ CSS/...

  137. Correct caching headers

  138. Opcache

  139. Data Caching

  140. APCU

  141. memcached

  142. PHP 5.6 https://blog.asmallorange.com/2013/08/php-roadmap- performance/

  143. Are you using your libraries correctly?

  144. Symfony

  145. Doctrine

  146. DI container

  147. SPDY/HTTP 2.0

  148. Minimize redirects

  149. Check image compression https://github.com/gruntjs/grunt-contrib-imagemin

  150. Compress HTML

  151. Check YSlow, Pagespeed

  152. DNS prefetch

  153. <link  rel="dns-­‐prefetch"     href="//host_name_to_prefetch.com">

  154. <link  rel="preload"     href="//host_name_to_prefetch.com">

  155. Move logic to async workers

  156. Precompute expensive stuff

  157. Varnish

  158. ESI

  159. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu Institution

  160. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu <esi:include

    src="..." /> Institution
  161. Load content asynchronously

  162. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu Institution

  163. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu <div

    id="placeholder"></div> <script>loadWidget('/aboutMe', function(w) { w.render({ replace : '#placeholder' }); })</script> Institution
  164. Flush content early

  165. Move logic to shutdown handlers

  166. http://www.php.net/manual/en/function.register-shutdown- function.php

  167. http://www.php.net/manual/en/function.fastcgi-finish- request.php

  168. Promises / Futures https://github.com/facebook/libphutil

  169. $future  =  new  HTTPFuture(       'http://www.example.com/'   );

      list($status,  $body,  $headers)  =       $future-­‐>resolve();
  170. pushState

  171. Bigpipe

  172. None
  173. Profile Menu Header LeftColumn RightColumn

  174. None
  175. None
  176. None
  177. None
  178. Generate code

  179. TSL early termination

  180. Keep up to date

  181. http://www.perfplanet.com/

  182. Regardless of what you do: Measure it

  183. Remember

  184. Speed matters

  185. https://joind.in/14255

  186. http://twitter.com/BastianHofmann http://lanyrd.com/people/BastianHofmann http://speakerdeck.com/u/bastianhofmann mail@bastianhofmann.de