Advanced Caching

Flawless Application Delivery

Trainer Intro

James Tacker

Technology Consultant & Content Developer

Previous Training Work:

  • Sauce Labs
  • New Relic
  • Salesforce
  • Atlassian

james.tacker@servicerocket.com

Prerequisites/Expectations

  • Sysadmin, DevOps, Solution Architect
  • Some familiarity with Web Servers
  • Some familiarity with Linux
  • Text Editor: Vim, Vi, Emacs etc.
  • Some knowledge of Networking

The Training Environment

  • AWS EC2 Instances
  • Ubuntu 16.04
    • Apache 2
    • Wordpress
    • NGINX Plus r11

Log Into AWS

If you haven't done so already, please take the time to SSH into your EC2 Instances (Windows users use PuTTY).

Check your email for the login credentials, check your spam folder!


                        ssh student<number>@<ec2-server-hostname>
                  

Course Administration

  • Course Duration: 4 hours
  • Ask questions at any time!

Agenda

NGINX Use Cases

Caching Overview

Module Objectives

This module enables you to:

  • Understand RFC Caching Guidelines
  • Review Basic NGINX Cache Configuration
  • Debugging the Cache

How Caching Works

Basic Principles

  • Browser Cache
  • CDN
  • Reverse Proxy Cache

HTTP
Cache-Control

Cache-Control
header dictates behavior


	"public"                             
"private" 
"no-cache"
"no-store"                           
"no-transform"              
"must-revalidate"        
"proxy-revalidate"
			
Documentation: RFC Guidelines

HTTP Headers


				Expires: Tue, 6 May 2017 03:18:12 GMT
Cache-Control: public, max-age=60
X-Accel-Expires: 30
Last-Modified: Tue, 29 April 2017 02:28:11 GMT
ETag: "3e74-215-3105fbbc"
			
Documentation: HTTP Header Definitions

X-Accel


# When passed URI /protected_files/myfile.pdf
location /protected_files {
  internal;
  alias /var/www/files/;
}

# Or proxy to another server
location /protected_files {
  internal;
  proxy_pass http://127.0.0.1:8080/;
}
			
Documentation: X-Accel

Special Headers

  • X-Accel-Redirect
  • X-Accel-Buffering
  • X-Accel-Charset
  • X-Accel-Expires
  • X-Accel-Limit-Rate

Etag


			location ~* ^/static/images/$ {
    add_header Cache-Control must-revalidate; 
    etag on;
}

Caching Process Part 1

  1. Client makes request
  2. Request hits NGINX

Caching Process Part 2

  1. NGINX generates hash
  2. NGINX checks if hash exists in memory
    • If not, then request proceeds to app

HTTP Header Details


#Hash Key
dcc2daea797a0dfd7bac7eec4e33a4a
___________________________________

#md5
(http + example.com + /index.php)

#Request
GET /index.php HTTP.1/1

#Headers
User-Agent: curl/7.35.0
Host: example.com
Accept: * / *

#Body
11101001 10101011 000000000 11101010 
                  

Caching Process Part 3

  1. App sends response
  2. Hash saved in memory
  3. File saved in file system

In Memory Details


				#In Memory
dcc2daea797a0dfd7bac7eec4e33a4a

#In File System
/tmp/cache/a/a4/daea797a0dfd7bac7eec4e33a4a
			

Caching Process Part 4

  1. Subsequent request
  2. NGINX checks if hash exists in memory
  3. Hash points to file
  4. Client response sent from cache

NGINX Caching Basics

  • proxy_cache_path
    : sets path
  • proxy_cache
    : invokes the cache
  • proxy_cache_key
    : sets key

			proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=my_cache:20m inactive=5m;

server {
    proxy_cache_key $scheme$host$request_uri;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
...
    location /application1 {
        proxy_cache my_cache;
        proxy_cache_valid any 10m;
        proxy_pass https://backend.server;
    }
}	

Cache Instrumentation


				add_header X-Cache-Status $upstream_cache_status;
			

MISS

BYPASS

EXPIRED

STALE

UPDATING

