Tizag.com Webmaster Tutorials - A collection of webmaster tutorials from HTML to PHP.

Saturday, November 12, 2011

Make PHP apps fast, faster, fastest

Part 1: Boost performance, throughput with opcode cache software


In a short time, PHP has become a popular programming language for Web applications. For the beginner, PHP is simple to install and easy to learn. For the more experienced developer, it (as of V5) offers robust object-oriented features. The community of PHP developers is enormous, and a significant number of open source and commercial libraries and tools extend the capabilities of the core language. PHP is favored by so many because it produces visible results rapidly.

Much like other scripting languages used for Web applications, including Perl, Python, and Ruby, PHP code is parsed, translated to opcodes (primitive instructions -- akin to assembly language -- that the PHP engine executes directly), and executed each and every time an HTTP request summons it. For negligible and low demand, your server executes this complex rendering process seemingly instantly. But as the number of pages served increases, interpretation -- in essence, rework -- can tax the system. In some cases, the "compilation" of your PHP code can far exceed the time required to execute the code. Hence, as demand grows, you can readily become a victim of your own success, as serving more dynamically interpreted, dynamically generated pages requires more and more resources.

If your site had an unlimited budget for processors and RAM, you'd likely never have to optimize your application stack (hardware, operating system, database, Web server, and PHP code) to keep your site responsive. However, because money is typically the scarcest of resources, tweaking for performance is inevitable. Tuning might mean adding memory to a starved system, modifying operating system parameters, hastening the Web or database server, rewriting code for efficiency, or some combination thereof. Each can contribute to gains.

Don't burn cycles -- Recycle

Yet another way to conserve CPU cycles is simply to reduce the amount of rework required to run your PHP application. Certainly, there is no need to translate the same PHP code each time. After your PHP code has been translated into opcodes, it can be saved and reused again and again -- until the original code is modified. Indeed, caching -- saving and reusing the intermediate PHP code, the opcodes -- is the idea behind several PHP accelerators, including the open source Alternative PHP Cache (APC), Turck MMCache for PHP, XCache, eAccelerator, and the commercial Zend Platform. The latter three cache and optimize the byte code, providing for even greater speedups.

This month, let's explore how to install, deploy, and configure XCache. XCache is a relative newcomer, but many sites are reporting good results with it. In addition, it is easy to build, install, and configure because it's implemented as a PHP extension. Recompiling Apache and PHP isn't required.

