Save 37% off PRO during our Black Friday Sale! »

Scalability Issues ... cure first, prevent later

Scalability Issues ... cure first, prevent later

Slides for the DPC12 edition of my scalability talk.

Ca901ddcea38854b9783781c91fc87c9?s=128

Thijs Feryn

June 09, 2012
Tweet

Transcript

  1. None
  2. Evangelist

  3. None
  4. None
  5. None
  6. @ThijsFeryn

  7. Please3 rate3my3talk3on3 Joind.in https://joind.in/6247

  8. It3works3on3my3computer

  9. None
  10. It’s3the3internet’s3fault

  11. Suits & hipsters

  12. “Isn't'hos*ng' supposed'to'be'a' bulk'product?”

  13. “The'Cloud'will' make'sure'my'app' scales”

  14. “Large'campaigns' on'shared'hos*ng,' why'is'that'a' problem?”

  15. “What's'a' database'index?”

  16. “We'll'solve'that' with'an'Ajax'call”

  17. “We'll'probably'have' 10.000'visitors'on' the'next'campaign”

  18. GeBng3the3numbers3right

  19. Let’s3do3a3complete3rewrite3!

  20. Have3you3got3the3Gme?

  21. Or3the3money?

  22. What3do3you3do?

  23. Nothing

  24. Throw3 servers3at3 the3 problem

  25. Do3some3 tricks3!

  26. Throw3servers3at3the3problem

  27. Scale3verGcally

  28. Fast Cheap vs Limited Expensive Long% term Short% term

  29. Scale3horizontally

  30. Efficient Unlimited vs ConsideraGons IniGal3effort Long% term Short% term

  31. What3kind3of3infrastructure3do3you3need?

  32. What3kind3of3infrastructure3do3you3need? One3big3 box?

  33. What3kind3of3infrastructure3do3you3need? Scale3across3 1003nodes?

  34. What3kind3of3infrastructure3do3you3need? That3big3F53 loadbalancer?

  35. What3kind3of3infrastructure3do3you3need? Only3the3DB3 gets3 hammered

  36. What3kind3of3infrastructure3do3you3need? Lots3of3staGc3 traffic

  37. What3kind3of3infrastructure3do3you3need? Shared3hosGng3 will3do3...3 except3during3the3 month3of3the3event

  38. About3a3mulGYserver3setup

  39. Goal:3(almost)3no3code3changes

  40. Cache

  41. Frontend Backend Data% cache Opcode% cache Page% cache APC Memcached

    SQLite File Redis +more +more
  42. What? When3not? How3long? CompaGbility Limited3size

  43. Tricks

  44. RewriteEngine*On RewriteCond*%{REQUEST_FILENAME}*=s*[OR] RewriteCond*%{REQUEST_FILENAME}*=l*[OR] RewriteCond*%{REQUEST_FILENAME}*=d RewriteRule*^.*$*=*[NC,L] RewriteRule*^.*$*index.php*[NC,L] Use3mod_rewrite Hit3frontcontroller3if3resource3doesn’t3exist

  45. Use3mod_rewrite Write3output3to3file3and3print3to3screen <?php 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;
  46. APC

  47. Auto3prepend3&3auto3append AutomaGcally3executed3before3every3request [PHP] auto_prepend_file*“/path/to/prepend.php” auto_append_file*“/path/to/append.php”

  48. Auto3prepend Read3from3cache3or3start3output3buffer <?php 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(); }
  49. Auto3append Close3output3buffer,3store3data3in3cache3&3 print3output <?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; }
  50. Data3cache Caching3layer3 before3on3top3 of3the3 database

  51. <?php class Data { private $_mysqlDependency; public function __construct($mysqlDependency) {

    $this->_mysqlDependency = $mysqlDependency; } public function fetchQueryFromDatabase($key) { return $this->_mysqlDependency- >fetchQueryEscaped("SELECT * FROM `myTable` WHERE `myKey` = '%s'",$key); } } No% cache
  52. <?php class Data { private $_namespace = 'myNamespace_'; private $_ttl

    = 3600; private $_mysqlDependency; public function __construct($mysqlDependency) { $this->_mysqlDependency = $mysqlDependency; } public function fetchQueryFromDatabase($key) { if(($value = apc_fetch(md5( $this->_namespace.$key))) === false){ $value = $this->_fetchDataFromDatabase($key); $this->_storeDataInCache($key,$value); } return $value; } ... Override% &%use%cache Read% from%DB%&% store%in%cache
  53. ... private function _storeDataInCache($key,$value) { apc_store(md5($this->_namespace.$key),$value, $this->_ttl); return $this; }

    private function _fetchQueryFromDatabase($key) { return $this->_mysqlDependency- >fetchQueryEscaped("SELECT * FROM `myTable` WHERE `myKey` = '%s'",$key); } } Fetch% from%DB Store% in%cache
  54. You3can3also3use3Memcached

  55. You3can3also3use3Memcached memcached.sess_prefix = "memc.sess.key." session.save_path="127.0.0.1:11211" session.save_handler = memcached Also% for%session%

    handling
  56. Reverse3 (caching)3 proxies

  57. Put3‘em3in3 front3of3your3 webserver

  58. They3honor3 your3caching3 headers

  59. None
  60. Request vcl_recv In cache? vcl_hash Cacheable? vcl_hit() vcl_miss() vcl_deliver() vcl_fetch()

    No Yes No Yes Response
  61. backend default { .host = "127.0.0.1"; .port = "8080"; }

    acl purge { "localhost"; "127.0.0.1"; "some.host.name.com"; "1.2.3.4"; }
  62. sub vcl_recv { if (req.request == "PURGE") { if (!client.ip

    ~ purge) { error 405 "Not allowed: " + client.ip; } return(lookup); } if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT" && req.request != "POST" && req.request != "TRACE" && req.request != "OPTIONS" && req.request != "DELETE") { return (pipe); }
  63. if (req.request != "GET" && req.request != "HEAD") { return

    (pass); } if (req.http.Accept-Encoding) { if (req.url ~ "\.(gif|jpg|jpeg|swf|flv|mp3|mp4| pdf|ico|png|gz|tgz|bz2)(\?.*|)$") { remove req.http.Accept-Encoding; } else if (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } else if (req.http.Accept-Encoding ~ "deflate"){ set req.http.Accept-Encoding = "deflate"; } else { remove req.http.Accept-Encoding; } }
  64. if (req.url ~ "\.(gif|jpg|jpeg|swf|css|js|flv|mp3| mp4|pdf|ico|png)(\?.*|)$") { unset req.http.cookie; set req.url

    = regsub(req.url, "\?.*$", ""); return (lookup); } if (req.url ~ "\?(utm_(campaign|medium|source|term)| adParams|client|cx|eid|fbid|feed|ref(id|src)?|v(er| iew))=") { set req.url = regsub(req.url, "\?.*$", ""); } if (req.http.cookie ~ "^ *$") { unset req.http.cookie; }
  65. sub vcl_fetch { if (req.url ~ "wp-(login|admin)" || req.url ~

    "preview=true" || req.url ~ "xmlrpc.php") { return (hit_for_pass); } if ( (!(req.url ~ "(wp-(login|admin)|login)"))) { unset beresp.http.set-cookie; set beresp.ttl = 1h; } if (req.url ~ "\.(gif|jpg|jpeg|swf|css|js|flv|mp3| mp4|pdf|ico|png)(\?.*|)$") { set beresp.ttl = 365d; } }
  66. sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache

    = "HIT"; } else { set resp.http.X-Cache = "MISS"; } } sub vcl_hit { if (req.request == "PURGE") { purge; set obj.ttl = 0s; error 200 "OK"; } } sub vcl_miss { if (req.request == "PURGE") { purge; error 200 "OK"; } }
  67. FPM hfp://www.php.net/manual/en/install.fpm.configuraGon.php

  68. [www] listen = 9000 user = www-data group = www-data

    pm = dynamic pm.max_children = 10 pm.start_servers = 4 pm.max_spare_servers = 6 pm.max_requests = 500 php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com php_flag[display_errors] = off php_admin_value[error_log] = /var/log/fpm-php.www.log php_admin_flag[log_errors] = on php_admin_value[memory_limit] = 32M
  69. None
  70. upstream fpm { server php1.server.com:9000; server php2.server.com:9000; } upstream memcached

    { server memcached1.server.com:11211; server memcached2.server.com:11211; } server { root /var/www; index index.php index.html index.htm; server_name nginx.server.com; location / { try_files $uri $uri/ /index.php; } location @php { fastcgi_pass fpm; fastcgi_index index.php; include fastcgi_params; }
  71. location ~ \.php$ { set $memcached_key $request_uri; memcached_pass memcached; memcached_next_upstream

    not_found; default_type text/html; error_page 404 405 502 = @php; } location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { expires max; add_header Pragma public; add_header Cache-Control "public, must- revalidate, proxy-revalidate"; } }
  72. location ~ \.php$ { set $memcached_key $request_uri; memcached_pass memcached; memcached_next_upstream

    not_found; default_type text/html; error_page 404 405 502 = @php; } location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { expires max; add_header Pragma public; add_header Cache-Control "public, must- revalidate, proxy-revalidate"; } }
  73. None
  74. Content Delivery Network

  75. +3 W33Total3 Cache

  76. None
  77. ✓Enable3caching ✓Enable3cron.php ✓Configure3log3retenGon ✓Flat3catalog ✓Enable3compilaGon ✓Install3Varnish3Cache3plugin ✓Split3frontend3&3backend3servers ✓Perform3indexing3on3separate3 server

  78. None
  79. Boost Varnish Memcached

  80. Don’t3be3clueless

  81. Ask3for3help

  82. Apply3the3tricks

  83. And3don’t3forget3to3refactor3akerwards

  84. And3then3relax3...3and3be3happy

  85. None