REVALIDATED

HIT

Written to cache

proxy_cache_bypass

Expired entry

Problem with upstream

proxy_use_stale

proxy_cache_revalidate

Valid, fresh content

Lab 1.0: WordPress DNS Modification

  1. SSH into your
    backend
    EC2 Instance
  2. Download the WordPress cli (1st command below)
  3. Replace the
    New-backend-url
    section and run command to search and replace old URL (2nd command below)
  4. Add content as needed via WordPress admin portal (login is
    admin:admin
    )

			$ sudo curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
$ sudo php wp-cli.phar search-replace 'http://ec2-54-205-18-28.compute-1.amazonaws.com' '<New-backend-url>' --path=/var/www/html --skip-columns=guid --allow-root
		    		

Lab 1.0: Successful Replace

Lab 1.1: Reverse Proxy

  1. SSH into your NGINX Plus Instance
  2. Backup
    default.conf
    , and create
    proxy.conf
    
    		    		$ cd /etc/nginx/conf.d/
    $ sudo mv default.conf default.conf.bak
    $ sudo vim /etc/nginx/conf.d/proxy.conf
    		    		
  3. proxy.conf
    configuration details:
    
       server {
        listen 80;
        root /usr/share/nginx/html;
        index index.php index.html;
    
        location / {
            proxy_pass http://<New-backend-url>/;
        }
    }
    		    		

Lab 1.2: Reverse Proxy Cache

  1. Reload and test
    http://Nginx-frotend-url/
    to ensure the proxy is working
  2. Define a cache path in the
    http
    context of
    proxy.conf
    
    		    		proxy_cache_path /data/nginx/cache levels=1:2
    keys_zone=wordpress_cache:20m inactive=5m;
    		    		
  3. In the
    server
    context, set the
    proxy_cache_key
    and
    proxy_set_header
    :
    
    proxy_cache_key $scheme$host$request_uri;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    		    	

Lab 1.3: Instrument and Test

  1. Use a
    map
    to instrument the cache on
    localhost
    
    						map $remote_addr $cache_status {
        127.0.0.1   $upstream_cache_status;
        default         "";
    }
    server {
        ...
        add_header X-Cache-Status $cache_status;
    }
    					
  2. Set the
    proxy_cache
    and the
    proxy_cache_valid
    for
    10m
    
    					location / {
    ...
        proxy_cache wordpress_cache;
        proxy_cache_valid any 10m;
    }
    				
  3. Save and reload NGINX. Test using
    curl -I http://localhost

NGINX Cache Types

  • GET and HEAD with no Set-Cookie response
  • Caches based on:
    • raw URL
    • key values
    
    						#Example
    proxy_cache_key $scheme$host$request_uri;
    					
  • Cache time defined by:
    • X-Accel-Expires
    • Cache-Control
    • Expires

Alternative Caches

  • FastCGI
  • Memcache
  • uwsgi and SCGI

Lab 2.0 Status Page

  1. Create a new conf called
    status.conf
  2. status.conf
    configuration details
    
    		server {
        listen 9090;
        root /usr/share/nginx/html;
    
        location = /status {
            status;
        }
    }
    				
  3. Add the
    status_zone
    directive in your
    proxy.conf
    
    				server {
        ...
        status_zone wordpress_proxy;
    }
    			
  4. Save, reload, then visit
    status.html

Selective Caching

Separate Cache Placement through keys and regex


					# Define caches and their locations
proxy_cache_path /mnt/ssd/cache keys_zone=ssd_cache:10m levels=1:2 inactive=600s
max_size=700m;
proxy_cache_path /mnt/disk/cache keys_zone=disk_cache:100m levels=1:2 inactive=24h
max_size=80G;

# Requests for .mp4 and .avi files go to disk_cache
# All other requests go to ssd_cache
map $request_uri $cache {
    ~\.mp4(\?.*)?$  disk_cache;
    ~\.avi(\?.*)?$  disk_cache;

    default ssd_cache;
}

server {
    # select the cache based on the URI
    proxy_cache $cache;
      ...
}
				

Debugging the Cache

