php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #57825 share cache between FAST CGI processes
Submitted: 2007-09-05 17:12 UTC Modified: 2011-09-30 09:30 UTC
From: marcin dot wanat at gmail dot com Assigned:
Status: Closed Package: APC (PECL)
PHP Version: 5.2.1 OS: Linux, SuSE
Private report: No CVE-ID:
 [2007-09-05 17:12 UTC] marcin dot wanat at gmail dot com
Description:
------------
PHP 5.2.4 (FCGI),  APC from CVS

loading module apc.so in php.ini cause each php process has own cache (as far as i can see by reloading apc.php).
Is it possible on to share one cache between all processes ?


APC conf:
./configure --enable-apc-spinlocks

php.ini:
extension=apc.so
apc.enabled=1
apc.shm_segments=1
apc.shm_size=1024
apc.num_files_hint=10000


I found similar 'bug' reported with WIN32, but maybe it is possible on linux or freebsd ?


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-09-05 17:56 UTC] gopalv82 at yahoo dot com
Changing to feature request as this behaviour is the intended one as of now.
 [2007-09-06 08:14 UTC] marcin dot wanat at gmail dot com
Maybe in future version of APC, memcached daemon can be used as storage because of its independence.
 [2007-09-06 09:37 UTC] gopalv82 at yahoo dot com
If you need memcached, use it directly.

APC is faster than memcached for local retrieval. I don't intend to slow it down by using any other backend which needs serialization.
 [2007-09-06 16:51 UTC] marcin dot wanat at gmail dot com
Yes, but memcache can't cache opcode itself. I need to cache opcode, and share it between FCGI PHP processes.
 [2007-09-06 16:53 UTC] rasmus@php.net
The point is that memcached is way too slow to make it worthwhile to do this.
 [2007-10-18 05:20 UTC] bruno dot baketaric at wob dot ag
There's a way to get around this missing feature (at least with Apache/mod_fcgid):
Force the fcgi-module to start only one process per Virtual-Server and let the php-cgi binary spawn enough children.

Put this into the fcgid.conf:

DefaultMaxClassProcessCount 1
DefaultMinClassProcessCount 1

And this into your wrapper script:

PHP_FCGI_CHILDREN=32
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=10000
export PHP_FCGI_MAX_REQUESTS

This way you get one APC-Cache/Virtual-Server.
 [2007-11-23 00:52 UTC] seufert at gmail dot com
To Bruno:
That wont scale, fast-cgi is supposed to start up more processes to cope with the load when required. And if your php process dies, then your going to get up to 32 Error 500's in a big batch, especially if a fast-cgi timeouts waiting for input back for the cgi process. I get this happening with 2 children to a limited degree.


I believe this is basically a duplicate of bug #11666.

Could you do something like let us set a path to a socket, for IPC between the php5-fcgi+apc processes. So for php processes running as the same user, on the same document root, could share the cache.
 [2007-11-23 11:30 UTC] rasmus@php.net
Look at the apc_mmap() function in apc_mmap.c and get rid of the unlink() call in the type of mmap you would like to do.  That way multiple processes should be able to mmap the same memory segment.
 [2008-01-18 19:33 UTC] magiatar at hotmail dot com
That doesn't work for me.

I already have 2-5 differents cache files.

I have commented all unlink in that file but the problem continues.

Is there any way to work with APC with only 1 cache file? With fastcgi the problem is critical for me.
 [2008-01-18 21:04 UTC] rasmus@php.net
Well, read the code.  You obviously also want to use a fixed filename and not do the mkstemp() or mktemp() on the filemask.  You want to just use the filename that is passed in for every process.
 [2008-07-23 06:53 UTC] tux at ilbello dot com
I think suExec + fastcgi/fcgid PHP is becoming widely adopted. A workaround to not waste all the cache on each respawn would be seriously appreciated.
 [2008-07-23 08:07 UTC] djonline at djonline dot ru
Is this problem fixed or workaround exist (without using PHP_FCGI_CHILDREN) ?
 [2008-07-24 07:14 UTC] djonline at djonline dot ru
Rasmus, i looked at apc_mmap().

I try to remove "unlink" and "mkstemp" in apc_mmap.c in last section (regular files) to make one cache for all system.

