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

Profiling PHP applications

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 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.

8e82eb7e128a14a16d642ae55227339b?s=128

Bastian Hofmann

February 01, 2015
Tweet

More Decks by Bastian Hofmann

Other Decks in Programming

Transcript

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

    PHP applications
  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. None
  14. None
  15. None
  16. None
  17. Questions? Ask

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

  19. None
  20. Why should you care?

  21. It is really important

  22. None
  23. None
  24. Every ms counts

  25. None
  26. None
  27. None
  28. So what is pagespeed?

  29. Server

  30. Your PHP application Request Response

  31. Your PHP application Request Response Load balancer

  32. Your PHP application Request Response Load balancer

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

  34. But there is more

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

  40. So what happens on your server is really important

  41. But the rest is as well

  42. Step 1

  43. Measuring

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

  52. http://www.soasta.com/

  53. https://www.librato.com

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

  55. None
  56. Resource Timing API http://www.w3.org/TR/resource-timing/

  57. None
  58. Getting it back to the server

  59. Tracking request

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

  61. logstash http://logstash.net/

  62. input filter output

  63. Very rich plugin system

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

    with timing information as query parameters
  65. Graphing it

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

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

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

    "/var/log/nginx/ access_log/monitoring-access.log" ]
 }
 }
  70. 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"]
 }
 }
  71. output { statsd { type => "pagespeed-access" exclude_tags => ["_grokparsefailure"]

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

  75. From within your PHP app

  76. DB queries

  77. HTTP calls

  78. Rendering time

  79. More fine grained metrics

  80. By pages

  81. By browser

  82. By country

  83. Logged in / out

  84. Heavy users

  85. Slow query logs

  86. Load balancers

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

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

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

    
 }
 mutate {
 type => "haproxy-http-log"
 gsub => [
 "server_name", "\.", "_",
 "client_ip", "\.", "_"
 ]
 }
 }
  90. 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}"
 ]
 }

  91. 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
  92. Define goals

  93. Step 2

  94. How to find out where the problems are

  95. Profiling

  96. None
  97. xdebug.profiler_enable_trigger = 1 http://url?XDEBUG_PROFILE

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

  99. None
  100. Use it locally on your dev machine

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

  102. Use it in production for a subset of requests

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

  104. None
  105. None
  106. None
  107. None
  108. php-meminfo https://github.com/BitOne/php-meminfo

  109. Symfony Debug Toolbar

  110. None
  111. None
  112. Extend it http://symfony.com/doc/current/cookbook/profiler/ data_collector.html

  113. None
  114. None
  115. None
  116. None
  117. None
  118. None
  119. Use it in production for a subset of requests

  120. https://qafoolabs.com/

  121. https://blackfire.io/

  122. http://newrelic.com/

  123. Step 3

  124. Fix it

  125. That's something you have to do

  126. None
  127. Keep up to date

  128. http://www.perfplanet.com/

  129. Some hints on better performance

  130. The obvious

  131. GZIP

  132. CDNs

  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. The not so well known

  144. SPDY/ HTTP2

  145. Minimize redirects

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

  147. Compress HTML

  148. Check YSlow, Pagespeed

  149. DNS prefetch

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

  151. Move logic to async workers

  152. The "crazy" stuff

  153. Varnish

  154. ESI

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

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

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

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

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

    id="placeholder"></div> <script>loadWidget('/aboutMe', function(w) { w.render({ replace : '#placeholder' }); })</script> Institution
  160. Cache ajax requests

  161. Flush content early

  162. Move logic to shutdown handlers

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

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

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

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

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

  168. Bigpipe

  169. None
  170. Profile Menu Header LeftColumn RightColumn

  171. None
  172. None
  173. None
  174. None
  175. Remember

  176. Speed matters

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