The cache server


				http {
    ...
    server {
    error_log /path2/to/log debug;
    ...
    }
}
			

The connection from the load balancer


...
events {
    debug_connection 192.168.1.1;
    debug_connection 192.168.10.0/24;
}
			
Documentation: Debugging NGINX

Extended Status

Leverage the status module to view cache stats

Lab 2.1: Load Generator

  1. Open a new shell on your local computer. Don't perform the test on the same machine i.e. your ec2 instance
  2. Ensure you have
    ab
    or similar load generator
    
    		  			$ ab -V
    This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
    Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
    Licensed to The Apache Software Foundation, http://www.apache.org/
    
  3. Installation steps here, or use homebrew
    
    		$ -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    $ brew tap homebrew/dupes
    $ brew install homebrew/dupes/ab
    	
  4. If necessary, you may have to rehash path to your shell

Lab 2.2: Perform Benchmark Test

  1. Test WordPress server directly (no NGINX) using
    ab
    :
    
    		  		ab -c 10 -t 30 -k http://wordpress-backend-url/;
    		  	
  2. Comment out all
    proxy_cache
    directives in
    proxy.conf
  3. Test the NGINX Proxy (without caching)
    
    		  	ab -c 10 -t 30 -k http://frontend-nginx-url/;
    		  
  4. Compare the results, then enable caching and re-test
    
    		  	ab -c 10 -t 30 -k http://frontend-nginx-url/;
    		  

Managing Cached Content

Module Objectives

This module enables you to:

  • Identify where cache data is stored
  • Modify location (external disc, tmpfs etc.)
  • Purge cache entries
  • Load instrumented cache data

Persistent Cache

NGINX uses a persistent disk-based cache

Options:

  • Load cache data at startup
  • Prune the cache over time
  • Manually purge content entries

Identifying Location

  1. Set content path
  2. 
    		  	proxy_cache_path /var/cache/nginx keys_zone=one:10m levels=1:2 max_size=40m;
    		  
  3. Define cache key
  4. 
    		  	proxy_cache_key $scheme$host$request_uri;
    		  
  5. Get the content into the cache, then check md5
  6. 
    		  	$ echo -n "httplocalhost:8080/index.html" | md5sum
    6d91blec887b7965d6a926cff19379ba -
    		  
  7. Verify presence of content
  8. 
    		  	cat /var/cache/nginx/4/9b/6d91blec887b7965d6a926cff19379ba
    		  

Lab 3: Map Files to Disc

  1. Map content to disc by using
    echo
    or a
    curl
    command
  2. 
    		  		$ echo -n "httplocalhost/" | md5sum
    $ curl -I http://localhost/
    		  	
  3. Verify the content is now in the cache directory
  4. 
    		    	$ cat /data/nginx/cache/<last 3>/<char of>/<md5 string>
    #example
    $ cd /data/nginx/cache/5/46/
    $ ls
    f7fbc9561a3975ce1ecff55583e50465
    
    
  5. Restart NGINX
  6. 
    		  		$ nginx -s reload

Load Previous Instrumentation


		proxy_cache_path /data/nginx/cache keys_zone=one:10m 
loader_files=100;
loader_threshold=200 
loader_sleeps=50;
			
  • Loads files in blocks of 100
  • Takes no longer than 200ms
  • Pauses for 50ms, then repeats

Pruning the Cache

The Cache Manager is a background process that operates based on:

  • inactive
    parameter
  • max_size
    parameter

				proxy_cache_path /path/to/cache keys_zone=name:size levels=1:2
inactive=time
max_size=size;
			

Lab 4.1: Load Cache Data

  1. Stop Nginx by running:
  2. 
    		  		$ nginx -s stop
  3. Use the
    loader_files
    and
    loader_threshold
    to load previous cache data
  4. 
    		    	proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=wordpress_cache:20m 
    	inactive=5m loader_files=100 loader_threshold=200;
    
  5. Restart NGINX
  6. 
    		  		$ nginx -s reload
  7. Check cache capacity in the
    status.html
    page
  8. Run a
    curl
    request to see if there is a
    HIT

