$30 off During Our Annual Pro Sale. View Details »

C.R.E.A.M. (Cache Rules Everything Around Me) - TEK13

C.R.E.A.M. (Cache Rules Everything Around Me) - TEK13

Slides for my Cache Rules Everything Around Me talk at TEK13 in Chicago

Thijs Feryn

May 16, 2013
Tweet

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. C.R.E.A.M
    CASH RULES EVERYTHING
    AROUND ME
    CACHE
    Thijs Feryn

    View Slide

  2. Hi#
    my#name#
    is#Thijs

    View Slide

  3. I’m#
    an#evangelist#at

    View Slide

  4. I’m#
    a#board#member#
    at

    View Slide

  5. View Slide

  6. View Slide

  7. Old school
    Don’t#
    store#anything#
    you#can#
    recalculate

    View Slide

  8. Old school
    Store/cache
    to avoid
    recalculation

    View Slide

  9. Protect your
    infrastructure

    View Slide

  10. Responsibilities

    View Slide

  11. Tear down silos

    View Slide

  12. Fundamentals

    View Slide

  13. View Slide

  14. Browser#cache
    Page#cache
    Internal#data#cache
    Opcode#cache

    View Slide

  15. View Slide

  16. Cache@control
    Cache&Control,“max&age=3600,,s&
    maxage=1000,,public,,must&revalidate”

    View Slide

  17. Expires
    Expires,"Wed,,1,Jan,2014,20:00:00,GMT"

    View Slide

  18. ETag
    If&None&Match:,"3e86&410&3596Obc"
    ETag:,"3e86&410&3596Obc"

    View Slide

  19. Problems

    View Slide

  20. View Slide

  21. Lexing
    Source,
    to,tokens
    Tokenizing
    Interpre4ng,
    tokens
    Compiling
    Generate,
    byte,code
    Execu4on
    Run,
    byte,code

    View Slide

  22. Lexing
    Tokenizing
    Compiling
    Cache,
    byte,code
    Execu4on
    Run,
    byte,code
    Opcode,caching

    View Slide

  23. Zend#Optimizer#(plus)
    Eaccelerator
    XCache
    APC

    View Slide

  24. View Slide

  25. Which direction
    are we heading?

    View Slide

  26. Zend Optimizer +
    APCu
    https://github.com/zend-dev/ZendOptimizerPlus
    https://github.com/krakjoe/apcu

    View Slide

  27. Caching internal data

    View Slide

  28. Compensate for expensive calls
    ✓RDBMS
    ✓Webservice
    ✓Feed
    ✓Other external resource

    View Slide

  29. APC
    User%
    func*ons

    View Slide

  30. apc_add('key1','This is key1', 10);
    apc_add('key2','This is key2');
    apc_add('key3',2);
    apc_delete('key2');
    apc_store('key2','bla',12);
    var_dump(
    apc_exists('key1'),
    apc_exists(array('key2','key3')),
    apc_inc('key3'),
    apc_dec('key3',12),
    apc_fetch('key1'),
    apc_clear_cache('user'),
    apc_fetch('key1')
    );

    View Slide

  31. var_dump(apc_sma_info());
    array(4) {
    ["num_seg"]=>
    int(1)
    ["seg_size"]=>
    float(33554352)
    ["avail_mem"]=>
    float(29335064)
    ["block_lists"]=>
    array(1) {
    [0]=>
    array(1) {
    [0]=>
    array(2) {
    ["size"]=>
    int(29335040)
    ["offset"]=>
    int(4219344)
    }
    }
    }
    }

    View Slide

  32. Memcached

    View Slide

  33. Memcached
    ✓Key value store
    ✓Distributed cache
    ✓Over TCP/IP
    ✓Stored in memory
    ✓Fast
    ✓Client-side intelligence

    View Slide

  34. try{
    $m = new Memcached();
    $m->addServer('localhost',11211);
    if($m->add('key1','value1',10) === false){
    throw new Exception($m->getResultMessage());
    }
    if($m->set('key2','value2',10) === false){
    throw new Exception($m->getResultMessage());
    }
    if($m-
    >setMulti(array('key3'=>'value3','key4'=>'value4'),
    10) === false){
    throw new Exception($m->getResultMessage());
    }
    } catch(Exception $e) {
    echo "Error: ".$e.PHP_EOL;
    }
    Create

    View Slide

  35. $m = new Memcached();
    $m->addServer('localhost',11211);
    $value1 = $m->get('key1');
    $result = $m->getMulti(array('key2','key3','key4'));
    var_dump($value1,$result);
    Retrieve

    View Slide

  36. try{
    $m = new Memcached();
    $m->addServer('localhost',11211);
    if($m->set('key1','value1',10) === false){
    throw new Exception($m->getResultMessage());
    }
    if($m->replace('key1','azerty',10) === false){
    throw new Exception($m->getResultMessage());
    }
    if($m-
    >setMulti(array('key1'=>'value1','key2'=>'value2'),
    10) === false){
    throw new Exception($m->getResultMessage());
    }
    } catch(Exception $e) {
    echo "Error: ".$e.PHP_EOL;
    }
    Update

    View Slide

  37. try{
    $m = new Memcached();
    $m->addServer('localhost',11211);
    if($m->delete('key1') === false){
    throw new Exception($m->getResultMessage());
    }
    if($m-
    >deleteMulti(array('key2','key3','key4')) === false){
    throw new Exception($m->getResultMessage());
    }
    } catch(Exception $e) {
    echo "Error: ".$e.PHP_EOL;
    }
    Delete

    View Slide

  38. $m = new Memcached();
    //$m-
    >setOption(Memcached::OPT_DISTRIBUTION,Memcached::DISTRIBUTION_CONSISTENT);
    $m->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE,true);
    $servers = array(
    array('localhost', 11211),
    array('localhost', 11212),
    array('localhost', 11213)
    );
    $m->addServers($servers);
    for($i=0; $i<10;$i++){
    if(($value = $m->get($i)) === false){
    $value = date('Y-m-d H:i:s');
    $m->set($i, $value);
    echo "$i not in cache, setting to $value
    >".PHP_EOL;
    echo "Error: ".$m->getResultMessage()." (".$m->getResultCode().")>".PHP_EOL;
    } else {
    echo "Value for $i: $value
    ".PHP_EOL;
    }
    }
    High availability

    View Slide

  39. Memcached
    memcached.sess_prefix = "memc.sess.key."
    session.save_path="127.0.0.1:11211"
    session.save_handler = memcached
    Also,
    for,session,
    handling

    View Slide

  40. View Slide

  41. ✓Just like Memcached
    ✓Replication
    ✓Disk persistence
    ✓Data structures
    ✓Transactions
    ✓More partitioning options
    ✓PubSub

    View Slide

  42. Keys
    require __DIR__.'/autoload.php';
    $server = array('host'=> '127.0.0.1','port'=> 6379,
    'database' => 0);
    $client = new Predis\Client($server);
    $client->flushdb();
    $client->set('key1', 'This is key1');
    $client->expire('key1',10);
    $client->expire('key2',10);
    $client->set('key2', 'This is key2');
    $client->persist('key2');
    $client->set('key3', 'This is key3');
    $client->del('key3');
    $client->rename('key2','key3');
    var_dump(
    $client->keys('k*'),
    $client->get('key1'),
    $client->exists('key3'),
    $client->ttl('key1'),
    $client->type('key1')
    );

    View Slide

  43. Strings
    require __DIR__.'/autoload.php';
    $server = array('host'=> '127.0.0.1','port'=> 6379,
    'database' => 0);
    $client = new Predis\Client($server);
    $client->flushdb();
    $client->set('key1', 'This is key1');
    $client->setex('key2', 10, 'This is key2');
    $client->set('key3', 1);
    $client->incr('key3');
    $client->incrby('key3',2);
    $client-
    >mset('key4','This is key4','key5','This is key5');
    var_dump(
    $client->strlen('key1'),
    $client->ttl('key2'),
    $client->getset('key1','New value for key1'),
    $client->get('key1'),
    $client->mget('key4','key5')
    );

    View Slide

  44. Hashes
    require __DIR__.'/autoload.php';
    $server = array('host'=> '127.0.0.1','port'=> 6379,'data
    base' => 0);
    $client = new Predis\Client($server);
    $client->flushdb();
    $client->hset('hash1', 'name', 'Name for hash1');
    $client->hmset('hash1', 'id', 1, 'status','ok');
    $client->hset('hash2', 'name', 'Name for hash2');
    $client->hsetnx('hash2', 'id', 1);
    $client->hincrby('hash3','id',1);
    $client->hset('hash2', 'bla', 'bla');
    $client->hdel('hash2','bla');
    var_dump(
    $client->hexists('hash1','id'),
    $client->hget('hash1','id'),
    $client->hgetall('hash1'),
    $client->hkeys('hash2'),
    $client->hvals('hash2'),
    $client->hlen('hash2'),
    $client->hmget('hash1','id','name')
    );

    View Slide

  45. Lists
    require __DIR__.'/autoload.php';
    $server = array('host'=> '127.0.0.1','port'=> 6379,
    'database' => 0);
    $client = new Predis\Client($server);
    $client->flushdb();
    $client->rpush('list1', 'b', 'c', 'e','f','g');
    $client->lpush('list1','a');
    $client->linsert('list1','BEFORE','e','d');
    $client->ltrim('list1',0,2);
    var_dump(
    $client->lindex('list1',0),
    $client->llen('list1'),
    $client->lpop('list1'),
    $client->lrange('list1',0,2)
    );

    View Slide

  46. Sets
    require __DIR__.'/autoload.php';
    $server = array('host'=> '127.0.0.1','port'=> 6379
    ,'database' => 0);
    $client = new Predis\Client($server);
    $client->flushdb();
    $client->sadd('set1','a','b','c',3,5,1);
    $client->sadd('set2',0,1,2);
    $client->smove('set1','set2',3);
    $client->srem('set1',5);
    var_dump(
    $client->scard('set1'),
    $client->smembers('set1'),
    $client->sismember('set1','f'),
    $client->srandmember('set1',2),
    $client->sinter('set1','set2'),
    $client->sdiff('set1','set2'),
    $client->sunion('set1','set2')
    );

    View Slide

  47. session.save_handler = redis
    session.save_path = "tcp://host1:6379?
    weight=1, tcp://host2:6379?
    weight=2&timeout=2.5, tcp://host3:6379?
    weight=2"
    Also,
    for,session,
    handling
    Requires,
    phpredis,PECL,
    module

    View Slide

  48. Page caching

    View Slide

  49. RewriteEngine*On
    RewriteCond*%{REQUEST_FILENAME}*=s*[OR]
    RewriteCond*%{REQUEST_FILENAME}*=l*[OR]
    RewriteCond*%{REQUEST_FILENAME}*=d
    RewriteRule*^.*$*=*[NC,L]
    RewriteRule*^.*$*index.php*[NC,L]
    Apache#
    mod_rewrite

    View Slide

  50. " location / {
    try_files $uri $uri/ /index.php;
    }
    Nginx

    View Slide

  51. require('db.php');
    $data = db_get_content_from_uri(
    $_SERVER['REQUEST_URI']);
    $fp = fopen(dirname(__FILE__).
    $_SERVER['REQUEST_URI'], 'w');
    fwrite($fp, $data);
    fclose($fp);
    echo $data;
    Write#to#file#
    print

    View Slide

  52. [PHP]
    auto_prepend_file*“/path/to/prepend.php”
    auto_append_file*“/path/to/append.php”
    Auto#
    execute#before#
    after#each#
    script

    View Slide

  53. if($_SERVER['REQUEST_METHOD'] == 'GET'){
    $key = md5('http://'.$_SERVER['HTTP_HOST'].
    $_SERVER['REQUEST_URI']);
    if(($output = apc_fetch($key)) !== false){
    echo $output;
    exit();
    }
    ob_start();
    }
    Prepend

    View Slide

  54. if($_SERVER['REQUEST_METHOD'] == 'GET'){
    $output = ob_get_contents();
    ob_end_clean();
    $key = md5('http://'.$_SERVER['HTTP_HOST'].
    $_SERVER['REQUEST_URI']);
    apc_store($key,$output,20);
    echo $output;
    }
    Append

    View Slide

  55. File
    MySQL
    APC
    Memcached
    Redis

    View Slide

  56. Avoid#slow#
    parts#of#your#PHP#
    application

    View Slide

  57. Avoid#
    PHP#runtime#
    entirely

    View Slide

  58. Reverse proxy

    View Slide

  59. Varnish

    View Slide

  60. backend(default({
    ((((((.host(=("127.0.0.1";
    ((((((.port(=("8080";
    }
    In#“/etc/varnish/default.vcl”
    Backend

    View Slide

  61. Out of the box

    View Slide

  62. Only get & HEAD
    No cookie & auth headers
    No set-cookie headers
    cache ttl > 0
    No vary “*”
    When will varnish cache?

    View Slide

  63. Request vcl_recv
    In cache?
    vcl_hash Cacheable?
    vcl_hit() vcl_miss()
    vcl_deliver()
    vcl_fetch()
    No
    Yes
    No
    Yes
    Response

    View Slide

  64. sub vcl_recv {
    if (req.restarts == 0) {
    if (req.http.x-forwarded-for) {
    set req.http.X-Forwarded-For =
    req.http.X-Forwarded-For + “, ” + client.ip;
    } else {
    set req.http.X-Forwarded-For = client.ip;
    }
    }
    if (req.request != “GET” &&
    req.request != “HEAD” &&
    req.request != “PUT” &&
    req.request != “POST” &&
    req.request != “TRACE” &&
    req.request != “OPTIONS” &&
    req.request != “DELETE”) {
    /* Non-RFC2616 or CONNECT which is weird. */
    return (pipe);
    }
    if (req.request != “GET” && req.request != “HEAD”) {
    /* We only deal with GET and HEAD by default */
    return (pass);
    }
    if (req.http.Authorization || req.http.Cookie) {
    /* Not cacheable by default */
    return (pass);
    }
    return (lookup);
    }

    View Slide

  65. sub vcl_pipe {
    # Note that only the first request to the backend will have
    # X-Forwarded-For set. If you use X-Forwarded-For and want to
    # have it set for all requests, make sure to have:
    # set bereq.http.connection = "close";
    # here. It is not set by default as it might break some broken web
    # applications, like IIS with NTLM authentication.
    return (pipe);
    }
    sub vcl_pass {
    return (pass);
    }
    sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
    hash_data(req.http.host);
    } else {
    hash_data(server.ip);
    }
    return (hash);
    }

    View Slide

  66. sub vcl_hit {
    return (deliver);
    }
    sub vcl_miss {
    return (fetch);
    }
    sub vcl_fetch {
    if (beresp.ttl <= 0s ||
    beresp.http.Set-Cookie ||
    beresp.http.Vary == "*") {
    " " /*
    " " * Mark as "Hit-For-Pass" for the next 2 minutes
    " " */
    " " set beresp.ttl = 120 s;
    " " return (hit_for_pass);
    }
    return (deliver);
    }
    sub vcl_deliver {
    return (deliver);
    }

    View Slide

  67. sub vcl_error {
    set obj.http.Content-Type = "text/html; charset=utf-8";
    set obj.http.Retry-After = "5";
    synthetic {"

    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">


    "} + obj.status + " " + obj.response + {"


    Error "} + obj.status + " " + obj.response + {"
    "} + obj.response + {"
    Guru Meditation:
    XID: "} + req.xid + {"

    Varnish cache server


    "};
    return (deliver);
    }
    sub vcl_init {
    " return (ok);
    }
    sub vcl_fini {
    " return (ok);
    }

    View Slide

  68. Monitoring
    &
    Logging

    View Slide

  69. Varnishstat

    View Slide

  70. 4+05:26:25
    Hitrate*ratio:*******10******100******254
    Hitrate*avg:*****0.8486***0.7619***0.7285
    *****1760818*********6.99*********4.82*client_conn*=*Client*connections*accepted
    ****11088687********25.96********30.36*client_req*=*Client*requests*received
    *****8042715********11.98********22.02*cache_hit*=*Cache*hits
    *****2609561********11.98*********7.15*cache_miss*=*Cache*misses
    *******47104*********1.00*********0.13*backend_conn*=*Backend*conn.*success
    *********610*********0.00*********0.00*backend_fail*=*Backend*conn.*failures
    *****2998265********12.98*********8.21*backend_reuse*=*Backend*conn.*reuses
    *******12081*********0.00*********0.03*backend_toolate*=*Backend*conn.*was*closed
    *****3010356********13.98*********8.24*backend_recycle*=*Backend*conn.*recycles
    **********13*********0.00*********0.00*backend_retry*=*Backend*conn.*retry
    *********520*********0.00*********0.00*fetch_head*=*Fetch*head
    *****2857965********11.98*********7.83*fetch_length*=*Fetch*with*Length
    ******151309*********2.00*********0.41*fetch_chunked*=*Fetch*chunked
    ********4404*********0.00*********0.01*fetch_close*=*Fetch*wanted*close
    *********676*********0.00*********0.00*fetch_failed*=*Fetch*failed
    *******31164*********0.00*********0.09*fetch_304*=*Fetch*no*body*(304)
    *********220**********.************.***n_sess_mem*=*N*struct*sess_mem
    **********53**********.************.***n_sess*=*N*struct*sess
    *******29540**********.************.***n_object*=*N*struct*object
    *******29561**********.************.***n_objectcore*=*N*struct*objectcore
    ********5058**********.************.***n_objecthead*=*N*struct*objecthead
    ********2613**********.************.***n_waitinglist*=*N*struct*waitinglist
    ***********3**********.************.***n_vbc*=*N*struct*vbc
    **********22**********.************.***n_wrk*=*N*worker*threads
    ********1789*********0.00*********0.00*n_wrk_create*=*N*worker*threads*created

    View Slide

  71. Varnishlog

    View Slide

  72. ***11*SessionOpen**c*12.12.12.1*53727*:80
    ***11*ReqStart*****c*12.12.12.1*53727*1401010767
    ***11*RxRequest****c*GET
    ***11*RxURL********c*/
    ***11*RxProtocol***c*HTTP/1.1
    ***11*RxHeader*****c*Host:*12.12.12.6
    ***11*RxHeader*****c*User=Agent:*Mozilla/5.0*(Macintosh;*Intel*Mac*OS*X*10.8;*rv:17.0)*
    Gecko/20100101*Firefox/17.0
    ***11*RxHeader*****c*Accept:*text/html,application/xhtml+xml,application/xml;q=0.9,*/
    *;q=0.8
    ***11*RxHeader*****c*Accept=Language:*nl,en;q=0.7,fr=be;q=0.3
    ***11*RxHeader*****c*Accept=Encoding:*gzip,*deflate
    ***11*RxHeader*****c*Connection:*keep=alive
    ***11*VCL_call*****c*recv*lookup
    ***11*VCL_call*****c*hash
    ***11*Hash*********c*/
    ***11*Hash*********c*12.12.12.6
    ***11*VCL_return***c*hash
    ***11*VCL_call*****c*miss*fetch
    ***11*Backend******c*13*default*default
    ***11*TTL**********c*1401010767*RFC*0*=1*=1*1357920021*0*1357920020*0*0
    ***11*VCL_call*****c*fetch
    ***11*TTL**********c*1401010767*VCL*120*=1*=1*1357920021*=0
    ***11*VCL_return***c*hit_for_pass
    ***11*ObjProtocol**c*HTTP/1.1
    ***11*ObjResponse**c*OK
    ***11*ObjHeader****c*Date:*Fri,*11*Jan*2013*16:00:20*GMT
    ***11*ObjHeader****c*Server:*Apache
    ***11*ObjHeader****c*X=Powered=By:*PHP/5.3.2=1ubuntu4.18
    ***11*ObjHeader****c*Cache=Control:*no=cache,*no=store,*max=age=0
    Client%

    View Slide

  73. ***11*VCL_return***c*hit_for_pass
    ***11*ObjProtocol**c*HTTP/1.1
    ***11*ObjResponse**c*OK
    ***11*ObjHeader****c*Date:*Fri,*11*Jan*2013*16:00:20*GMT
    ***11*ObjHeader****c*Server:*Apache
    ***11*ObjHeader****c*X=Powered=By:*PHP/5.3.2=1ubuntu4.18
    ***11*ObjHeader****c*Cache=Control:*no=cache,*no=store,*max=age=0
    ***11*ObjHeader****c*Vary:*Accept=Encoding
    ***11*ObjHeader****c*Content=Encoding:*gzip
    ***11*ObjHeader****c*Content=Length:*119
    ***11*ObjHeader****c*Content=Type:*text/html
    ***11*Gzip*********c*u*F*=*119*336*80*80*887
    ***11*VCL_call*****c*deliver*deliver
    ***11*TxProtocol***c*HTTP/1.1
    ***11*TxStatus*****c*200
    ***11*TxResponse***c*OK
    ***11*TxHeader*****c*Server:*Apache
    ***11*TxHeader*****c*X=Powered=By:*PHP/5.3.2=1ubuntu4.18
    ***11*TxHeader*****c*Cache=Control:*no=cache,*no=store,*max=age=0
    ***11*TxHeader*****c*Vary:*Accept=Encoding
    ***11*TxHeader*****c*Content=Encoding:*gzip
    ***11*TxHeader*****c*Content=Type:*text/html
    ***11*TxHeader*****c*Content=Length:*119
    ***11*TxHeader*****c*Accept=Ranges:*bytes
    ***11*TxHeader*****c*Date:*Fri,*11*Jan*2013*16:00:20*GMT
    ***11*TxHeader*****c*X=Varnish:*1401010767
    ***11*TxHeader*****c*Age:*0
    ***11*TxHeader*****c*Via:*1.1*varnish
    ***11*TxHeader*****c*Connection:*keep=alive
    ***11*Length*******c*119
    ***11*ReqEnd*******c*1401010767*1357920020.712090731*1357920020.727306366*0.000087738*
    Client%

    View Slide

  74. ***13*BackendClose*=*default
    ***13*BackendOpen**b*default*127.0.0.1*51597*127.0.0.1*8080
    ***13*TxRequest****b*GET
    ***13*TxURL********b*/
    ***13*TxProtocol***b*HTTP/1.1
    ***13*TxHeader*****b*Host:*12.12.12.6
    ***13*TxHeader*****b*User=Agent:*Mozilla/5.0*(Macintosh;*Intel*Mac*OS*X*10.8;*rv:17.0)*
    Gecko/20100101*Firefox/17.0
    ***13*TxHeader*****b*Accept:*text/html,application/xhtml+xml,application/xml;q=0.9,*/
    *;q=0.8
    ***13*TxHeader*****b*Accept=Language:*nl,en;q=0.7,fr=be;q=0.3
    ***13*TxHeader*****b*X=Forwarded=For:*12.12.12.1
    ***13*TxHeader*****b*X=Varnish:*1401010767
    ***13*TxHeader*****b*Accept=Encoding:*gzip
    ***13*RxProtocol***b*HTTP/1.1
    ***13*RxStatus*****b*200
    ***13*RxResponse***b*OK
    ***13*RxHeader*****b*Date:*Fri,*11*Jan*2013*16:00:20*GMT
    ***13*RxHeader*****b*Server:*Apache
    ***13*RxHeader*****b*X=Powered=By:*PHP/5.3.2=1ubuntu4.18
    ***13*RxHeader*****b*Cache=Control:*no=cache,*no=store,*max=age=0
    ***13*RxHeader*****b*Vary:*Accept=Encoding
    ***13*RxHeader*****b*Content=Encoding:*gzip
    ***13*RxHeader*****b*Content=Length:*119
    ***13*RxHeader*****b*Content=Type:*text/html
    ***13*Fetch_Body***b*4(length)*cls*0*mklen*1
    ***13*Length*******b*119
    ***13*BackendReuse*b*default
    Backend%

    View Slide

  75. varnishlog -c -m VCL_call:hit | grep -i 'RxURL'
    Varnishlog
    varnishlog -b -i TxURL
    Hits Misses

    View Slide

  76. Cache,staWc,files
    sub*vcl_recv{
    **if((req.request*==*"GET"*||*
    req.request*==*"HEAD")*&&*req.url*~*"\.
    (png|gif|jpe?g|swf|css|js|html?|sstm)
    $"*){
    ******return(lookup);
    **}*else*{
    ******return(pass);
    **}
    }

    View Slide

  77. Custom,hit/miss,marker
    sub*vcl_deliver*{
    **if*(obj.hits*>*0)*{
    ****set*resp.http.X=Varnish=Cache*=*"HIT";
    **}
    **else*{
    ****set*resp.http.X=Varnish=Cache*=*"MISS";
    **}
    }

    View Slide

  78. Set,TTL
    sub*vcl_fetch*{
    ****if(req.url*~*"^/bla")*{
    ********set*beresp.ttl*=*10s;
    ****}*else*{
    ********set*beresp.ttl*=*3600s;
    ****}
    }

    View Slide

  79. Expiration
    1.Vcl (beresp.ttl)
    2.Cache-control s-maxage
    3.Cache-control max-age
    4.Expires

    View Slide

  80. Remove,client,cookies
    sub*vcl_recv*{
    ****unset*req.http.cookie;
    }
    Remove,server,cookies
    sub*vcl_fetch*{
    ****unset*beresp.http.set=cookie;
    }

    View Slide

  81. Remove,GA,cookies
    sub*vcl_recv*{
    if*(req.http.Cookie)*{
    ****set*req.http.Cookie*=*
    regsuball(req.http.Cookie,"(^|;*)**__utm.=[^;]+;?*
    *","\1");*
    ****if*(req.http.Cookie*==*"")*{
    ********remove*req.http.Cookie;
    ****}
    }

    View Slide

  82. Ignore,cookies
    sub*vcl_recv*{
    ***if*(req.request*==*"GET"*||*req.request*==*
    "HEAD")*{
    *****return*(lookup);
    ***}
    }
    Ignores%default%behaviour

    View Slide

  83. Add,cookies,to,hash
    sub*vcl_recv*{
    ***if*(req.request*==*"GET"*||*req.request*==*"HEAD")*{
    *****return*(lookup);
    ***}
    }
    sub*vcl_hash*{
    ****hash_data(req.http.cookie);
    }
    All%cookies

    View Slide

  84. Add#a#specific#cookie#to#hash
    sub*vcl_recv*{
    ***if*(!req.http.Cookie*~*"country")*{
    *******return(pass);
    ***}
    }
    sub*vcl_hash*{
    **if(req.http.Cookie*~*"country"){
    **********hash_data(regsuball(req.http.Cookie,*"^.+;?*?
    country=([a=zA=Z0=9]+)(*|;|*;).*$","\1"));
    **}
    }

    View Slide

  85. ✓Purge
    ✓Ban
    ✓Always,miss
    Cache,invalidaWon

    View Slide

  86. sub*vcl_recv*{
    ********if*(req.request*==*"PURGE")*{
    ****************return*(lookup);
    ********}
    }
    sub*vcl_hit*{
    ********if*(req.request*==*"PURGE")*{
    ****************purge;
    ****************error*200*"Purged";
    ********}
    }
    sub*vcl_miss*{
    ********if*(req.request*==*"PURGE")*{
    ****************error*404*"Not*in*cache";
    ********}
    }
    Purge
    HTTP%call%
    to%purge

    View Slide

  87. ✓Implement,in,your,CMS
    ✓HTTP,200,:,removed,from,cache
    ✓HTTP,404:,not,in,cache
    ✓Some,CMS,plugins,require,200,for,miss()
    Purge
    curl*=X*PURGE*http://varnish.dev/your=page

    View Slide

  88. sub*vcl_recv*{
    ********if*(req.request*==*"PURGE")*{
    ban("req.http.host*==*"*+*req.http.host*+*"*
    &&*req.url*==*"*+*req.url);
    error*200*"Banned";
    ********}
    }
    Ban
    sub*vcl_recv*{
    ********if*(req.request*==*"PURGE")*{
    ************ban("req.http.host*==*"*+*req.http.host*+*
    "*&&*req.url*~*"*+*req.url);
    error*200*"Banned";
    ********}
    }
    Ban%URL%
    pattern
    Ban%URL
    Name%
    doesn’t%
    matter

    View Slide

  89. sub*vcl_recv*{
    ********if*(req.request*==*"PURGE")*{
    ************ban("obj.http.x=host*==*"*+*req.http.host*+*
    "*&&*obj.http.x=url*==*"*+*req.url);
    ************error*200*"Banned";
    ********}
    }
    sub*vcl_fetch*{
    ********set*beresp.http.x=url*=*req.url;
    ********set*beresp.http.x=host*=*req.http.host;
    }
    sub*vcl_deliver*{
    ********unset*resp.http.x=url;
    ********unset*resp.http.x=host;
    }
    Smart,bans
    Ban%lurker%
    friendly

    View Slide

  90. sub*vcl_recv*{
    ********if*(req.request*==*"REFRESH")*{
    ****************set*req.request*=*"GET";
    ****************set*req.hash_always_miss*=*true;
    ********}
    }
    Refresh/always,miss

    View Slide

  91. Edge Side Includes

    View Slide

  92. header.php
    menu.php main.php
    footer.php
    TTL#5s
    No#caching
    TTL#10s
    TTL#2s

    View Slide




















  93. View Slide

  94. ESI#VCL
    sub$vcl_recv${
    $$$$set$req.http.Surrogate5Capability="key=ESI/1.0";
    }
    sub$vcl_fetch${
    $ if(beresp.http.Surrogate5Control~"ESI/1.0")${
    $$$$$$$$$unset$beresp.http.Surrogate5Control;
    $ $$$$set$beresp.do_esi=true;
    $$$$}
    }$

    View Slide

  95. View Slide

  96. proxy_cache_path /tmp/nginx/fastcgi_cache
    levels=1:2 keys_zone=my-cache:10m inactive=5m;
    Init%cache%
    files%(disk,%
    ramdisk)

    View Slide

  97. location / {
    proxy_pass http://localhost:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_cache my-cache;
    proxy_cache_key "$scheme$request_method$host
    $request_uri";
    proxy_cache_valid 200 302 60m;
    proxy_cache_valid 404 1m;
    }

    View Slide

  98. location ~ /purge(/.*) {
    proxy_cache_purge my-cache "$scheme
    $request_method$host$1";"
    }
    ✓Requires,ngx_cache_purge
    ✓Requires,separate,“purge”,URL,(buggy,behaviour)
    ✓https://github.com/FRiCKLE/ngx_cache_purge

    View Slide

  99. FPM
    hXp://www.php.net/manual/en/install.fpm.configura4on.php

    View Slide

  100. server {
    listen 80;
    root /var/www/;
    " location / {
    try_files $uri $uri/ /index.php;
    }
    location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME
    $request_filename;
    }"
    }

    View Slide

  101. fastcgi_cache_path /tmp/nginx/fastcgi_cache
    levels=1:2 keys_zone=my-cache:10m inactive=5m;
    Looks%
    familiar?

    View Slide

  102. location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_cache my-cache;
    fastcgi_cache_key "$scheme$request_method$host
    $request_uri";
    fastcgi_cache_valid 200 302 1h;
    fastcgi_cache_valid 301 1d;
    fastcgi_cache_valid any 1m;
    fastcgi_cache_min_uses 1;
    fastcgi_cache_use_stale error timeout
    invalid_header http_500;
    } FastCGI%
    cache%to%
    cache%zone

    View Slide

  103. location ~ /purge(/.*) {
    fastcgi_cache_purge my-cache "$scheme
    $request_method$host$1";"
    }
    Remember%
    this%one?

    View Slide

  104. View Slide

  105. upstream my_memcached {
    " server my.memcached.org:11211;
    " server my.other.memcached.org:11211;"
    }
    upstream my_fpm {
    " server my.fpm.org:9000;
    " server my.other.fpm.org:9000;"
    }
    Upstream%
    servers
    Loadbalancing

    View Slide

  106. location ~ \.php$ {
    set $memcached_key $request_uri;
    memcached_pass my_memcached;
    memcached_next_upstream not_found;
    default_type "text/html; charset=utf-8";
    error_page 404 405 502 = @php;
    }"
    location @php {
    default_type "text/html; charset=utf-8";
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass my_fpm;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME
    $request_filename;
    }

    View Slide

  107. $contents = date("Y-m-d H:i:s");
    $m = new Memcached();
    $m->addServer('localhost',11211);
    $m->set($_SERVER['REQUEST_URI'],
    $contents,3600);
    echo $contents;
    Save%to%
    Memcached%&%
    output

    View Slide

  108. And#
    on#that#
    bombshell#...

    View Slide

  109. View Slide

  110. Thanks

    View Slide