Now it looks like that:

        else {

struct passwd *userinfo;
char file_mask2[250];

            //fd = mkstemp(file_mask);
userinfo=getpwuid( geteuid());
sprintf(file_mask2,"%s-%s",file_mask,userinfo->pw_name);
            fd = open(file_mask2, O_CREAT|O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
            if(fd == -1) {
                apc_eprint("apc_mmap: mkstemp on %s failed:", file_mask);
                return (void *)-1;
            }
            if (ftruncate(fd, size) < 0) {
                close(fd);
                //unlink(file_mask);
                apc_eprint("apc_mmap: ftruncate failed:");
            }
            shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NOSYNC, fd, 0);
            close(fd);
            //unlink(file_mask);
        }
    }
    if((long)shmaddr == -1) {
        apc_eprint("apc_mmap: mmap failed:");
    }
    return shmaddr;
}

It is also add current user name to "file_mask".
Files "file_mask.username" are created, but there is too much segmentation faults. So it not work.

I try to switch to shm (--disable-mmap), and change apc_shm.c, adding one fixed key id and set permission flags to grant r/w access to all processes, also remove apc_shm_destroy call to make shared memory segment persistent between all fastcgi processes.

int apc_shm_create(const char* pathname, int proj, size_t size)
{
    int shmid;  /* shared memory id */
    int oflag;  /* permissions on shm */
    key_t key;  /* shm key returned by ftok */

    key = IPC_PRIVATE;
#ifndef PHP_WIN32
    /* no ftok yet for win32 */
    if (pathname != NULL) {
        if ((key = ftok(pathname, proj+1)) < 0) {
            apc_eprint("apc_shm_create: ftok failed:");
        }
    }
#endif

//    oflag = IPC_CREAT | SHM_R | SHM_A; //old flag
    oflag = IPC_CREAT | 0666;
key=11; //fixed key for test
    if ((shmid = shmget(key, size, oflag)) < 0) {
        apc_eprint("apc_shm_create: shmget(%d, %d, %d) failed: %s. It is possible that the chosen SHM segment size is higher than the operation system allows. Linux has usually a default limit of 32MB per segment.", key, size, oflag, strerror(errno));
    }

    return shmid;
}

void* apc_shm_attach(int shmid)
{
    void* shmaddr;  /* the shared memory address */

    if ((long)(shmaddr = shmat(shmid, 0, 0)) == -1) {
        apc_eprint("apc_shm_attach: shmat failed:");
    }

    /*
     * We set the shmid for removal immediately after attaching to it. The
     * segment won't disappear until all processes have detached from it.
     */
//    apc_shm_destroy(shmid); // REMOVED THIS
    return shmaddr;
}

But there is segmentation fault too. error_log: "Premature end of script headers: script.php".

strace on php-cgi shown last call to "futex(".


It will be very nice, if apc will have 2 options:
1. One fixed size cache for entry server, shared between all users and fcgi processes. Ideal for dedicated server, where hosted only trusted or own projects, and when different user/sites need to share the same data. 
2. One cache for each user, shared between each fcgi processes under same user. Ideal for not trusted hosting.

p.s. apc from cvs head, php 5.2.6.
 [2008-08-01 07:05 UTC] gopalv82 at yahoo dot com
the issue isn't sharing data, but sharing locks
 [2009-03-04 11:53 UTC] djonline at djonline dot ru
Gopal, you asked to test Lockhammer in production systems on 
your blog - http://t3.dotgnu.info/blog/php/test-my-
lockhammer.html
Can you explain what output is expected, and what output is 
not expected ?
e.g i have:
[root@km30609 3.1.12]# ./lockhammer_pthread
> (3120) waiting
> (3121) waiting
> (3121) in lock
> (3122) waiting
> (3123) waiting
> (3124) waiting
> (3125) waiting
> (3126) waiting
> (3127) waiting
> (3128) waiting
> (3129) waiting
> (3130) waiting
> (3131) waiting
> (3132) waiting
> (3133) waiting
> (3134) waiting
> (3135) waiting
> (3136) waiting
> (3137) waiting
> (3138) waiting
> (3139) waiting
> (3122) in lock
< (3121) off lock
> (3121) waiting
> (3123) in lock
< (3122) off lock
> (3122) waiting
> (3124) in lock
< (3123) off lock
> (3123) waiting
< (3124) off lock
> (3120) in lock
> (3124) waiting
< (3120) off lock
> (3125) in lock
> (3120) waiting
> (3126) in lock
< (3125) off lock
> (3125) waiting
> (3127) in lock
< (3126) off lock
> (3126) waiting
> (3128) in lock
< (3127) off lock
> (3127) waiting