This article is based on XCache V1.2.0. It reliably supports PHP V4.3.11 to V4.4.4, PHP V5.1.x to V5.2.x, and early versions of PHP V6. (XCache doesn't support PHP V5.0.x.) XCache works with mod_php and FastCGI, but not with the Common Gateway Interface (CGI) or the command-line PHP interpreter. The XCache source code builds on a variety of systems, including FreeBSD, Sun Solaris, Linux®, and (as shown here) on Mac OS X. XCache can be built on Microsoft® Windows®, as well, using the Cygwin UNIX® emulation environment or Visual C. You can build XCache for Cygwin or for native Win32. The latter target is compatible with the official Win32 release of PHP.

The demonstrations shown here are based on Apache V2.2.3, PHP V5.2.0, XCache V1.2.0 (released 10 Dec 2006), and Xcode V2.4.1 on Mac OS X V10.4.8 Tiger. The hardware platform is an Apple MacBook with a 2-GHz Intel® Core Duo and 2 GB of RAM.

Step-by-step instructions for building XCache

Before you continue, ensure that your installation of PHP works as is and verify that phpize is in your shell's PATH. You should also have a C compiler, such as the GNU Compiler Collection (GCC), and a suite of development tools that includes make andm4. On Mac OS X, the free Xcode software development environment provides the necessary build tools.

Complete the instructions below to build, deploy, and benchmark XCache on Mac OS X. Builds on other platforms are similar. If you use Linux, your distribution may already include XCache or may make it available to you in a prepackaged form.

Increase Mac OS X's shared memory

Begin by increasing the amount of shared memory set aside on Mac OS X. To do so, create (or edit) the file /etc/sysctl.conf and create the following entries:


Listing 1. Increase amount of shared memory set aside on Mac OS X
                 kern.sysv.shmmax=33554432 kern.sysv.shmmin=1 kern.sysv.shmmni=32 kern.sysv.shmseg=8 kern.sysv.shmall=8192 

These settings increase the amount of shared memory to 32 MB. If you find that you need to expand shared memory further, setkern.sysv.shmall to the value of kern.sysv.shmmax divided by the hardware page size, which you can find using sysctl hw.pagesize. For example, if you want 128 MB of shared memory, set kern.sysv.shmmax=134217728 and setkern.sysv.shmall=32768.

To realize your modifications, restart Mac OS X. When rebooted, verify that the new settings took effect by typing:

sysctl -a | grep kern.sysv 

Build XCache from source

Next, build XCache from source code. Download the source from http://xcache.lighttpd.net. When you have the code, unpack it, and change to the new directory that the .tar file creates.


Listing 2. Build XCache from source
                 $ cd /tmp $ wget http://210.51.190.228/pub/XCache/Releases/xcache-1.2.0.tar.gz $ tar xzf xcache-1.2.0.tar.gz $ cd xcache 

Run phpize to prepare XCache for compilation.


Listing 3. Run phpize
                 $ phpize Configuring for: PHP Api Version:         20020918 Zend Module Api No:      20020429 Zend Extension Api No:   20050606 

Run configure to create a makefile appropriate for the native operating system.


Listing 4. Run configure to create a makefile
                 $ ./configure --enable-xcache --enable-xcache-coverager  checking build system type... i686-apple-darwin8.8.1 checking host system type... i686-apple-darwin8.8.1 ... creating libtool configure: creating ./config.status config.status: creating config.h 

Here, the --enable-xcache option includes XCache support, and --enable-xcache-coverager includes an additional feature to measure the efficacy of the accelerator. To enable the opcode optimizer, add --enable-xcache-optimizer.

Of course, the next step is to build and install the code using the make command. Run make, then run make install as root.


Listing 5. Build and install the code using make
                 $ make ... cp ./xcache.so /Users/strike/tmp/xcache/modules/xcache.so Build complete.  $ sudo make install Installing shared extensions: /usr/lib/php/extensions/no-debug-non-zts-20020429/ 

If the previous two actions go smoothly, you should now have XCache in /usr/lib/php/extensions/no-debug-non-zts-20020429/xcache.so. (The path /usr/lib/php/extensions/no-debug-non-zts-20020429 reflects the version of the API in use and the compilation options used to build PHP. If you enabled the experimental Zend Thread Safety feature, "no-debug" could be "debug," and "non-zts" could be "zts.")

Alter the php.ini file

Now that the extension is installed, you must alter your php.ini file to include and configure the XCache extension. Open /private/etc/php.ini and add the following lines to the file.


Listing 6. Alter php.ini for the XCache extension
                 [xcache-common] zend_extension      = /usr/lib/php/extensions/no-debug-non-zts-20020429/xcache.so  [xcache.admin] ; Change xcache.admin.user to your preferred login name  xcache.admin.user   = "admin"  ; Change xcache.admin.pass to the MD5 fingerprint of your password ; Use md5 -s "your_secret_password" to find the fingerprint xcache.admin.pass   = "0ad72f3f352fcd8acdf266bafd0ac48d"  [xcache] ; Change xcache.size to tune the size of the opcode cache xcache.size         = 24M xcache.shm_scheme   = "mmap" xcache.count        = 2 xcache.slots        = 8K xcache.ttl          = 0 xcache.gc_interval  = 0  ; Change xcache.var_size to adjust the size of variable cache xcache.var_size     = 8M xcache.var_count    = 1 xcache.var_slots    = 8K xcache.var_ttl      = 0 xcache.var_maxttl   = 0 xcache.var_gc_interval =     300 xcache.test         = Off xcache.readonly_protection = On xcache.mmap_path    = "/tmp/xcache" xcache.coredump_directory =   "" xcache.cacher       = On xcache.stat         = On xcache.optimizer    = Off  [xcache.coverager] xcache.coverager    = On xcache.coveragedump_directory = "" 

Note: Some comments have been elided for brevity. To learn what each parameter controls, see the sample settings in the xcache.ini file included with the XCache source code.

The size of the opcode and variable cache is 32 MB, the maximum set aside in /etc/rc. For Mac OS X, xcache.mmap_path must be a file name. And because the PHP code is going to run on a MacBook, xcache.count is set to 2, the number of CPUs in the MacBook. To access the XCache statistics page, you must change the xcache.admin.pass setting. Run:

$ md5 -s "password" 

where password is your password. Copy the output to xcache.admin.pass. For example, if you want your password to beop3nsesam3, run:

$ md5 -s "op3nsesam3" MD5 ("op3nsesam3") = cd959ac3debe8f587546a3fa353b3268 

and copy cd959ac3debe8f587546a3fa353b3268 to xcache.admin.pass.

Restart the Web server

With your XCache settings in place, restart your Apache Web server. On most systems, you can use apachectl restart asroot.

$ sudo apachectl restart /usr/sbin/apachectl restart: httpd restarted 

Create a program to call phpinfo()

To verify that XCache is enabled, create a small PHP program to call phpinfo() and open that file in your Web browser. You should see an XCache section like the one shown below.


Figure 1. phpinfo() method summarizes the XCache settings
The phpinfo() method summarizes the XCache settings

Monitor XCache

To monitor XCache, install the administration pages found in the admin directory of the XCache source code. Copy the entire admin directory to your Apache document root. On Mac OS X, the document root is typically /Library/WebServer/Documents.

$ cp -pr admin /Library/WebServer/Documents 

When the copy is complete, restart the Web server with sudo apachectl restart. To verify that the administration panel works, point your browser to http://localhost/admin. You should see a dashboard similar to Figure 2.


Figure 2. The XCache Administration dashboard
The XCache Administration dashboard

Test an application

Choose an application or two to test. You can use your own code or, if you want something more complex, try a large PHP application, such as phpMyAdmin or Serendipity.

Running a benchmark

The Apache HTTP Web server ships with a utility named ab, short for Apache HTTP server benchmarking tool. Use ab to automate a large number of requests for PHP pages. The phpMyAdmin application is a good candidate because it's probably already installed on your system.

The ab utility is simple to use: Provide a repeat count and a URL. The ab utility requests that URL many times over and returns statistics. Because XCache is already enabled, the first benchmark will show performance with acceleration.

Before you run ab, point your browser to http://localhost/phpmyadmin/. Visiting this page once loads all the PHP code used to render the page into the cache. Now, run the benchmark shown below, iterating 100,000 times.


Listing 7. Benchmark for phpMyAdmin
                 $ ab -n 100000 http://localhost/phpmyadmin ... Concurrency Level:      1 Time taken for tests:   14.597 seconds Complete requests:      100000 Failed requests:        98262    (Connect: 49131, Length: 49131, Exceptions: 0) Broken pipe errors:     0 Non-2xx responses:      50869 Total transferred:      25739714 bytes HTML transferred:       12005084 bytes Requests per second:    6850.72 [#/sec] (mean) Time per request:       0.15 [ms] (mean) Time per request:       0.15 [ms] (mean, across all concurrent requests) Transfer rate:          1763.36 [Kbytes/sec] received 

The statistics of interest are requests per second and the total time to complete all the tests. For the former, a higher value is better; for the latter, lower is better.

Now, disable XCache in your php.ini file and run the benchmark again, as shown in Listing 8. You can comment out the reference to the XCache extension or turn all the XCache features off. Restart Apache before you run the benchmark again.


Listing 8. Benchmark for phpMyAdmin with XCache disabled
                 $ sudo apachectl restart $ ab -n 100000 http://localhost/phpmyadmin Concurrency Level:      1 Time taken for tests:   17.771 seconds Complete requests:      100000 Failed requests:        98256    (Connect: 49128, Length: 49128, Exceptions: 0) Broken pipe errors:     0 Non-2xx responses:      50872 Total transferred:      25741232 bytes HTML transferred:       12005792 bytes Requests per second:    5627.15 [#/sec] (mean) Time per request:       0.18 [ms] (mean) Time per request:       0.18 [ms] (mean, across all concurrent requests) Transfer rate:          1448.50 [Kbytes/sec] received 

Here, with XCache disabled, the number of requests per second fell, reflecting that the Apache server took longer for each request. The time to run the entire suite of tests climbed, as well.

Although this is a simple benchmark -- the phpMyAdmin connection to the database could have been disabled to limit processing time to interpreting PHP alone -- and not highly scientific, it does demonstrate what you can achieve with XCache. For a tiny investment (and, thankfully, no need to recompile PHP or Apache), XCache can yield a relatively large return. The more complex your code, the greater the possible benefits.

If you're curious to see how well XCache is working, visit http://localhost/xadmin and click List PHP. You should see a list of PHP files in the cache, along with cache hits, the size of the code as measured in opcodes, the size of the source file measured in bytes, and more. Figure 3 shows some results taken when XCache was built specifically for the XAMPP stack package.


Figure 3. XCache administration page reflects state and contents of cache
XCache administration page reflects state and contents of cache

As mentioned, XCache is one of a number of accelerator options. There are free open source alternatives and a commercial option in the powerful Zend software. Each PHP accelerator has its own set of system requirements, so choosing one depends largely on your existing or desired configuration and the characteristics of your application. It's difficult to recommend one over the other, but it is recommended that you install a compiler cache.

Tons of tuning options

In addition to caching, there are many other avenues to explore to speed your application. You can trim the fat from the PHP engine by omitting many of its more esoteric features. For example, if you don't use TCP/IP V6 (IPv6) networking, disable the feature when you build PHP. You can see the entire list of PHP configuration options by typing ./configure --help at the top of the PHP source code tree. No matter which configuration options you choose, add:

--enable-inline-optimization --disable-debug 

to your final configuration command. The former option produces the fastest PHP executable possible (without additional opcode optimizations by software like Zend Engine); the latter option takes PHP out of debug mode, which is needed only if you are trying to resolve issues in the PHP application server itself.

Of course, just like any C application, you can leverage the C compiler to build a better executable. If you run PHP as an Apache Dynamic Shared Object (DSO) on Linux or FreeBSD on x86 processors, consider adding the -prefer-non-pic option to yourCFLAGS (the environment variable that stores C compiler options). Non-PIC builds PHP using position-independent code and provides something of a 10-percent boost. You can also use -march in CFLAGS to identify your processor type, as in -march=opteron for the AMD Opteron processor.

Another speed enhancer is opcode optimization. Here, software such as the Zend Engine takes the time to optimize the opcodes produced during compilation, literally reducing the amount of work that the code performs.

Caching and optimization are transparent and require no additional programming muscle. To apply some elbow grease, pursueprofiling, or examining where your code spends its time. A bottleneck is an obvious target for rework, as are wasteful or slow algorithms. Tweaking code to eke out cycles can be valuable -- but don't attempt any optimization without profiling first.


source http://www.ibm.com/developerworks/library/os-php-fastapps1/

1 comment:

Burton Taylor said...

Performance is one of the main tasks for any apps. The article is very informative as far as performance of any app is concerned.

web application development