Mounting to
tmpfs

  1. Create a mount point
  2. 
    $ mount -t tmpfs -o size=2G tmpfs /var/cache/nginx
    
    
  3. Match the cache directory in
    proxy_cache_path
    or
    fastcgi_cache_path
  4. 
    http {
        proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=one:10m;
        fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=one:10m;
    ...
    }
    
  5. Test the RAM directory
  6. 
    $ df -ah | grep tmpfs
    tmpfs 2.0G 29M 1996M 1% /var/cache/nginx
    		  	

proxy_cache_purge
Directive

Allows you to remove full cache entries that match a configured value.


		server {
    proxy_cache myCache;
    proxy_pass http://localhost:8081;
    proxy_cache_purge $purge_method;
}

Purge Methods

Partial Purge

  • use
    curl
    command to send
    PURGE HTTP
    request,
    map
    evaluates request and enables the directive

Full Purge

  • turn
    purger
    parameter on in the
    proxy_cache_path
    , all wildcard pages will also be purged

HTTP PURGE Example

Request:

$ curl –X PURGE –D – “http://www.mysite.com"


		# setting the default purge method will only delete matching URLs.
map $request_method $purge_method {
    PURGE 1;
    default 0;
	}
server {
    listen 80;
    server_name www.mysite.com
    proxy_cache myCache;
    proxy_pass http://localhost:8081;
    proxy_cache_purge $purge_method;
}

	

purger
Example

Request:

$ curl –X PURGE –D – “http://www.mysite.com/*"


		proxy_cache_path /data/nginx/cache levels=1:2 keys=myCache:10m purger=on;

server {
    listen 80;
    server_name www.mysite.com;
    location / {

        proxy_cache_purge $purge_method;
    }
}

	

Lab 4.2: Configure Cache Purge

  1. Open
    proxy.conf
    and create the following
    map
    :
  2. 
    map $request_method $purge_method {
    	default  0;
    	PURGE    1;
    }
    	
  3. Specify the
    proxy_cache_purge
    directive
  4. 
    location / {
    	proxy_cache_purge $purge_method;
    	...
    	proxy_cache wordpress_cache;
    }
    	
  5. Save and reload NGINX
  6. Send the
    curl
    command using
    PURGE
  7. 
    $ curl –X PURGE –I http://localhost/
    

exprires
Directive

Expires
and
Cache-Control
response header modification


			map $sent_http_content_type $expires {
    
    default                  off;
    application/pdf          42d;
    ~image/                  max;
    css/javascript           modified +24h;
    text/html                epoch;
}

expires $expires;

Cache Tuning

Module Objectives

This module enables you to:

  • Interpret and modify headers
  • Configure caching resources
  • Bypass cache tier

Header Interpretation

Example 1


		location /images/ {
    proxy_cache my_cache;
    proxy_ignore_headers Cache-Control;
    proxy_cache_valid any 30m;
    ...
}
	

Example 2


		location /images/ {
    proxy_cache my_cache;
    add_header Cache-Control public;
    ...
}
	
Warning!: add_header Pitfall!

Caching Resources

Directives that control cached responses:

  • proxy_cache_min_uses
  • proxy_cache_methods

Caching limit rates:

  • proxy_cache_bypass
  • proxy_no_cache

Documentation: Cache Admin Guide

proxy_cache_min_uses


		server {
    proxy_cache myCache;
    proxy_pass http://localhost:8081;
    proxy_cache_min_uses 5;
}

proxy_cache_methods

Syntax:

proxy_cache_methods $request_method


map $request_method $cache_method {
	default 0;
	GET     1;
	POST    1;
	HEAD    1;
	PUT     0;
}

server {
	proxy_cache_methods $cache_method;
	proxy_cache my_cache;
	proxy_cache valid any 4s;
	proxy_pass http://localhost:8080/;
}

proxy_cache_bypass


		  			proxy_cache_bypass $cookie_nocache $http_pragma $http_authroization;
		  		

proxy_cache_no_cache

Syntax:

