This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Strip your binaries Performance Tuning PHP 2005-05-29 4
Eliminate waste by removing symbols from object files using strip utility.
Saves disk space and more importantly memory needed to load the library or run the binary. In case of PHP makes the binary or Apache library 20-30% smaller.
PHP configuration directives can have significant impact on performance of PHP applications.
● • Make sure that register_globals is disabled (default since 4.2.0)● • Disable magic_quotes_* directives.
● • make sure your applications will escape input when necessary● • Turn off expose_php● • Turn off register_argc_argv for non-cli SAPIs● • Unless absolutely necessary do not enable always_populate_raw_post_data
Since the webserver plays an important part in the request serving process, it is important to tune it. A big part of this is the Apache child creation process.
● • StartServers set to avg. # of requests you'd expect.● • MaxSpareServers keep this number high, to allow Apache to gracefully handle
traffic spikes.● • MaxClients keep this number at about 2/5 of the maximum processes your server
can handle.● • MaxRequestsPerChild ideally unlimited (0), but practically should be limited to
Reducing File IO● • Keep DirectoryIndex file list as short as possible.● • Whenever possible disable .htaccess via AllowOverride none● • Use Options FollowSymLinks to simplify file access process
in Apache● • Avoid using mod_rewrite or at least complex regexs● • If logs are unnecessary disable them.● • If logging is a must, log everything to 1 file, and break it up during
Lingerd is a daemon (service) designed to take over the job of properly closing network connections from an http server like Apache.
Because of some technical complications in the way TCP/IP and HTTP work, each Apache process currently wastes a lot of time "lingering" on client connections, after the page has been generated and sent. Lingerd takes over this job, leaving the Apache process immediately free to handle a new connection. As a result, Lingerd makes it possible to serve the same load using considerably fewer Apache processes.
Warning: will only work (properly) if KeepAlive is disabled.
Virtually any webpage is the combination of dynamic (php) and static content (images, CSS, JavaScript, etc...)
For maximum performance it is best to separate the serving of dynamic and static content.
Benefits● • Ability to disable KeepAlive for server handling dynamic data.● • Simpler and Faster serving numerous static requests.● • Allow more complex configuration (.htaccess, mod_rewrite) for dynamic data
without affecting static content● • Easy distribution of the content serving load across servers.
The first step in the script execution is the conversion of said script into a series instructions (opcodes), which the Zend Engine can understand and run.
Since scripts rarely change, an obvious optimization is to cache the opcodes so that the scripts do not need to be parsed every time.
Often enough output of PHP scripts can remain static for an extended period of time. In these cases, certain actions can be eliminated, resulting in a faster script execution.
Pre-generationWhen the content changes, generate static versions of the affected pages, taking PHP out of the equation completely.
On demandSame as pre-generation, only the content is not generated until the 1st request for the specified content arrives.
Content Caching in PHP Performance Tuning PHP 2005-05-29 20
<?phpfunction cache_start(){ global $cache_file_name, $age;
// a superbly creative way for creating cache files $cache_file_name = __FILE__ . '_cache';
// default cache age if (empty($age)) $age = 600;
// check if cache exists and if the cached data is still valid if (@filemtime($cache_file_name) + $age > time()) { // Yey! cache hit, output cached data and exit readfile($cache_file_name); unset($cache_file_name); exit; }
// nothing in cache or cache is too old ob_start();}
function cache_end()http://talks.php.net/show/perf_tunning/20 (1 of 2) [5/29/2005 3:49:25 PM]
// nothing to do if (empty($cache_file_name)) return;
// fetch output of the script $str = ob_get_clean();
// output data to the user, so they don't need to wait // for the cache writing to complete echo $str; // write to cache fwrite(fopen($cache_file_name.'_tmp', "w"), $str); // atomic write rename($cache_file_name.'_tmp', $cache_file_name);}
cache_start();
// set cache termination code as the exit handler// this way we don't need to modify the scriptregister_shutdown_function("cache_end");?>
http://talks.php.net/show/perf_tunning/20 (2 of 2) [5/29/2005 3:49:25 PM]
Performance Tuning PHP
Content Caching in PHP Cont. Performance Tuning PHP 2005-05-29 21
<?php require "./cache.php"; // our cache code
// Simple guestbook script. $db = new sqlite_db("gb.sqlite"); $r = $db->array_query("SELECT * FROM guestbook", SQLITE_ASSOC); foreach ($r as $row) { echo $r->user . ' wrote on ' . date("Ymd", $r->date) . ":<br />\n"; echo $r->message . "<hr /><hr />"; }?>
Implementing cache without modifying the script
# Add to .htaccessphp_value auto_prepend_file "/path/to/cache.php"
# Or to virtual host entry in httpd.confphp_admin_value auto_prepend_file "/path/to/cache.php"
I'd like to use caching, but my content is completely dynamic and cannot be time delayed.
LIES! LIES! LIES!
Even the most dynamic pages, often have static elements generated by PHP. Partial caching can accelerate the page generation by caching the static portions of otherwise dynamic pages.
Partial Caching in Action Performance Tuning PHP 2005-05-29 25
<?php// Authenticates a user and stores their id inside $uidrequire "./user_auth.inc.php";
function header(){ if ($uid) echo "Welcome {$GLOBALS['user_nick']}"; echo rest_of_header();}
function footer(){ if ($uid) echo "Logout: <a href='/logout.php'>{$GLOBALS['user_nick']}</a>"; echo rest_of_footer();}
// cache the output of the header function// we append $uid to they key to ensure each user has their own// non conflicting entry.mmcache_cache_output(__FILE__ . $uid, 'header();', 60 * 24); // rest of the dynamic page
http://talks.php.net/show/perf_tunning/25 (1 of 2) [5/29/2005 3:49:35 PM]
Another way to reduce content, is to replace bulky legacy HTML elements with CSS.
Advantages● • 20-30% smaller pages.● • CSS can be moved to static files and be served independently.● • In some cases makes the browser render page faster.● • More flexible layout.
Disadvantages● • Can be A LOT of manual labor.● • Older browsers (Netscape 4.0) do not support CSS.● • Some CSS is rendered differently or is unsupported all together.
HTML contains a large quantity of useless data such as whitespace, comments etc... that is normally used to make the output readable to the developers.
In production no one other then the browser will be reading the HTML we can use the tidy extension to strip all the unnecessary bits.
Advantages● • 10-30% smaller pages.● • While compressing HTML can fix HTML bugs.
Disadvantages● • Requires Tidy extension.● • CPU costs make this useful only if the output is cached.
Most PHP scripts perform File IO operations, whether it be inclusion of scripts or opening or writing to files. One common mistake made by developers often makes these operations much slower then necessary.
Common element of various PHP scripts are sessions.
Generic Session Optimizations● • Don't use session.auto_start.● • Do not enable session.use_trans_sid● • Whenever possible set session.cache_limiter to private_no_expire
● • Assign each user (vhost) it's own sessions directory.● • For large sites consider using session.save_path = "N;/path"● • If possible avoid automatic garbage collection.
Extra |+----------+-------+---------------+-------+---------+------+------+------------+| mm_users | range | login | login | 50 | NULL | 2 | where used |+----------+-------+---------------+-------+---------+------+------+------------+
http://talks.php.net/show/perf_tunning/38 (2 of 2) [5/29/2005 3:50:02 PM]
// Faster MySQL/SQLite Specific approach$query = "INSERT INTO foo VALUES";$query = "(" . implode("),(", array_keys(array_fill(0, 10, 1))) . ")";// INSERT INTO foo VALUES (0), (1), (2) ...mysql_query($query);
// Query Chaining// for DBs that support it PostgreSQL, MSSQL, SQLite, MySQL 4.0+$query = '';for ($i = 0; $i < 10; $i++) $query .= "INSERT INTO foo VALUES({$i});";mysql_query($query);
http://talks.php.net/show/perf_tunning/39 (1 of 2) [5/29/2005 3:50:04 PM]
To ensure data integrity in certain situations you will need to use locks. However, overuse of locks or improper implementation can severely hinder the performance of your application.
● • If supported, whenever possible use row level locks instead of table locks.● • When using table locks, try to lock as few tables as possible.● • Whenever possible avoid locks all together.
Usage of joins allows simplification & acceleration of the script by moving portions of the logic to the database engine.
<?php// slow joinless approach$a = sqlite_fetch_single($db, "SELECT id FROM foo WHERE name='ilia'");$b = sqlite_array_query($db, "SELECT * FROM bar WHERE id={$a}");
// Fast Join implementation$b = sqlite_array_query($db, "SELECT b.* FROM foo f INNER JOIN bar b ON f.id=b.id WHERE f.name='ilia'");?>
Join Gotchas● • Unoptimized joins can be VERY slow.● • Internal (read) lock on all tables involved.
Temporary tables are memory buffers that can be used as in between steps for data retrieval, to avoid complex (and slow) PHP logic.
<?php// Quickly fetch the ids of needed messagesmysql_query("CREATE TEMPORARY TABLE mtmp AS SELECT id FROM msg WHERE thread_id={$_GET['th']} AND apr=1 ORDER BY id ASC LIMIT {$count}, {$_GET['start']}");
// Retrieve needed data by using the temporary table as base$result = mysql_query("SELECT * FROM mtmp mt INNER JOIN msg m ON m.id=mt.id INNER JOIN thread t ON m.thread_id=t.id INNER JOIN forum f ON t.forum_id=f.id LEFT JOIN users u ON m.poster_id=u.id LEFT JOIN level l ON u.level_id=l.id LEFT JOIN poll p ON m.poll_id=p.id LEFT JOIN poll_opt_track pot ON pot.poll_id=p.id
http://talks.php.net/show/perf_tunning/44 (1 of 2) [5/29/2005 3:50:15 PM]
In some situations, regular expressions would take too long to replace. Now you need to decide which regular expression implementation you want ereg or PCRE.
● • PCRE● • Much faster in most cases.● • UTF-8 support.● • Significantly greater functionality.
● • ereg● • Always available.● • Can operate on multi-byte strings w/mbstring extension.
Type conversion prevents things like SQL injection due to unexpected input. It also optimizes the application by providing PHP with a type it expects, rather having to internally perform type conversions each time the variable is used.