May be cache sharing already work at apc 3.1.12 ?
 [2009-11-10 19:02 UTC] frieder dot schueler_Q at _gmail dot com
Are there any plans to add this feature to apc in near future? I think most people are switching to fastcgi/fcgid or already switched and _all_ will have or have this problem! This feature request is now over 2 years old and there is still no visible progress. For users with the popular apache webserver php-fpm is no solution and all the other workarounds like using memcache are crap.
The other two popular caches (eaccelerator and xcache) do not have this feature. If APC fixes this problem, a lot of people will switch to APC.

What is the problem of this feature request? Is it just lack of time? Are there not enough developers? Or is the problem hard to fix?
Is there anyone who is still trying to fix this? Maybe we should start a website where people can vote for the problem and donate 5$ until someone is willing to fix this!

Best regards,
Frieder
 [2009-11-13 09:12 UTC] gopalv82 at yahoo dot com
Hmm... maybe I should put up my threadless/thinkgeek wishlist up ;)

Anyway, jokes aside. The reason I haven't fixed it so far is that fixing it so that it works for fcgi and with multiple processes makes it slower for the apache mode of operation.

And there's a high likelihood that I'll break some of the already working apc functionality in the process.

The locking sub-system + memory management subsystem is what needs to be fixed here. So that pointer 0xf00 in process #1 becomes 0xbaa in process #2, so that all references are held properly.

Right now, apache2 prefork mode ensures that both processes share the same address space, which makes this rewrite-on-the-fly unnecessary.

But I'm planning some other apache2 fixes which might make this less expensive that it looks right now.

Real life keeps interfering though :)
 [2010-02-01 17:40 UTC] djonline at djonline dot ru
Why it is so hard make simple unix shared cache for first 
time, like php-shm functions 
does ?

Why you ask for Lockhammer YEAR ago and silent after that ?

Why you name you as 'official php cache' while you can't fix 
this simple issue with 
official mod_fcgid over the years?

Why there is NO documentation AT ALL on all new 3.x stuff 
like "Lazy loading", 
"preload_path", "file_md5" ?
 [2010-02-01 17:45 UTC] rasmus@php.net
Gopal already explained why it is way more complicated to do 
this across non-forked processes.  Add to his list is the 
fact that there will be no owner-death protection for the 
cache, so you end up leaving huge chunks of garbage shared 
memory segments around if things don't exit gracefully.

Patches are welcome.
 [2010-04-19 03:55 UTC] creamd at c64 dot sk
Never posted to developer forums before, but learning that the problem of sharing user cache between all processes when using fast-cgi (in my case with Lighttpd) comes as feature and is still unsolved makes me really desperate. I wanted to use APC caching quite extensively on the new version of the site I'm working on when I realized that there is *that* problem. 

I couldn't find any alternative solution when I tried googling for it. Just more and more bug reports and vague related postings. That leads me to the question.

Is there *any* memory caching system around, working with fast-cgi (under Lighttpd) that actually supports sharing of cached variables across processes?
 [2010-05-11 06:05 UTC] guillaume at ironie dot org
I'm interested in some solution for apache2-mpm-worker and mod_fcgid. Any roadmap for this feature?
 [2010-06-13 16:02 UTC] tedivm at tedivm dot com
I know this is a tricky problem, but it's also an important one. Has there been any progress in the last 2.5+ years on this?
 [2010-06-13 19:00 UTC] tedivm at tedivm dot com
Maybe this is bring approached (by us, the 'bug submitters') in the wrong manner.

As it stands now there is basically a choice if you want to use the FastCGI/FCGID- modules-

1) Use a low limit for memory to keep the over all memory down, since each process gets it's own. Downside is more cache misses.
2) The opposite- use a high limit- will ensure less misses but at a large memory cost.

So far the focus (at least on this ticket) is trying to share memory, like with mod_php, but that's got it's own downfalls. What if we instead tried 
to 
reduce the cost of a miss instead, to make lowering the memory less of a negative?