proxy_no_cache $arg$arg_comment


	map $request_uri $no_cache;
    /default	0;
    /test       1;

server {
    proxy_cache_methods GET HEAD POST;
    proxy_cache my_cache;
    proxy_cache_valid any 10m;
    proxy_no_cache $no_cache;
    proxy_pass http://localhost:8080/;
}

proxy_cache_use_stale


		location / {
    ...
    proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
}
	

proxy_cache_revalidate


location / {
    proxy_cache my_cache;
    proxy_cache_min_uses 3;
    proxy_cache_use_stale error http_500 http_503 http_502;
    proxy_cache_revalidate on;

    proxy_pass http://myUpstream/;
}
	

proxy_cache_lock


location / {
    proxy_cache my_cache;
    proxy_cache_min_uses 3;
    proxy_cache_use_stale error http_500 http_503 http_502;
    proxy_cache_revalidate on;

    proxy_cache_lock on;
    proxy_pass http://myUpstream/;
}
	

SwR/SiE

Origin Servers


		Cache-Control: max-age=3600 stale-while-revalidate=120 stale-if-error=900
	

NGINX Servers


		proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m 
		max_size=10g inactive=60m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_cache_use_stale updating;
        proxy_cache_background_update on;
        proxy_pass http://my_upstream;
    }
}
	

Cache-Control Review

  • proxy_cache_valid
  • proxy_cache_bypass
  • proxy_no_cache
  • Cache-Control public

Lab 5.1: Set Cache Params

  1. Create a separate conf file called
    cache.params.conf
  2. Transfer all cache details at
    server
    and
    http
    contexts

		  		proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=wordpress_cache:20m inactive=5m loader_files=100 loader_threshold=200;

map $remote_addr $cache_status {
    127.0.0.1   $upstream_cache_status;
    default         "";
}

map $request_method $purge_method {
    default  0;
    PURGE    1;
}

proxy_cache_key $scheme$host$request_uri;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    add_header X-Cache-Status $cache_status;
		  	

Lab 5.2: Set Reference Cache Params

  1. Add one
    map
    that bypasses the cache based on
    $status
    and a custom variable called
    $do_not_cache
    , and another based on
    $content_type
    with
    $expires
  2. Open
    proxy.conf
    and add the following:
  3. 
    	proxy_cache_bypass $do_not_cache;
    proxy_cache_methods GET HEAD POST;
    expires $expires;
    

Cache Scaling

Module Objectives

This module enables you to:

  • Enable microcaching
  • Create and Deploy Cache Placement Strategies
  • Optimize read and write operations
  • Create high-capacity/highly-available caches

Microcaching

Benefits:

  • Improves web performance
  • Reduces load on origin servers

Drawbacks:

  • Depends on cacheability of content
  • Spike on origin server after entry expires

Microcaching Scenarios

  • Front page of busy blog or news site
  • RSS feed of recent information
  • Status page of a CI build platform
  • Calendar data
  • Personalized dynamic content on client side

Microcaching Example


proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;
server {
    listen external-ip:80;  # External IP address
    proxy_cache cache;
    proxy_cace_valid 200 1s;
    status_zone wordpress; # NGINX Plus status monitoring

    location / {
        proxy_http_version 1.1; # Always upgrade to HTTP/1.1
        proxy_set_header Connection ""; # Enable keepalives
        proxy_set_header Accept-Encoding ""; # Optimize encoding
        proxy_pass http://wordpress-upstreams;
    }
}

upstream wordpress-upstreams {
    zone wordpress 128k;
    keepalive 20; # Keepalive pool to upstream
    server localhost:80;
}

	

Lab 6.1 Microcaching

  1. Open
    proxy.conf
    and change the
    proxy_cache_valid
    directive value to
    1s
  2. Save and reload NGINX, and re-run your
    ab
    test
    
    		ab -c 10 -t 30 -k http://frontend-nginx-url/;
    	
  3. Take a look at the status dashboard
  4. There should be increase in connections received, but also notice the spike in 3xx codes every so often?

