Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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. <?php 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') );
  2. <?php 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) } } } }
  3. <?php 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
  4. <?php $m = new Memcached(); $m->addServer('localhost',11211); $value1 = $m->get('key1'); $result

    = $m->getMulti(array('key2','key3','key4')); var_dump($value1,$result); Retrieve
  5. <?php 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
  6. <?php 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
  7. <?php $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 "<strong>$i</strong> not in cache, setting to $value <br / >".PHP_EOL; echo "Error: ".$m->getResultMessage()." (".$m->getResultCode().")<hr / >".PHP_EOL; } else { echo "Value for <strong>$i</strong>: $value <br />".PHP_EOL; } } High availability
  8. Keys <?php 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') );
  9. Strings <?php 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') );
  10. Hashes <?php 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') );
  11. Lists <?php 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) );
  12. Sets <?php 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') );
  13. <?php 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
  14. Only get & HEAD No cookie & auth headers No

    set-cookie headers cache ttl > 0 No vary “*” When will varnish cache?
  15. 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); }
  16. 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); }
  17. 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); }
  18. sub vcl_error { set obj.http.Content-Type = "text/html; charset=utf-8"; set obj.http.Retry-After

    = "5"; synthetic {" <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>"} + obj.status + " " + obj.response + {"</title> </head> <body> <h1>Error "} + obj.status + " " + obj.response + {"</h1> <p>"} + obj.response + {"</p> <h3>Guru Meditation:</h3> <p>XID: "} + req.xid + {"</p> <hr> <p>Varnish cache server</p> </body> </html> "}; return (deliver); } sub vcl_init { " return (ok); } sub vcl_fini { " return (ok); }
  19. 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
  20. ***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%
  21. ***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%
  22. ***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%
  23. 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
  24. <html> <body> <table> <tr> <td colspan="2" > <esi:include src="/header.php" />

    </td> </tr> <tr> <td><esi:include src="/menu.php" /></td> <td><esi:include src="/main.php" /></td> </tr> <tr> <td colspan="2" > <esi:include src="/footer.php" /> </td> </tr> </table> </body>
  25. 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; }
  26. 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
  27. 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; }" }
  28. 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
  29. 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
  30. 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; }
  31. <?php $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