Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

I have an Nginx server that is a caching proxy for an Apache server running a Drupal website. The issue I'm seeing is that, for no apparent reason, some URI requests will hit the cache and others won't.

An example - we have the URL www.site.com/cat/1 that we look through using the following line in bash:

for num in `seq 1 10`; do echo $num; curl -I http://www.site.com/cat/1; sleep 1; done

Out of those 10 requests, at least one will result in a cache miss however the number never stays the same and it never happens at the same point in the loop :/

These are the headers returned by Nginx when there is a miss. Note that the 'Cache' is the $upstream_cache_status Nginx variable:

HTTP/1.1 200 OK
Server: nginx
Date: Mon, 22 Jul 2013 18:17:08 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
X-Drupal-Cache: HIT
Etag: "1374517025-0"
Content-Language: en
Link: </node/3548>; rel="shortlink",</cat/1>; rel="canonical"
X-Generator: Drupal 7 (http://drupal.org)
Cache-Control: max-age=10800
Last-Modified: Mon, 22 Jul 2013 18:17:05 +0000
Expires: Mon, 22 Jul 2013 21:17:08 GMT
Vary: Cookie
Cache: MISS

And these are the headers returned when there is a hit:

HTTP/1.1 200 OK
Server: nginx
Date: Mon, 22 Jul 2013 18:17:09 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
X-Drupal-Cache: HIT
Etag: "1374517025-0"
Content-Language: en
Link: </node/3548>; rel="shortlink",</cat/1>; rel="canonical"
X-Generator: Drupal 7 (http://drupal.org)
Cache-Control: max-age=10800
Last-Modified: Mon, 22 Jul 2013 18:17:05 +0000
Expires: Mon, 22 Jul 2013 21:17:09 GMT
Vary: Cookie
Cache: HIT

As you can see, they are the same except for the 'Cache:' header. From the caching logs I see the following example:

***22/Jul/2013:19:35:01 +0100 x.x.x.x MISS Cache-Control: max-age=10800 Upstream-Cache-Control: public, max-age=86400 Ignore-Cache: 0 Bypass-Cache: 0 Expires: Mon, 22 Jul 2013 21:35:01 GMT Uptream-Expires: Sun, 19 Nov 1978 05:00:00 GMT www.site.com "HEAD /cat/1 HTTP/1.1" (200) "curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3" Args: - HTTP Cookie: - 

***22/Jul/2013:19:35:02 +0100 x.x.x.x HIT Cache-Control: max-age=10800 Upstream-Cache-Control: public, max-age=86400 Ignore-Cache: 0 Bypass-Cache: 0 Expires: Mon, 22 Jul 2013 21:35:02 GMT Uptream-Expires: Sun, 19 Nov 1978 05:00:00 GMT www.site.com "HEAD /cat/1 HTTP/1.1" (200) "curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3" Args: - HTTP Cookie: -

***22/Jul/2013:19:35:05 +0100 x.x.x.x MISS Cache-Control: max-age=10800 Upstream-Cache-Control: public, max-age=86400 Ignore-Cache: 0 Bypass-Cache: 0 Expires: Mon, 22 Jul 2013 21:35:01 GMT Uptream-Expires: Sun, 19 Nov 1978 05:00:00 GMT www.site.com "HEAD /cat/1 HTTP/1.1" (200) "curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3" Args: - HTTP Cookie: - 

An explanation of the log entries:

HIT|MISS - Whether or not the cache was hit
Cache-Control: Nginx returns this
Upstream-Cache-Control: Apache returns this
Ignore-Cache: If 1, Nginx will not cache Apache's response
Bypass-Cache: If 1, Nginx will bypass it's cache
Expires: Nginx returns this
Uptream-Expires: Apache returns this
Args: Nginx's $args variable HTTP Cookie: Nginx's $http_cookie variable

So, as can be seen from the 3 log entries it doesn't appear to be a case of the cache entry expiring. What's annoying is that I get similar hit/miss results if I use a browser as well, so I don't believe it's the cookies or lack there-of. Here is Apache's response if I query it directly:

HTTP/1.1 200 OK
Date: Mon, 22 Jul 2013 18:46:42 GMT
Server: Apache
X-Drupal-Cache: HIT
Etag: "1374517025-0"
Content-Language: en
Link: </node/3548>; rel="shortlink",</cat/1>; rel="canonical"
X-Generator: Drupal 7 (http://drupal.org)
Cache-Control: public, max-age=86400
Last-Modified: Mon, 22 Jul 2013 18:41:17 +0000
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Vary: Cookie
Connection: close
Content-Type: text/html; charset=utf-8

And here is the Nginx proxy config:

#nginx.conf
proxy_cache_path    /var/cache/nginx/site-cache levels=1:2:2 keys_zone=site-cache:256m inactive=180m max_size=512m;
proxy_temp_path     /var/cache/nginx/proxy_temp ;

#sites.conf
    proxy_cache_bypass      $http_regenerate_cache $bypass_cache $http_admin_bypass_cache;
    proxy_no_cache          $ignore_cache;
    expires         3h;
    add_header              Cache $upstream_cache_status;
    proxy_ignore_headers   Cache-Control Expires;
    proxy_redirect          off;
    proxy_set_header        Host $host;
    proxy_pass              http://192.168.0.10:80;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_read_timeout      10m;
    proxy_connect_timeout   10m;
    proxy_cache             site-cache;
    proxy_cache_valid       301 302 10m;
    proxy_cache_valid       200 180m;
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;

The Apache config:

<VirtualHost *:80>
ServerName www.site.com

DocumentRoot /sites/sites.com/www
ErrorLog /var/log/httpd/www.site.com.error.log
CustomLog /var/log/httpd/www.site.com.access.log combined
<Directory /sites/sites.com/www>
AllowOverride All
</Directory>

</VirtualHost>

The .htaccess file is the stock-standard Drupal one and the only header-related stuff I see in there is

ExpiresDefault A1209600

If you can shed some light on the matter and suggest a course of action, that would be great as I have no idea what the issue is. Unfortunately, switching to something like Varnish is not viable this far into the project. Thus, any help is greatly appreciated :D

share|improve this question
    
What happens when you make, say, a hundred queries to the same URL? How many Cache-Hits and how many misses? –  Mikko Jul 23 '13 at 19:57
    
When increased to 100 curls I see a 20-30% cache miss –  Marcus Jul 24 '13 at 16:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.