fastcgi cache how-to cache for logged-in users and make it custom for each user

Currently I'm doing cache using fastcgi_cache for non-logged-in users, and using ( if + fastcgi_no_cache + fastcgi_cache_bypass ) to pass logged-in users directly to backend which is PHP-FPM.

this work good enough, but when PHP-FPM start hitting 500+ req/s the slow/load start.

So what i'm thinking about is to create a cache for logged-in users and each user has it's own cached files, is that possible? if yes can you please provide me some tips about that. I've goggled a lot but nothing help with that.

the site running custom php cms with mysql and memcached and apc

cat /etc/nginx/nginx.comf

user  username username;

worker_processes     8;
worker_rlimit_nofile 20480;

pid /var/run/nginx.pid;

events {

    worker_connections 10240;
    use epoll;
}

http {
    include       mime.types;
    default_type  application/octet-stream;


    log_format main '$remote_addr - $remote_user [$time_local] '
            '"$request" $status  $body_bytes_sent "$http_referer" '
            '"$http_user_agent" "$http_x_forwarded_for"';
    access_log      off;
    error_log   /var/log/nginx/error.log    warn;
    log_not_found       off;
    log_subrequest      off;

    server_tokens       off;
    sendfile        on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   3;
    keepalive_requests  50;
    send_timeout        120;    
    connection_pool_size    256;
    chunked_transfer_encoding on;
    ignore_invalid_headers   on;
    client_header_timeout   60; 
    large_client_header_buffers 4 128k;
    client_body_in_file_only off;
    client_body_buffer_size 512K;
    client_max_body_size    4M;
    client_body_timeout 60;
    request_pool_size   32k;
    reset_timedout_connection on;
    server_name_in_redirect off;
    server_names_hash_max_size 4096;
    server_names_hash_bucket_size 256;
    underscores_in_headers  off;
    variables_hash_max_size 4096;
    variables_hash_bucket_size 256;

    gzip            on;
    gzip_buffers        4 32k;
    gzip_comp_level     1;
    gzip_disable            "MSIE [1-6]\.";
    gzip_min_length     0;
    gzip_proxied        any;
    gzip_types      text/plain text/css application/x-javascript text/javascript text/xml application/xml application/xml+rss application/atom+xml;

    open_file_cache     max=3000 inactive=20s;
    open_file_cache_min_uses 1;
    open_file_cache_valid   20s;
    open_file_cache_errors  off;

    fastcgi_buffer_size     8k;
    fastcgi_buffers         512 8k;
    fastcgi_busy_buffers_size   16k;
    fastcgi_cache_methods   GET HEAD;
    fastcgi_cache_min_uses  1;
    fastcgi_cache_path /dev/shm/nginx levels=1:2 keys_zone=website:2000m inactive=1d max_size=2000m;
    fastcgi_connect_timeout 60;
    fastcgi_intercept_errors on;
    fastcgi_pass_request_body on;
    fastcgi_pass_request_headers on;
    fastcgi_read_timeout    120;
    fastcgi_send_timeout    120;
    proxy_temp_file_write_size 16k;

    fastcgi_max_temp_file_size  1024m;

    include /etc/nginx/vhosts/*.conf;

}

vhost settings :

server {

    listen 80;
    server_name domain.com;

    access_log  off;
    error_log  /var/log/nginx/error.log warn;
    root /home/username/public_html;

    location ~ \.php$ {

        # pass cache if logged in
        set $nocache "";
                if ($http_cookie ~ (MyCookieUser*|MyCookiePass*)) {
                  set $nocache "Y";
                }
                fastcgi_no_cache $nocache;
                fastcgi_cache_bypass $nocache;
        fastcgi_cache       website;
        fastcgi_cache_key         $host$uri$is_args$args;
        fastcgi_cache_valid       200 301 302 304 40s;
        fastcgi_cache_valid       any 5s;
        fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503 http_404;
        fastcgi_ignore_headers  Set-Cookie;
        fastcgi_hide_header     Set-Cookie;
        fastcgi_ignore_headers  Cache-Control;
        fastcgi_hide_header     Cache-Control;
        fastcgi_ignore_headers  Expires;
        fastcgi_hide_header     Expires;
                fastcgi_no_cache $nocache;
                fastcgi_cache_bypass $nocache;
                fastcgi_index  index.php;
                fastcgi_pass 127.0.0.1:8081;
                fastcgi_param  SCRIPT_FILENAME  /home/username/public_html$fastcgi_script_name;
                include /etc/nginx/fastcgi_params;

    }

    location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|ppt|txt|mid|swf|midi|wav|bmp|js)$ {
        root            /home/username/public_html;
        expires             max;
        add_header          Cache-Control   cache;
    }

}

php-fpm config

emergency_restart_threshold = 10
emergency_restart_interval = 60s
process_control_timeout =10s
rlimit_files = 102400
events.mechanism = epoll
[www]
user = username
group = username
listen = 127.0.0.1:8081
listen.backlog = 10000
pm = dynamic
pm.max_children = 2048
pm.start_servers = 64
pm.min_spare_servers = 20
pm.max_spare_servers = 128
pm.process_idle_timeout = 10s;
pm.max_requests = 50000
request_slowlog_timeout = 40s
request_terminate_timeout = 60s

Server RAM : 32GB DDR3 Processor : Dual E5620 Centos6 64bit


Solution 1:

You just need to add a variable string to fastcgi_cache_key that represents the user ID. Something like:

set $user_key 0;
if ($cookie_userid != "") { // you set cookie "userid" via your app
    set $user_key $cookie_userid;
}
fastcgi_cache_key $user_key$scheme$host$uri$args;

This way, all anonymous users will get $user_key = 0, and the rest of your users will have their own cached version of each page.

Depending on your traffic, this could be heavy on whatever storage you choose, as you will be saving tons of duplicate pages with (maybe?) small personalizations.