One possible way to do this would be by having a central, file-based cache behind the memory one. If APC can't find it in memory it could check this 
backend before recompiling- if it's present we can just load it into memory from there. If there is no opcode cache then APC can do it's normal 
thing, 
only then save a copy of the opcode to file.

The benefit here is that lower shm limits on each process doesn't have nearly as much of a negative affect- rather than having to load and recompile 
a 
file, it just has to load a file. There would be extra overhead in the event of both a memory and file miss (an extra stat call), but I think it 
would 
be worth it for cgi and should be disabled for mod_php.

I'm not on the mailing list and haven't seen the source code (yet, lol) so there could be flaws to this I'm not aware of it, but I think it's a 
reasonable solution to the bigger issue, if not the underlying problem itself.
 [2010-06-13 19:45 UTC] rasmus@php.net
It works fine if you use spawnfcgi or php-fpm.  Any process 
manager that launches a parent process and spawns child 
processes from that will work fine.
 [2010-06-16 10:21 UTC] ivoras at gmail dot com
I have an experimental patch for mmaped shared memory which appears to work but needs more testing:


http://ivoras.net/blog/tree/2010-06-16.php-apc-and-shared-memory.html
 [2010-12-14 06:24 UTC] th dot geist at googlemail dot com
Thanks Rasmus. This settles my unease. :)
 [2011-07-07 11:59 UTC] thangarajj at gmail dot com
Is there any sort of development happening to solve this rather huge issue? We've switched all our servers to using FastCGI & as you can imagine it's not pretty to see each process making up it's own cache.

Would be wonderful if there is even some sort of workaround.
 [2011-07-07 14:14 UTC] rasmus@php.net
thangarajj at gmail dot com, did you read the comments?
It works fine if you use php-fpm in PHP 5.3.
 [2011-07-08 07:53 UTC] thangarajj at gmail dot com
Rasmus,
Yes, I did see that, but since we're using cpanel & cpanel has still not even estimated support for php-fpm on a future version, we are unable to use it. I should have mentioned this in my original comment, sorry.
Plus I've read somewhere that fastcgi is supposed to be able to manage processes/children better than php-fpm. I'm not sure how accurate this is though.

What do you recommend in my situation?
 [2011-07-08 10:45 UTC] rasmus@php.net
A better web host? FPM is the way forward and it is superior to other process managers in every way. You asked if we worked on it. We did. FPM is that work. But really any process manager that launches a single master process and then spawns children from that will work fine with APC. And any process manager that doesn't do it that way is inherently broken.
 [2011-09-30 09:30 UTC] jpauli@php.net
Rasmus: What's the matter with mod_fcgid so ? Isn't that what it actually does ?
 [2012-01-31 15:47 UTC] simonsimcity at gmail dot com
Just to have a small question at the side ...

You've mentioned that php-fpm should work ...
My Question:
If I configure two fpm ... on different sockets ... The first fpm should be responsible for www.example1.com and the second one for www.example2.com ...
I assume that if www.example1.com has 4 workers all worker will have the same cache because they're controlled by the same manager.

Will both manager have the same shared APC-cache or will there be a separate cache for each one? In my opinion it would be nice if they'd have separate one.
This is untested and just a question how it is designed to be.
 [2012-08-20 02:48 UTC] nospam at bigalex dot it
@simonsimcity: sadly (or luckily for some people here), the way php-fpm works 
makes all the processes share the same cache, since apc is loaded into the main 
process that is forked to spawn children.
This is a problem for me, since I am looking into offering shared hosting 
through php-fpm, and this behaviour causes insecurities (and doesn't allow a 
single user to have TOTAL_MEMORY/NUMBER_OF_USERS memory available, so racing 
happens).
I am working to fix the insecurities, but the racing would still happen unless 
the module would be heavily rewritten. I am looking into it, but anyway it is 
likely the new code would not be disclosed (but the way to do it will).
Since the thread is somewhat old, please let me know if you already have a 
solution about that! :)
 [2012-08-20 09:51 UTC] simonsimcity at gmail dot com
Sorry for posting the small question here (was too off-topic).
I now wrote the question to the PHP Mailinglist: http://news.php.net/php.general/318771
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 25 07:02:14 2014 UTC