I'm using APC to reduce my loading time for my PHP files. My files load very fast, except for one file where I define more than 100 arrays. This 270 kb file takes 200 ms to load. The rest of the files are full of objects, methods, and functions.
I'm wondering: does OP code caching not work as well for arrays?
My APC cache should be big enough to handle all of my classes. Currently 40% of my cache is free. My hit rate is 99%.
apc.shm_size=32 M
apc.max_file_size = 1M
apc.shm_segments= 1
APC 3.1.6
I'm using PHP 5.2, Apache 2, and Windows Vista.
All your arrays need to be serialized when stored in cache and then unserialised again when you load them from cache, this costs time and might be the significant factor of speed loss that you experience. (for your info: Serialisation)
One way to speed up serialisation a bit is to use igbinary, igbinary can be used seamlessly with APC by putting apc.serializer=igbinary in php.ini or in the ini file that goes over APC. (note: this requires APC >= 3.1.7)
You could also put apc.stat (in the same ini file) as 0 so that it only check files for modifications once as opposed to every time.
One thing about opcode caching is that unless you have it configured correctly, it will continue to stat each file to look for changes. This can cause significant overhead if you need to parse and convert many files to opcode.
You typically get a huge boost in performance by setting apc.stat = 0. However, be aware, that in order to make changes to your code, you'll need to call apc_clear_cache() or restart apache.
http://www.php.net/manual/en/apc.configuration.php#ini.apc.stat
The problem was using the gettext library to translate everything. When I get rid of around 1000 function calls, the load time is reduced from 200 ms to 6 ms.
My guess is that the serialization of the data is also a problem, however it is a secondary one.
Related
I've searched all over the web for documentation including on the XCache website.
I'm new to PHP opcode caching and XCache. I'd like an explanation of how XCache works. I know that it stores compiled php code so that it doesn't need to be recompiled everytime. But how does XCache know when php code has been updated and thus the cache is out of date?
How do I know if I need to clear the cache?
Does XCache compile and cache all php code on the server? If so can this be configured?
What are clogs? OOMs? I see large numbers for both of these in the XCache Admin page interface.
In the Code Coverage Viewer... what does Percent mean? Is this the percentage of code that has been cached?
Does hits mean the number of lines of compiled code that has been read from cache?
Does lines mean the total number of lines of code?
What is the ToDo column for?
Why are some lines highlighted in red?
I'm using PHP 5.3.2, XCache 1.3.0, and Ubuntu 10.04 if it helps.
Xcache:
optimizes performance by removing the compilation time of PHP scripts
by caching the compiled state of PHP scripts into the shm (RAM) and
uses the compiled version straight from the RAM.
Based on observations using PHP 5.5.3 and Xcache 3.1.0 this is what I can deduce:
Cacher
This module deals with two kinds of caching Opcode and Variable.
The Opcode caching is designed to be a simple drop-in. You can't customize how it decides to cache, just how much:
xcache.count setting refers to how many cache threads and correlates to how many processor cores you want to utilize — the idea is that multithreading should be the fastest, but there is no guarantee so experiment yourself
As a guideline, valid count values would be 2^n like 1, 2, 4, 8 — 0 will disable the cacher and other values will get rounded to the nearest valid value
xcache.size setting refers to the aggregate memory of all cache threads. So, each thread gets roughly size/count amount of memory
OOM aka Out of Memory, refers to the event of a cache thread hitting it's maximum size
Variable caching requires using a simple get/set api in your app code. After enabling it using xcache.var_size and xcache.var_count (similar to Opcode settings) you use xcache_set($var1) and xcache_get($var1) in your scripts.
Invalidation
The xcache.stat setting controls whether or not to check if the file was modified since it was cached:
When set to On files get checked and re-cached
When set to Off skips the check will keep the first cached version as long as the expiration time, which could help performance by limiting disk i/o
In your dev environment it's a good idea to keep it On so you can update and check your code continuously — otherwise you have to flush the cache to see updates to files.
Flushing
There is a web admin interface which allows you to flush a particular cache. The web admin uses a php api: xcache_clear_cache(…).
Since the cache is RAM based anytime the server restarts the cache should be flushed.
Expiration
Cached items expire according to xcache.ttl and xcache.var_ttl which respectively control the number of seconds a cached item lives (0 is indefinite and the default).
Coverager
The coverager module, aka Code Coverage, is a little mysterious. According to the FeatureList it seems like a diagnostic tool intended to be enabled for temporary administrative/testing situations:
Coverager + real life testcase framework, this include: [TOSHARE]
real life testcase framework, a control script with real browser. you have to write the test cases.
builtin Coverager + its viewer from web, to see how much script you have tested.
the testcase+Coverager just help you make sure all real life php web applications is running correctly when
after enabling XCache
after upgrading php4 to php5
after upgrading php4/5 to php6
I've occasionally run up against a server's memory allocation limit, particularly with a bloated application like Wordpress, but never encountered "Unable to allocate memory for pool" and having trouble tracking down any information.
Does anyone know what this means? I've tried increasing the memory_limit without success. I also haven't made any significant changes to the application. One day there was no problem, the next day I hit this error.
Using a TTL of 0 means that APC will flush all the cache when it runs out of memory. The error don't appear anymore but it makes APC far less efficient. It's a no risk, no trouble, "I don't want to do my job" decision. APC is not meant to be used that way. You should choose a TTL high enough so the most accessed pages won't expire. The best is to give enough memory so APC doesn't need to flush cache.
Just read the manual to understand how ttl is used : http://www.php.net/manual/en/apc.configuration.php#ini.apc.ttl
The solution is to increase memory allocated to APC.
Do this by increasing apc.shm_size.
If APC is compiled to use Shared Segment Memory you will be limited by your operating system. Type this command to see your system limit for each segment :
sysctl -a | grep -E "shmall|shmmax"
To alocate more memory you'll have to increase the number of segments with the parameter apc.shm_segments.
If APC is using mmap memory then you have no limit. The amount of memory is still defined by the same option apc.shm_size.
If there's not enough memory on the server, then use filters option to prevent less frequently accessed php files from being cached.
But never use a TTL of 0.
As c33s said, use apc.php to check your config. Copy the file from apc package to a webfolder and point browser to it. You'll see what is really allocated and how it is used. The graphs must remain stable after hours, if they are completly changing at each refresh, then it means that your setup is wrong (APC is flushing everything). Allocate 20% more ram than what APC really use as a security margin, and check it on a regular basis.
The default of allowing only 32MB is ridiculously low. PHP was designed when servers were 64MB and most scripts were using one php file per page. Nowadays solutions like Magento require more than 10k files (~60Mb in APC). You should allow enough memory so most of php files are always cached. It's not a waste, it's more efficient to keep opcode in ram rather than having the corresponding raw php in file cache.
Nowadays we can find dedicated servers with 24Gb of memory for as low as $80/month, so don't hesitate to allow several GB to APC. I put 2GB out of 24GB on a server hosting 5Magento stores and ~40 wordpress website, APC uses 1.2GB. Count 64MB for Magento installation, 40MB for a Wordpress with some plugins.
Also, if you have developpment websites on the same server. Exclude them from cache.
Probably is APC related.
For the people having this problem, please specify you .ini settings. Specifically your apc.mmap_file_mask setting.
For file-backed mmap, it should be set to something like:
apc.mmap_file_mask=/tmp/apc.XXXXXX
To mmap directly from /dev/zero, use:
apc.mmap_file_mask=/dev/zero
For POSIX-compliant shared-memory-backed mmap, use:
apc.mmap_file_mask=/apc.shm.XXXXXX
solution for me:
apc.ttl=0
apc.shm_size=anything you want
edit start
warning!
#bokan indicated me that i should add a warning here.
if you have a ttl of 0 this means the every cached item can be purged immediately. so if you have a small cache size like 2mb and a ttl of 0 this would render the apc useless, because the data in the cache gets always overwritten.
lowering the ttl means only that the cache cannot become full, only with items which can't be replaced.
so you have to choose a good balance between ttl and cache size.
in my case i had a cache size of 1gb, so it was more than enough for me.
edit end
had the same issue on centos 5 with php 5.2.17 and noticed that if the
cache size is small and the ttl parameter is "high" (like 7200) while
having a lot of php files to cache, then the cache fills up quite fast
and apc doesn't find anything which it can remove because all files in
the cache still fit in the ttl.
increasing the memory size is only a part solution, you still run in
this error if you cache fills up and all files are within the ttl.
so my solution was to set the ttl to 0, so apc fills up the cache an
there is allways the possibility for apc to clear some memory for new
data.
hope that helps
edit:
see also: http://pecl.php.net/bugs/bug.php?id=16966
download http://pecl.php.net/get/APC extract and run the apc.php, there you have a nice diagram how your cache usage look like
Running the apc.php script is key to understanding what your problem is, IMO. This helped us size our cache properly and for the moment, seems to have resolved the problem.
For newbies like myself, these resources helped:
Finding the apc.ini file to make the changes recommended by c33s above, and setting recommended amounts:
http://www.untwistedvortex.com/optimizing-tuning-apc-alternate-php-cache/
Understanding what apc.ttl is:
http://www.php.net/manual/en/apc.configuration.php#ini.apc.ttl
Understanding what apc.shm_size is:
http://www.php.net/manual/en/apc.configuration.php#ini.apc.shm-size
As Bokan has mentioned, you can up the memory if available, and he is right on how counter productive setting TTL to 0 is.
NotE: This is how I fixed this error for my particular problem. Its a generic issue that can be caused by allot of things so only follow the below if you get the error and you think its caused by duplicate PHP files being loaded into APC.
The issue I was having was when I released a new version of my PHP application. Ie replaced all my .php files with new ones APC would load both versions into cache.
Because I didnt have enough memory for two versions of the php files APC would run out of memory.
There is a option called apc.stat to tell APC to check if a particular file has changed and if so replace it, this is typically ok for development because you are constantly making changes however on production its usually turned off as it was with in my case - http://www.php.net/manual/en/apc.configuration.php#ini.apc.stat
Turning apc.stat on would fix this issue if you are ok with the performance hit.
The solution I came up with for my problem is check if the the project version has changed and if so empty the cache and reload the page.
define('PROJECT_VERSION', '0.28');
if(apc_exists('MY_APP_VERSION') ){
if(apc_fetch('MY_APP_VERSION') != PROJECT_VERSION){
apc_clear_cache();
apc_store ('MY_APP_VERSION', PROJECT_VERSION);
header('Location: ' . 'http'.(empty($_SERVER['HTTPS'])?'':'s').'://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']);
exit;
}
}else{
apc_store ('MY_APP_VERSION', PROJECT_VERSION);
}
This worked for our guys (running a slew of Wordpress sites on the same server).
Changed memory settings in the /etc/php.d/apc.ini file. It was set to 64M, so we doubled it to 128M.
apc.shm_size=128M
Looking at the internets there can be various of causes.
In my case leaving everything default except...
apc.shm_size = 64M
...cleared the countless warnings that I was getting earlier.
I received the error "Unable to allocate memory for pool" after moving an OpenCart installation to a different server. I also tried raising the memory_limit.
The error stopped after I changed the permissions of the file in the error message to have write access by the user that apache runs as (apache, www-data, etc.). Instead of modifying /etc/group directly (or chmod-ing the files to 0777), I used usermod:
usermod -a -G vhost-user-group apache-user
Then I had to restart apache for the change to take effect:
apachectl restart
Or
sudo /etc/init.d/httpd restart
Or whatever your system uses to restart apache.
If the site is on shared hosting, maybe you must change the file permissions with an FTP program, or contact the hosting provider?
To resolve this problem set value for apc.shm_size as integer
Locate your apc.ini file (In my system apc.ini file location /etc/php5/conf.d/apc.ini) and set:
apc.shm_size = 1000
on my system i had to insert
apc.shm_size = 64M
into /usr/local/etc/php.ini
(FreeBSD 9.1)
then when i looked at apc.php (which i copied from /usr/local/share/doc/APC/apc.php to /usr/local/www/apache24/data)
i found that the cache size had increased from the default of 32M to 64M and i was no longer getting a large cache full count
references:
http://au1.php.net/manual/en/apc.configuration.php
also read Bokan's comments, they were very helpful
Monitor your Cached Files Size (you can use apc.php from apc pecl package) and increase
apc.shm_size according to your needs.
This solves the problem.
I have a single server site thats pushing 200k unqiues per day, and the traffic doubles roughly every 40 days (for the last 5 months anyway).
I pretty much only plan to cache the output of mysql_query functions for an hour or so. If cache is older than that, run query, put result back into the cache for another hour.
My mysql DB is about 200mb in size (grows by maybe 10-20mb/month).
Im doing a lot of file caching by writing HTML outputs and using them for a few minutes, and then regenerating the html.
Unfortunately, since its a database site, that allows for many sorting, searching and ordering methods, as well as pagination.... there are over 150,000 cached pages. Im also not caching the search queries, which cause most of the load.
I'd like to implement a caching system, and I wanted to know which one is faster. Would love to see some benchmarks.
A quick Googling says that APC is 5 times faster than Memcached.
My experience say that APC is nearly 7-8 times faster than Memcached.. but, memchached can be accessed by different services (for example, if you run mainly on apache and delegates some traffic, e.g. static contents like images or pure html, to another web-service, like lighttpd), that can be really usefull, if not indispensable.
APC have less feature than memcached and is easly to use and optimize, but this depends on your needs.
Like you mentioned there are a few different aspects of caching. I probably would focus on the following aspects of caching in your php app:
opcode caching which caches the compiled bytecode of php scripts. You can see a benchmark here (albeit an older article): http://itst.net/654-php-on-fire-three-opcode-caches-compared
Note: I strongly recommend using opcode caching.
Caching user data - APC and others do this. This would be your reference data or data that is fairly static and doesn't change often. You can clear the cache every day or trigger a clean cache when this reference data changes. This is also strongly recommended since typically reference data is used frequently and doesn't change often.
Caching sql queries - I know that Zend makes this task easy with a simple setup. Since these queries don't change this is another obvious one (like you mentioned)
Additional (if possible):
caching html pages - obviously caching a static page is faster than a generated one and typically this is hard to do since most pages in apps are so dynamic. Worth it if you can do it although if your queries are cached and your SQL is simple I wouldn't focus on this.
caching sql results - personally I stay away from this. I'll let the database do its work and what it does best since the DBMS typically has caching. I may cache the results for the thread of execution (i.e., I just retrieved this so don't do it again) but I don't go much beyond that.
I've used APC and eAccelerator successfully (I personally like to work with APC and it supposed opcode caching and user data caching for my reference data and sql queries). Use XDebug to profile your code.
You want to compare APC key-value store vs Memcache right? Because APC also does opcode cache, which is a different thing.
Well, on a single machine, APC k-v cache is way faster than memcache. Memcache has more functionality, but is intended for distributed environments, while APC works on single servers only.
I did a benchmark recently to set and then get 1 million keys in both, each key was a sequential integer, and the values were a 32byte string.
Over localhost, memcache could retrieve 12k keys/second in a single thread. APC returned 90K/second. However, if you use multi-threads or "multi_get" with memcache, it gets very close to APC performance.
The benchmark ran on a 1GB vps at slicehost.
in my case apc is 59 times faster than memcache
<?php
ini_set('apc.enable_cli','1'); //if u run in cli you may need to do changes in php.ini
error_reporting(E_ALL);
$mem=new Memcache();
$mem->connect('127.0.0.1',11211);
$mem->replace('testin','something');
$i=0;
$time=time()+microtime();
apc_store ( 'testin','something');
$num=1000000;
while($i<$num){
$mem->get('testin');
$i++;
}
echo "memcache took: ",time()+microtime()-$time," for 1 million gets","\n";
$time=time()+microtime();
$i=0;
print_r(apc_fetch('testin'));
while($i<$num) {
apc_fetch('testin');
$i++;
}
echo "apc took: ",time()+microtime()-$time,"for 1 million gets \n";
here is the output
memcache took: 37.657398939133 for 1 million gets
somethingapc took: 0.64599800109863for 1 million gets
It's almost impossible to accurately predict which would be faster. I would run tests with both in a development environment with similar data.
When performance is of importance, always use a profiler.
Im use IPB 3.1.4 with APC it works justy two times faster then without it.
Requests per second: 43.46 [#/sec] (mean)
Requests per second: 24.23 [#/sec] (mean)
Don't test IPB with memcached yet
In a system I am currently working on, there is one process that loads large amount of data into an array for sorting/aggregating/whatever. I know this process needs optimising for memory usage, but in the short term it just needs to work.
Given the amount of data loaded into the array, we keep hitting the memory limit. It has been increased several times, and I am wondering is there a point where increasing it becomes generally a bad idea? or is it only a matter of how much RAM the machine has?
The machine has 2GB of RAM and the memory_limit is currently set at 1.5GB. We can easily add more RAM to the machine (and will anyway).
Have others encountered this kind of issue? and what were the solutions?
The configuration for the memory_limit of PHP running as an Apache module to server webpages has to take into consideration how many Apache process you can have at the same time on the machine -- see the MaxClients configuration option for Apache.
If MaxClients is 100 and you have 2,000 MB of RAM, a very quick calculation will show that you should not use more than 20 MB *(because 20 MB * 100 clients = 2 GB or RAM, ie the total amount of memory your server has)* for the memory_limit value.
And this is without considering that there are probably other things running on the same server, like MySQL, the system itself, ... And that Apache is probably already using some memory for itself.
Or course, this is also a "worst case scenario", that considers that each PHP page is using the maximum amount of memory it can.
In your case, if you need such a big amount of memory for only one job, I would not increase the memory_limit for PḦP running as an Apache module.
Instead, I would launch that job from command-line (or via a cron job), and specify a higher memory_limit specificaly in this one and only case.
This can be done with the -d option of php, like :
$ php -d memory_limit=1GB temp.php
string(3) "1GB"
Considering, in this case, that temp.php only contains :
var_dump(ini_get('memory_limit'));
In my opinion, this is way safer than increasing the memory_limit for the PHP module for Apache -- and it's what I usually do when I have a large dataset, or some really heavy stuff I cannot optimize or paginate.
If you need to define several values for the PHP CLI execution, you can also tell it to use another configuration file, instead of the default php.ini, with the -c option :
php -c /etc/phpcli.ini temp.php
That way, you have :
/etc/php.ini for Apache, with low memory_limit, low max_execution_time, ...
and /etc/phpcli.ini for batches run from command-line, with virtually no limit
This ensures your batches will be able to run -- and you'll still have security for your website (memory_limit and max_execution_time being security measures)
Still, if you have the time to optimize your script, you should ; for instance, in that kind of situation where you have to deal with lots of data, pagination is a must-have ;-)
Have you tried splitting the dataset into smaller parts and process only one part at the time?
If you fetch the data from a disk file, you can use the fread() function to load smaller chunks, or some sort of unbuffered db query in case of database.
I haven't checked up PHP since v3.something, but you also could use a form of cloud computing. 1GB dataset seems to be big enough to be processed on multiple machines.
Given that you know that there are memory issues with your script that need fixing and you are only looking for short-term solutions, then I won't address the ways to go about profiling and solving your memory issues. It sounds like you're going to get to that.
So, I would say the main things you have to keep in mind are:
Total memory load on the system
OS capabilities
PHP is only one small component of the system. If you allow it to eat up a vast quantity of your RAM, then the other processes will suffer, which could in turn affect the script itself. Notably, if you are pulling a lot of data out of a database, then your DBMS might be require a lot of memory in order to create result sets for your queries. As a quick fix, you might want to identify any queries you are running and free the results as soon as possible to give yourself more memory for a long job run.
In terms of OS capabilities, you should keep in mind that 32-bit systems, which you are likely running on, can only address up to 4GB of RAM without special handling. Often the limit can be much less depending on how it's used. Some Windows chipsets and configurations can actually have less than 3GB available to the system, even with 4GB or more physically installed. You should check to see how much your system can address.
You say that you've increased the memory limit several times, so obviously this job is growing larger and larger in scope. If you're up to 1.5Gb, then even installing 2Gb more RAM sounds like it will just be a short reprieve.
Have others encountered this kind of
issue? and what were the solutions?
I think you probably already know that the only real solution is to break down and spend the time to optimize the script soon, or you'll end up with a job that will be too big to run.
Recent versions of PHP have a cache of filenames for knowing the real path of files, and require_once() and include_once() can take advantage of it.
There's a value you can set in your php.ini to set the size of the cache, but I have no idea how to tell what the size should be. The default value is 16k, but I see no way of telling how much of that cache we're using. The docs are vague:
Determines the size of the realpath cache to be used by PHP. This value should be increased on systems where PHP opens many files, to reflect the quantity of the file operations performed.
Yes, I can jack up the amount of cache allowed, and run tests with ab or some other testing, but I'd like something with a little more introspection than just timing from a distance.
You've probably already found this, but for those who come across this question, you can use realpath_cache_size() and realpath_cache_get() to figure out how much of the realpath cache is being used on your site and tune the settings accordingly.
Though I can't offer anything specific to your situation, my understanding is that 16k is pretty low for most larger PHP applications (particularly ones that use a framework like the Zend Framework). I'd say at least double the cache size if your application uses lots of includes and see where to go from there. You might also want to increase the TTL as long as your directory structure is pretty consistent.
To expand on the answer provided by Noodles, you can create a little test.php with the following code:
<?php
echo "<br>cache size: ".realpath_cache_size();
echo "<br>";
echo "<br>cache: ".print_r(realpath_cache_get(););
?>
Upload this to your site and navigate to it. It will show you the amount of bytes currently being used by your cache, as well as what's actually in the cache. This value is changing all the time so keep hitting that F5 button to get a better sense of where you're at. It's a good idea also to do your testing during peak times.
If you see the value is frequently hitting your max cache size as defined in your php.ini then it's time to increase that value.
Keep in mind that the default PHP setting is 16K which is 16384 bytes.
the 16K is the # of files not activity.
Set to 1k for most sites. Very similar to settings in APC, xcache ea etc.