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.
Performance Tuning with    Zend Framework        Alan Seiden      August 23, 2011                        New York City    ...
Why a ZF Performance topic?• I’ve recently helped several clients with  performance of their ZF apps• Performance is impor...
What we’ll cover tonight• Question: Does ZF performance differ  from regular PHP performance?• Using ZF performance tools ...
ZF vs. regular PHP• ZF is PHP   – Framework is PHP   – Your app is PHP• But it’s more PHP code than your app would use if ...
Zend_Db query profiler• A good reason to use Zend_Db• Better than manual profiling because you  won’t miss any queries• Se...
Query profiling viewed in FirePHP
Profiling to a log file// a good place to put this profiling code is in the postDispatch() event of a front    controller ...
Log file results2011-08-18T11:34:06-04:00 DEBUG (7): 2 queries in 0.937705 secondsQueries:0 - "SELECT COUNT(1) AS "zend_pa...
Zend_Cache• Flexible caching component• Caches any kind of data: output from PHP  scripts, complete web pages, ACL objects...
Zend_Cache• Back-ends where cached data can be stored  –   Zend Server memory or disk cache  –   Disk (your choice of loca...
Zend_Cache configuration• Easiest way is in application.ini    – If you set up your app using Zend_Tool; front-endresource...
Caching tip for Zend_Db_Table• Do cache metadata (table/field definitions) if you  use Zend_Db_Table• Otherwise you will h...
Use an opcode/bytecode cache• Frameworks add classes and code to an app• PHP ordinarily must read/interpret/compile all  t...
ZF Performance Guidehttp://framework.zend.com/manual/en/performance.html• Covers several topics related to ZF performance•...
Class loading• The issues around class loading are given  special attention in the Performance Guide• In particular, the “...
Autoloader/require_once() issue• The good:   – ZF’s autoloader is deemed a well performing component       • Enabled in /p...
How to remove require_once()Official UNIX way% cd path/to/ZendFramework/library% find . -name *.php -not -wholename   */Lo...
Removing require_once() #2Using PHP// from http://pastebin.com/wHKJZ68echdir (‘mylocationlibraryZend);foreach(new Recursiv...
Keep an eye on the front end• Otherwise known as the “client” side• Includes .js, .css, images, and AJAX calls• Check it o...
HTTP requestsIn particular, beware if several AJAX calls must execute on page load(not shown here) in order for page to re...
Apache rewrite rule.htaccess usually looks like this:RewriteEngine OnRewriteCond %{REQUEST_FILENAME} -s [OR]RewriteCond %{...
Nonexistent filesRewriteEngine OnRewriteCond %{REQUEST_FILENAME} -s [OR]RewriteCond %{REQUEST_FILENAME} -l [OR]RewriteCond...
Solution• I haven’t found a perfect solution• To intercept normal “file not found” errors in Apache:   –   RewriteRule !.(...
404 Before/after new ruleBefore             After
Further learning• Attend the NYC Web Performance Meetup• Follow me at @alanseiden• Keep coming to our ZF meetup:  http://w...
New York City area Zend Framework Meetup                 http://www.meetup.com/ZendFramework-NYCmetro/                 Aff...
Upcoming SlideShare
Loading in …5
×

Performance tuning with zend framework

8,043 views

Published on

How to measure and optimize performance of applications that use Zend Framework 1.x. A talk presented at the New York City Zend Framework Meetup (http://www.meetup.com/ZendFramework-NYCmetro/) on August 23, 2011.

Published in: Technology

Performance tuning with zend framework

  1. 1. Performance Tuning with Zend Framework Alan Seiden August 23, 2011 New York City ZF Meetup
  2. 2. Why a ZF Performance topic?• I’ve recently helped several clients with performance of their ZF apps• Performance is important to everyone today
  3. 3. What we’ll cover tonight• Question: Does ZF performance differ from regular PHP performance?• Using ZF performance tools – Zend_Db_Profiler – Zend_Cache• Other ZF performance optimizations• Client side measurement and optimizations
  4. 4. ZF vs. regular PHP• ZF is PHP – Framework is PHP – Your app is PHP• But it’s more PHP code than your app would use if built from scratch – Meant to cover common use cases• With ZF’s MVC, each request goes through routing, dispatch• Each class contains redundant require_once() calls – Redundant if you use class autoloader (best performance) – Only in ZF 1.x. To be corrected in ZF 2.0
  5. 5. Zend_Db query profiler• A good reason to use Zend_Db• Better than manual profiling because you won’t miss any queries• See the actual SQL created by Zend_Db• One way: Firebug/FirePHP – In application.ini:resources.db.params.profiler.enabled = trueresources.db.params.profiler.class = "Zend_Db_Profiler_Firebug"
  6. 6. Query profiling viewed in FirePHP
  7. 7. Profiling to a log file// a good place to put this profiling code is in the postDispatch() event of a front controller plugin$db = Zend_Registry::get(db); // defined in bootstrap$profiler = $db->getProfiler();$totalTime = $profiler->getTotalElapsedSecs();$queryCount = $profiler->getTotalNumQueries();foreach ($profiler->getQueryProfiles() as $i=>$query) { $secs = $query->getElapsedSecs(); $msg = $i . - " . $query->getQuery() . "; $msg .= , Params: . implode(,, $query->getQueryParams()); $msg .= , Time: . number_format($secs, 6). seconds; $messages[] = $msg;}$log = $queryCount . queries in . number_format($totalTime, 6) . seconds . "n";$log .= "Queries:n";$log .= implode("n", $messages);$logger = Zend_Registry::get(‘logger’); // defined in bootstrap$logger->debug($log);
  8. 8. Log file results2011-08-18T11:34:06-04:00 DEBUG (7): 2 queries in 0.937705 secondsQueries:0 - "SELECT COUNT(1) AS "zend_paginator_row_count" FROM "SQHMSTP" LEFT JOIN "XUPMSTP" AS "UP1" ON QHAFSR = UP1.UPUID LEFT JOIN "XUPMSTP" AS "UP2" ON QHAUSR = UP2.UPUID INNER JOIN "XTVMSTP" AS "TV1" ON TV1.TVFLD = QHSTAT and TV1.TVCODE = QHSTAT INNER JOIN "XTVMSTP" AS "TV2" ON TV2.TVFLD = RPTTYP and TV2.TVCODE = QHTYPE WHERE (QHCOCD = 01)", Params: , Time: 0.820897 seconds1 - "SELECT "SQHMSTP"."QHCASE", "SQHMSTP"."QHCHAS", (QHADMM * 10000 + QHADDD * 100 + QHADYY) AS "QHADDT", "SQHMSTP"."QHTYPE", "SQHMSTP"."QHDLR", "SQHMSTP"."QHSTAT", "SQHMSTP"."QHRPRF", "SQHMSTP"."QHCREF", "SQHMSTP"."QHSTAT", CASE WHEN (QHSTAT = 20 OR (QHSTAT = 40 AND QHRPRF = )) THEN 1 ELSE 0 END AS "EDITABLE", CASE WHEN (QHSTAT = 20 OR QHSTAT = 40) THEN 1 ELSE 0 END AS "DELETABLE", "UP1"."UPNAME" AS "QHASSNAME", "UP2"."UPNAME" AS "QHAUSRNAME", "TV1"."TVDESC" AS "QHSTATDESC", "TV2"."TVDESC" AS "QHTYPEDESC" FROM "SQHMSTP" LEFT JOIN "XUPMSTP" AS "UP1" ON QHAFSR = UP1.UPUID LEFT JOIN "XUPMSTP" AS "UP2" ON QHAUSR = UP2.UPUID INNER JOIN "XTVMSTP" AS "TV1" ON TV1.TVFLD = QHSTAT and TV1.TVCODE = QHSTAT INNER JOIN "XTVMSTP" AS "TV2" ON TV2.TVFLD = RPTTYP and TV2.TVCODE = QHTYPE WHERE (QHCOCD = 01) ORDER BY "QHCASE" DESC FETCH FIRST 40 ROWS ONLY",Params: , Time: 0.116808 seconds
  9. 9. Zend_Cache• Flexible caching component• Caches any kind of data: output from PHP scripts, complete web pages, ACL objects, query results• Zend_Cache API stores cached data in your choice of “backends” (next slide)
  10. 10. Zend_Cache• Back-ends where cached data can be stored – Zend Server memory or disk cache – Disk (your choice of location) – Memcached – APC – SQLite – Xcache – Static (for generating static files for Apache to serve) – Two-tier fast/slow
  11. 11. Zend_Cache configuration• Easiest way is in application.ini – If you set up your app using Zend_Tool; front-endresources.cachemanager.database.frontend.name = Core; lifetime of 3600 means one hourresources.cachemanager.database.frontend.options.lifetime = 3600; automatic_serialization enables non-strings (objects) to be cachedresources.cachemanager.database.frontend.options.automatic_serialization = true; back-end; ZendServer_ShMem is Zend Server’s shared memory cacheresources.cachemanager.database.backend.name = "ZendServer_ShMem"resources.cachemanager.database.backend.customBackendNaming = true
  12. 12. Caching tip for Zend_Db_Table• Do cache metadata (table/field definitions) if you use Zend_Db_Table• Otherwise you will have a performance hit• The degree of performance penalty of always reading metadata depends on the database server• Play it safe and cache this metadata – Assuming tables/fields are relatively constant// in application.ini// (“database” cache was defined on previous slide)resources.db.defaultMetadataCache = "database"
  13. 13. Use an opcode/bytecode cache• Frameworks add classes and code to an app• PHP ordinarily must read/interpret/compile all that code on each request• A bytecode cache stores the “compiled” bytecode in memory after first execution, speeding subsequent runs• Examples of bytecode caches: – Zend Server’s Optimizer+ – APC – XCache – Windows Cache Extension for PHP
  14. 14. ZF Performance Guidehttp://framework.zend.com/manual/en/performance.html• Covers several topics related to ZF performance• Written by the ZF development team• Among its recommendations: – Avoid “action view helper”: invokes dispatch cycle • Replace with view helpers that query a model directly – “Use partial() only when really necessary” • Partial() clones the whole View object. Use render() if do not need a new, clean View object – And…
  15. 15. Class loading• The issues around class loading are given special attention in the Performance Guide• In particular, the “autoloader/require_once()” issue is the most frequently discussed performance “flaw” of ZF 1.x• It will be fixed in ZF 2.0• Details of 1.x “flaw” on next slide......
  16. 16. Autoloader/require_once() issue• The good: – ZF’s autoloader is deemed a well performing component • Enabled in /public/index.php like so: require_once Zend/Loader/Autoloader.php; Zend_Loader_Autoloader::getInstance();• The bad: – Even though autoloader loads classes as needed, each class executes require_once() statements at the top for each class it might need• Solution: remove require_once() statements from almost every ZF class – P.S. Matthew Weier O’Phinney says, “this will only improve speed if an opcode cache is used.”
  17. 17. How to remove require_once()Official UNIX way% cd path/to/ZendFramework/library% find . -name *.php -not -wholename */Loader/Autoloader.php -not -wholename */Application.php -print0 | xargs -0 sed --regexp- extended --in-place s/(require_once)/// 1/gDoesn’t remove it from Autoloader.php and Application.php because it’s needed there!
  18. 18. Removing require_once() #2Using PHP// from http://pastebin.com/wHKJZ68echdir (‘mylocationlibraryZend);foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(.)) as $o_File) { if ( .php === substr($o_File, -4) && false === strrpos($o_File, . . DIRECTORY_SEPARATOR . Loader . DIRECTORY_SEPARATOR . Autoloader.php) && false === strrpos($o_File, . . DIRECTORY_SEPARATOR . Application.php)) { $s_Code = preg_replace(/^(s*)(require_once)/im, 1// 2, file_get_contents($o_File), -1, $i_Replacements); if ($i_Replacements > 0) { echo $o_File, with , $i_Replacements, replacements., PHP_EOL; file_put_contents($o_File, $s_Code); } }}
  19. 19. Keep an eye on the front end• Otherwise known as the “client” side• Includes .js, .css, images, and AJAX calls• Check it out with Firebug’s “Net” panel or your favorite tool• Example coming up...
  20. 20. HTTP requestsIn particular, beware if several AJAX calls must execute on page load(not shown here) in order for page to render
  21. 21. Apache rewrite rule.htaccess usually looks like this:RewriteEngine OnRewriteCond %{REQUEST_FILENAME} -s [OR]RewriteCond %{REQUEST_FILENAME} -l [OR]RewriteCond %{REQUEST_FILENAME}RewriteRule ^.*$ – [NC,L]RewriteRule ^.*$ index.php [NC,L]• Any request that’s not a real file gets routed into ZF/PHP• What’s the performance flaw?
  22. 22. Nonexistent filesRewriteEngine OnRewriteCond %{REQUEST_FILENAME} -s [OR]RewriteCond %{REQUEST_FILENAME} -l [OR]RewriteCond %{REQUEST_FILENAME}RewriteRule ^.*$ – [NC,L]RewriteRule ^.*$ index.php [NC,L]• Nonexistent files (whether favicon.ico or my.hacker.getya) get routed to ZF, putting load on app server, before generating a 404 not found error• Shouldn’t the web server handle 404?
  23. 23. Solution• I haven’t found a perfect solution• To intercept normal “file not found” errors in Apache: – RewriteRule !.(js|ico|gif|jpg|png|css|html|txt|log)$ index.php• If I’m confident that app URLs shouldn’t have any periods/dots in ZF URLs: – RewriteRule !.([^.]+)$ index.php – ZF will only receive period-free URLs – Apache can then catch “weird” URLs such as “w00tw00t.at.ISC.SAN” (I found this in a customer’s Apache log)• Demonstration on next slide• Better idea? Send to alan@alanseiden.com
  24. 24. 404 Before/after new ruleBefore After
  25. 25. Further learning• Attend the NYC Web Performance Meetup• Follow me at @alanseiden• Keep coming to our ZF meetup: http://www.meetup.com/ZendFramework-NYCmetro/• Attend ZendCon, Oct. 17-20, 2011• Share your discoveries—you are welcome to present at the ZF Meetup
  26. 26. New York City area Zend Framework Meetup http://www.meetup.com/ZendFramework-NYCmetro/ Affiliated with http://www.nyphp.org/Thanks for attending Performance Tuning with Zend Frameworkpresented on Aug. 23, 2011 byAlan Seiden http://www.alanseiden.com alan@alanseiden.com Twitter: @alanseidenSign up to hear about all our ZF meetups athttp://www.meetup.com/ZendFramework-NYCmetro/

×