Lab 6.2 Microcaching

  1. Add the following to the
    server
    context:
    
    		  		server {
        listen 80;
        ...
        proxy_cache_bypass 404 403 500 503 502;
        expires $expires;
    	...
        proxy_cache_revalidate on;
        proxy_cache_lock on;
    
    }
    		  	
  2. Save and Reload NGINX, then re-run the
    ab
    test. Notice a difference?

Cache Placement Strategies

  • Single Disk
  • Mirror
  • Stripe
  • Hash

Single Disk


		proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;

		server {
		...
		proxy_cache cache
		proxy_cache valid 200 15s;
	}
	

Mirror


		$ lvcreate -L 50G -m1 -n mirrorlv vg0
	

Documentation: Create Mirrored Volume

Stripe


		$ lvcreate -i3 -I4 -L1G -nmy_logical_volume my_volume_group
lvcreate -- rounding 1048576 KB to stripe boundary size 1056768 KB / 258 PE
	

Documentation: Create Striped Logical Volume

Hash


		proxy_cache_path /mnt/disk1/cache keys_zone=disk1:100m levels=1:2 inactive=600s
                 max_size=5G use_temp_path=off;
proxy_cache_path /mnt/disk2/cache keys_zone=disk2:100m levels=1:2 inactive=600s
                 max_size=5G use_temp_path=off;

split_clients $request_uri $cache {
    50%     disk1;
    *       disk2;
}

server {
    listen localhost:80;
    proxy_cache $cache;
    status_zone loadbalancer;
...
}
	

Testing Placement Strategies

  • Use
    iostat
    to monitor I/O on individual disks
  • Test both cloud and bare-metal servers
  • Make sure caches are flushed and empty before each test run

Documentation: Cache Placement Strategy

Optimizing Read Operations

  • aio
  • directio
  • thread_pools

Async I/O


		thread_pool io_pool threads=16;
http{
….....
   location /data{
     sendfile   on;
     aio       threads=io_pool;
   }
}
	

Blocking Operations

thread_pools

Byte Range Requests

Problem: Subsequent requests spawn new cache-fill operations during long cache-fill.

Solution: Cache lock or slicing

Lock a Single Fill


		proxy_cache_path /tmp/mycache keys_zone=mycache:10m;

server {
    listen 80;

    proxy_cache mycache;
    proxy_cache_valid 200 600s;
    proxy_cache_lock on;

    # Immediately forward requests to the origin if we are filling the cache
    proxy_cache_lock_timeout 0s;

    # Set the 'age' to a value larger than the expected fill time
    proxy_cache_lock_age 200s;

    proxy_cache_use_stale updating;

    location / {
        proxy_pass http://origin:80;
    }
}
	

Slice-by-Slice

Use the Cache Slice module to optimize bandwidth during long cache-fill operations

slice
Example


	proxy_cache_path /tmp/mycache keys_zone=mycache:10m;

server {
    listen 80;

    proxy_cache mycache;

    slice              1m;
    proxy_cache_key    $host$uri$is_args$args$slice_range;
    proxy_set_header   Range $slice_range;
    proxy_http_version 1.1;
    proxy_cache_valid  200 206 1h;

    location / {
        proxy_pass http://origin:80;
    }
}

Splitting Across Disks


	proxy_cache_path /path/to/hdd1 levels=1:2 keys_zone=my_cache_hdd1:10m
                 max_size=10g inactive=60m use_temp_path=off;
proxy_cache_path /path/to/hdd2 levels=1:2 keys_zone=my_cache_hdd2:10m
                 max_size=10g inactive=60m use_temp_path=off;

split_clients $request_uri $my_cache {
              50%          “my_cache_hdd1”;
              50%          “my_cache_hdd2”;
}

server {
    ...
    location / {
        proxy_cache $my_cache;
        proxy_pass http://my_upstream;
    }
}
	

