PHP open_basedir and Magento Performance

PHP open_basedir and Magento Performance

Mar 31

  • Created: Mar 31, 2010 11:13 AM

The PHP open_basedir directive is a security feature within PHP that allows you to specify which files PHP is allowed to be opened. With open_basedir, you specify the directory tree or trees that PHP can open and PHP will not open anything outside of these directories. There are negative side effects in relation to system performance when using open_basedir. The most significant is that when open_basedir is enabled, the PHP realpath cache will be disabled. The PHP realpath cache has been available in PHP since 5.1.0 and caches the paths of PHP include files.

If running a smaller site with a low file count and with relatively shallow directory paths, the fact that directory paths will not be cached isn’t necessarily essential. But with applications such as Magento built on the Zend Framework, you end up with both a large base file count with a large include path and a very deep directory structure. In this situation you need to make sure that your paths do become cached with the realpath cache which means leaving open_basedir disabled.

While stack tracing a PHP process on a Magento store, you will see many lstat calls similar to the following:

access(&quot;/chroot/home/store/html/app/code/local/Core/Block/Template.php&quot;, F_OK) = 0<br />
time(NULL)                              = 1268839768<br />
lstat(&quot;/chroot&quot;, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home&quot;, {st_mode=S_IFDIR|0711, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home/store&quot;, {st_mode=S_IFDIR|S_ISGID|0751, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home/store/html&quot;, {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home/store/html/app&quot;, {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home/store/html/app/code&quot;, {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home/store/html/app/code/local&quot;, {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home/store/html/app/code/local/Core&quot;, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home/store/html/app/code/local/Core/Block&quot;, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0<br />
lstat(&quot;/chroot/home/store/html/app/code/local/Core/Block/Template.php&quot;, {st_mode=S_IFREG|0644, st_size=5968, ...}) = 0

When the realpath cache is enabled the number of these calls will drop dramatically as the paths being used will be cached, preventing the tree of lstat calls that you see above. When open_basedir is enabled, these paths cannot be cached requiring all of the lstat calls seen above every time the file is called. The issue with this situation is that the system is spending a significant amount of cpu time performing system calls instead of running the processes in userland. If you see a significant amount of cpu time spent in %sy your system may not be using the realpath cache.

So how bad is performance running Magento with the open_basedir enabled? I ran a simple test to find out. I installed a Magento demo store on a test server and compared the number of lstat calls with open_basedir enabled and disabled for a single product page load.

With open_basedir enabled: 25998 lstat() calls

With open_basedir disabled: 1155 lstat() calls

The resulting difference was an additional 24843 lstat calls required for a single page load with open_basedir enabled. Regarding the page load times, there is a very trivial difference for a single page load with no other concurrent processes, but as soon as you have many concurrent page load processes running on the server, these lstat calls will bring the server to a crawl. The issue will be amplified if the server is running on older slow IDE or SATA disks.

Posted in: Magento, php / Tagged: , ,