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

[Lonestar PHP] Fast, Not Furious: How to identi...

[Lonestar PHP] Fast, Not Furious: How to identify and fix slow code

There's a saying "hardware is cheaper than developers", but this only holds true if you treat your hardware with the respect it deserves.

Learn how to diagnose, confirm and fix bottlenecks in your application using new tools like XHProf and tried and true tools like xdebug.

Also, we'll take an in-depth look at apc (advanced PHP cache) and memcache; even if you know and use memcache, this one can probably teach you a thing or two.

Davey Shafik

June 30, 2012
Tweet

More Decks by Davey Shafik

Other Decks in Programming

Transcript

  1. •Engineer at Engine Yard for Orchestra.io PHP Platform as a

    Service (PaaS) •Author of Zend PHP 5 Certification Study Guide, Sitepoints PHP Anthology: 101 Essential Tips, Tricks & Hacks & PHP Master: Write Cutting Edge Code •A contributor to Zend Framework, phpdoc, FRAPI and PHP internals •@dshafik •(Buy My Books!) Davey Shafik 2
  2. About These Slides • Two slides per “slide” • Title

    Slide (for when I’m talking) • Details slide (for later) • Nobody likes it when you can read the slide just as well as the speaker can • I like slides that are useful 6
  3. Anecdote OR: why you shouldn’t randomly optimize — and why

    you should be careful with PHP 5.3’s memory garbage collection 9
  4. Common Causes of Slowdown 1. Datastore • Doesn’t matter if

    it’s PostgreSQL, MySQL, Oracle, MongoDB, CouchDB, or MSSQL 2. External Resources • APIs, Filesystems, Network Sockets, External Processes 3. Bad Code • The only great code, is code that never has to run. Everything else, is just good code. 11
  5. Do You Have a Problem? • The #1 issue with

    performance tuning, is assuming you even have a problem. • Premature Optimization is a waste of time. • Determine desired performance (e.g. 100 concurrent users with less than 1s response times). Benchmark on production hardware. Do you even have a problem? How big? 13
  6. Benchmarking Vs Profiling • Profiling Records Relative Speed + Memory

    Usage + # of calls per function + Call graph • The act of profiling affects the speed (the outcome) of the code (just like quantum physics!) • Benchmarking Tests Actual Speed • What your users actually see 17
  7. Grab the tarball: $ wget http://pecl.php.net/get/ xhprof-0.9.2.tgz $ tar –zxvf

    xhprof-0.9.2.tgz Change to the sub-directory: $ cd xhprof-0.9.2/extension Compile: $ ./configure --enable-xhprof $ make $ make install Installing xhprof 19
  8. Clone from git: $ git clone git://github.com/preinheimer/xhprof.git Setup the correct

    Database adapter: $ cd xhprof/xhprof_lib/utils $ rm xhprof_runs.php $ ln –s xhprof_runs_mysql.php xhprof_runs.php Installing xh-gui 21
  9. Create the Database: CREATE TABLE `details` ( `id` char(17) NOT

    NULL, `url` varchar(255) default NULL, `c_url` varchar(255) default NULL, `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `server name` varchar(64) default NULL, `perfdata` MEDIUMBLOB, `type` tinyint(4) default NULL, `cookie` BLOB, `post` BLOB, `get` BLOB, `pmu` int(11) default NULL, `wt` int(11) default NULL, `cpu` int(11) default NULL, `server_id` char(3) NOT NULL default 't11', `aggregateCalls_include` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `url` (`url`), KEY `c_url` (`c_url`), KEY `cpu` (`cpu`), KEY `wt` (`wt`), KEY `pmu` (`pmu`), KEY `timestamp` (`timestamp`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; Installing xh-gui 22
  10. Update the config: $ cd .. # back up to

    xhprof_lib $ cp config.sample.php config.php Change these: $_xhprof['dbhost'] = 'localhost'; $_xhprof['dbuser'] = 'username'; $_xhprof['dbpass'] = 'password'; $_xhprof['dbname'] = 'xhprof'; $_xhprof['servername'] = 'myserver'; $_xhprof['namespace'] = 'myapp'; $_xhprof['url'] = 'http://url/to/xhprof/xhprof_html'; Installing xh-gui 23
  11. Setup Httpd: Apache: <VirtualHost *:80> ServerName xh.dev DocumentRoot /path/to/xhprof/xhprof_html </VirtualHost>

    Nginx: server { listen 80 default_server; server_name xh.dev; root /path/to/xhprof/xhprof_html; index index.php; } Installing xh-gui 24
  12. Add prepend/append config to php.ini: auto_prepend_file = "/path/to/xhprof/external/header.php" auto_append_file =

    "/path/to/xhprof/external/footer.php" OR Apache VirtualHost: php_admin_value auto_prepend_file /path/to/xhprof/external/header.php php_admin_value auto_append_file /path/to/xhprof/external/footer.php Using xhprof/xh-gui 26
  13. function _urlSimilartor($url) { $url = preg_replace("/[0-9]+/", "XXX", $url); $qs =

    parse_url($url, PHP_URL_QUERY); if ($qs) { $parts = array(); parse_str($qs, $parts); $values = array_pad(array(), sizeof($parts), "XXX"); $normalized = array_combine(array_keys($parts), $values); $replace = http_build_query($normalized); $url = str_replace($qs, $replace, $url); } $url = preg_replace("![?&]_profile=\d!", "", $url); return $url; } URL Similartor 28
  14. Key-Value Stores • APC • memcache • Cassandra • redis

    • Most NoSQL implementations (CouchDB, MongoDB, MemBase) 31
  15. Namespace 1 Data Data Data Data Data Data Data Data

    Data Data Data Data Namespace 2 Data Data Data Data Data Data Data Data Data Data Data Data Memcache Namespaces 33
  16. Namespace 1 Data Data Data Data Data Data Data Data

    Data Data Data Data Namespace 2 Data Data Data Data Data Data Data Data Data Data Data Data Memcache Namespaces 33
  17. • Create a namespace key in memcache if there isn’t

    one • memcache_set('mynamespace', rand(1, 1000)); • Use the namespace name, value, and the items unique key to create a key • mynamespace_189_a1773d62a609dd09e98ea1aebeddbd94 • When you want to clear the cache, increment the namespace key • memcache_increment(‘mynamespace’); The Code 34
  18. Namespace 1 Namespace 1.1 Namespace 1.2 Namespace 1.3 Namespace 1.4

    Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Memcache Namespace Segmenting 35
  19. The Code • Create a segment key in memcache if

    there isn’t one • memcache_set('mynamespace_config', rand(1, 1000)); • Use the namespace name, value, segment name, value and the items unique key to create a key • mynamespace_189_config_4_a609dd09e98ea1aebeddbd94 • When you want to clear the segment cache, increment the segment key • memcache_increment('mynamespace_config'); 36
  20. example.org example.org_session example.org_public example.org_admin example.org_config Data Data Data Data Data

    Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Data Practical Cache Layout 37
  21. require_once 'Cache/Memcache.php'; $cache = new Cache_Memcache(); $key = $_SERVER['REQUEST_URI']; $data

    = $cache->get($key, 'blog-pages'); if ($data !== false) { echo $data; } else { ob_start(); // output all the data to the buffer … // Assign to $data and actually output $data = ob_get_flush(); // Cache it $cache->set($key, $data, 'blog-pages'); } Using The Code 38
  22. Other Memcache Tricks • Meta Key • json string containing:

    • Last modified date • # of slabs • Use date to send Last-Modified header and 304 Not Modified Status • Use # of slabs to split content across multiple keys if > 1MB in size 41
  23. Other Memcache Tricks Key: mynamespace_189_a1773d62a609dd09e98ea1aebeddbd94_meta { /* RFC 1123 */

    lastModified: "Fri, 29 Jun 2012 00:30:25 -0400", slabs: 2 } 42
  24. The Worst Hello World, Ever <?php class Greeting { public

    function sayHello($to) { echo "Hello $to"; } } $greeter = new Greeting(); $greeter->sayHello("World"); ?> 46
  25. Token Name Value Token Name Value T_OPEN_TAG <?php T_WHITESPACE T_CLASS

    class } T_WHITESPACE T_WHITESPACE T_STRING Greeting } T_WHITESPACE T_WHITESPACE { T_VARIABLE $greeter T_WHITESPACE T_WHITESPACE T_PUBLIC public = T_WHITESPACE T_WHITESPACE T_FUNCTION function T_NEW new T_WHITESPACE T_WHITESPACE T_STRING sayHello T_STRING Greeting ( ( T_VARIABLE $to ) ) ; T_WHITESPACE T_WHITESPACE { T_VARIABLE $greeter T_WHITESPACE T_OBJECT_OPERATOR -> T_ECHO echo T_STRING sayHello T_WHITESPACE ( " T_CONSTANT_ENCAPSED_STRING "World" T_ENCAPSED_AND_WHITESPACE Hello ) T_VARIABLE $to ; " T_WHITESPACE ; T_CLOSE_TAG ?> 47