I did a small benchmark comparing APC vs. Memcache. First of all, I'd like to say that in many situations, that would be like comparing apples to oranges. APC is opcode cache, primarily, and memcache is generic memory caching tool. In addition to that, memcache can be scaled to many servers.

Still, for some simple memory caching, primarily to reduce database hits on repeated (summary) queries, I was wondering if APC (more precisely, it's user data caching functionality) would perform better than memcache, because memcache has certain network latency involved, since it is running as a network service and is interfaced through network protocols.

For simple data (strings, arrays, arrays of arrays) -- that are often found on most CMS systems as summary fields, for instance latest topics, latest news, latest whatever, I find the following

  • Memcache outperforms APC (user data caching) when number of reads is close to number of writes (ie. below 20 reads for 1 write)
  • APC outperforms Memcache when number of reads is greater than 20 for each write, where APC is significantly faster for 100 reads per write or more, situations.

Does anyone have any experience with this, or can anyone perhaps suggest or perform some more thorough benchmarking (for situations not requiring scalable memcaching) - like forced multithreading on more than 2 cores?

Environment:
- OS: Vista 32-bit
- Mem: 2GB
- CPU: Turion64 X2
- PHP: 5.2.4 (as apache module)
- Apache. 2.2
- APC 3.0.15-dev (from PHP 5.2.4 PECL bundle)
- Memcache php_memcache.dll from PHP 5.2.4 PECL bundle
- Memcached for Win32, ver. 1.2.1

Source code follows. You can call the script with (any of the) three params:
loops= number of loops to perform (start with 100)
rows= number of rows of 5-field array with random integer and string data, variable size (start with 20)
reads= number of reads from cache for one write (start with 1-100, or more)

	header ('Content-type: text/plain');
	$loops= isset($_GET['loops']) ? (int) $_GET['loops'] : 100;
	$nrows= isset($_GET['rows']) ? (int) $_GET['rows'] : 20;
	$nreads= isset($_GET['reads']) ? (int) $_GET['reads'] : 100;

// Prepare array of arrays (20 rows, 4 fields per row)
echo "Preparing array... ($nrows rows)"; flush();
$rows= array();
for ($i=0; $i<$nrows; $i++) {
	// Try with array of arrays (typical for CMS content fields)
	$rows[]= array ('var1' => mt_rand(1, 65536), 'var2' => mt_rand(1, 40000000), 'var3' => randomString(mt_rand(5, 32)), 'var4' => randomString(mt_rand(100, 512)));

	// Or try with pure strings (uncomment both for mixed rows)
	$rows[]= randomString(1, 512);
}
echo " Done!\n"; flush();

// APC loop, 1000 iterations, store 1, read 100
echo "Begin APC loop ({$loops})... "; flush();
$tstart= microtime(true);
for ($i=0; $i<$loops; $i++) {
	// Write phase
	apc_delete('therows');
	apc_store('therows', $rows);

	// Read phase
	for ($j=0; $j<$nreads; $j++) {
		$rows2= apc_fetch('therows');
	}
}
$time= microtime(true) - $tstart;
echo " Done: $time sec\n"; flush();

// Memcache loop, 1000 iterations, store 1, read 100
echo "Begin Memcache loop ({$loops})... "; flush();
$memcache= new Memcache();
$memcache->connect('127.0.0.1', 11211);
$tstart= microtime(true);
echo " Connected... "; flush();
for ($i=0; $i<$loops; $i++) {
	// Write phase
	$memcache->set('therows', $rows);

	// Read phase
	for ($j=0; $j<$nreads; $j++) {
		$rows2= $memcache->get('therows');
	}
}
$time= microtime(true) - $tstart;
echo " Done: $time sec\n"; flush();

function randomString($len) {

$str= '';
for ($i=0; $i<$len; $i++) {
	$seed= mt_rand (0, 2);
	switch ($seed) {
		case 0: $str.= mt_rand (0, 9); break;
		case 1: $str.= chr(mt_rand(0, 25)+65); break;
		case 2:
		default: $str.= chr(mt_rand(0, 25)+97); break;	
	}
}

return $str;	
}

    Hello
    A couple of questions.

    You tell about your super machine setup.
    Why?
    It is useless info. If you can not tell any numbers of the performance, these technical data means nothing.......
    You do not show any figures. No results from your benchmark!
    So, how can I compare with my cache? My speeds.

    I haved used eAccelerator for some years.
    Please add the code so eAccelerator can be compared
    with your benchmark results.
    I do not know how to write same code for eAccelerator.

    Another question.

    Your script is not using actual php pages scripts to benchmark.
    It looks it uses only some special functions from the cache module.

    Wouldnt, for a true real compare be much better to use some normal php code.
    That does not involve any special cache functions, but real website php script or something like it.
    Code that would work at any PC, without having any special PHPCaching
    and would work with any PHP Caching enabled.

    Thanks.

      tinder wrote:

      Hello
      A couple of questions.
      You do not show any figures. No results from your benchmark.
      So, how can I compare my cache?

      Ok, here you go. The above code, for several situations, 1000 loops, 20 arrays of fields in the cache:

      1:1 read:write
      APC 0.55 sec
      Memcache 0.08 sec

      20:1 read:write
      APC 0.75 sec
      Memcache 0.79 sec

      100:1 read:write
      APC 1.53 sec
      Memcache 3.54 sec

      Different number of rows or loops does not change relative differences.

      I use haved used eAccelerator for some years.
      Please add the code so eAccelerator can be compared
      with your benchmark results.
      I do not know how to write same code for eAccelerator.

      This was not opcode cacher benchmark, but specific APC (user data api) vs Memcache. If you want eAccelerator opcode cacher benchmarks, please see the link below.

      Another question.
      Your script is not using actual php pages scripts[/b] to benchmark.



      This test was pure data-store/data-retrieve test. In a real page, the results actually show the same trend, in fact APC performed even better probably because of memcache's connection overhead on each script access.

      For example, using Apache's benchmark tool (ab) I did 100 requests to a page that loads 20 last topics from memory cache, using the isolated retrieve code as shown above. With APC the page loaded in average at 13.92msec, and with memcache it loaded in average at 24msec. Concurrency level did not change relative differences.


      It looks it is only uses some special function from the cache module.



      These functions (user data caching) were exactly the reason of benchmarking. 🙂 My problem was, if I had APC as opcode cacher, should I install and use memcache, or APC's user data caching functions?

      Again, I did not perform opcode cacher benchmarks, others have done that before with much better and more precise results:

      http://eaccelerator.net/wiki/BenchTroll

        tinder wrote:

        You tell about your super machine setup.
        Why?
        It is useless info.

        Not so. There may be differences between Windows and Linux libraries (specifically because of network interface to memcache), and there may be differences if different processes are forced to different cores. I had no control over it.

          Write a Reply...