Lab 7.1: Split Across Directories

  1. Create two cache directories to emulate hard disks
  2. 
    		  	$ sudo mkdir -p /data/nginx/cache1 /data/nginx/cache2
    		  
  3. Setup
    proxy_cache_path
    directives for each directory
  4. Use
    split_clients
    to spread cache writes
  5. 
    		  	split_clients $request_uri $cache_dir {
        		50%         "cache1";
        		*           "cache2";
    }
    ...
    proxy_cache $cache_dir;
    		  
  6. Run the following dynamic
    curl
    request
  7. 
    $ for i in `seq 1 100` ; do curl -s -o /dev/null -w "%{http_code}" http://<ec2-hostname>/\?$i ; done
    		  
  8. Run
    top
    or check the status page

Cache Clusters

High Cacpacity

  • Sharded Cache
  • "Hot" level Cache

High Availability:

  • Shared Cache
    • keepalived (VRRP)
    • All-Active GCE

No Shared Disk?

NGINX Plus is sensitive to disk latency, potentially overwhelmed by thread volumes, and requires cluster-wide locks that could result in overlapping cache operations

Sharded Cache

Primary Use Cases:

  • High Capacity—partitioned across multiple servers
  • High Performance—minimizes origin server load

Fault Tolerance Scenarios

One node fails, only 1/N cached data is 'lost'. New nodes automatically partition entries

Consistent Hashing


		upstream cache-servers {
	hash $scheme$proxy_host$request_uri consistent;

	server cache-server1;
	server cache-server2;
	server cache-server3;
}
	

Combining LB and Cache Tiers

"Hot" Cache

Demo 7.1: Setting up the Cache Tier

Prerequisites

  • Load Balancer with NGINX Plus
  • Application Server (origin)
  • At least two NGINX Plus Cache Servers
    • Extended Status enabled to see the cache fill

Demo 7.2: Sharding the Cache

  1. Enable
    consistent hash
    on the cache upstream
  2. Make dynamic requests to spread across nodes
  3. Stop NGINX processes on one of the cache servers, note that server responses are still sent from the second cache

High Availability Cache

Primary Cache


		proxy_cache_path /tmp/mycache keys_zone=mycache:10m;
server {
    status_zone mycache;          # for NGINX Plus status dashboard
    listen 80;
    proxy_cache mycache;
    proxy_cache_valid 200 15s;

    location / {
        proxy_pass http://secondary;
    }
}

upstream secondary {
    zone secondary 128k;          # for NGINX Plus status dashboard
    server 192.168.56.11;         # secondary
    server 192.168.56.12 backup;  # origin
}
	

Secondary Cache


		proxy_cache_path /tmp/mycache keys_zone=mycache:10m;
server {
    status_zone mycache;          # for NGINX Plus status dashboard
    listen 80;
    proxy_cache mycache;
    proxy_cache_valid 200 15s;

    location / {
        proxy_pass http://origin;
    }
}

upstream origin {
    zone origin 128k;            # for NGINX Plus status dashboard
    server 192.168.56.12;        # origin
}
	

GCE HA Solution

Advantages:

  1. Detects changes
  2. Active checking
  3. Automatic recovery

Deployment Guide: All-Active GCE Load Balancer

Demo 8.1: HA Shared Cache

Failover Scenenarios

Demo 8.2: Testing Failover

  1. Configure origin server
  2. 
    		  	access_log /var/log/nginx/access.log;
    location / {
        return 200 "It's now $time_local\n";
    }
    		  
  3. Configure cache validation
  4. 
    		  proxy_cache_valid 200 15s;
    		  
  5. Verify cache behavor
  6. 
    		  $ while sleep 1 ; do curl http://<external frontend lb ip>/ ; done
    		
  7. Verfiy failover behavior (2nd scenario)
  8. 
    		  $ nginx -s stop
    # Inspect log on origin server
    tail -f /var/log/nginx/access.log
    		 

Timing Cache Updates

expires
headers that are shared by mutliple instances, could result in time stamp mismatch. It's recommended to shorten the cache timeout on the secondary server

nginx-sync

Share configurations in an HA cluster

Documentation: nginx-sync

Additional Resources

Further Information

  • NGINX Documentation
  • NGINX Admin Guides
  • NGINX Blog
  • Q&A

  • Survey!
  • Sales: nginx-inquiries@nginx.com