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

Scalability Issues: Cure now, prevent later

Thijs Feryn
November 29, 2012

Scalability Issues: Cure now, prevent later

Slides for my Future Of Web Apps talk about scalability in Prague.

Thijs Feryn

November 29, 2012
Tweet

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. Hi  
    my  name  
    is  Thijs

    View full-size slide

  2. Excited  
    to  be  
    here!

    View full-size slide

  3. I’m  
    an  evangelist  at

    View full-size slide

  4. I’m  
    a  board  member  
    at

    View full-size slide

  5. It  works  on  my  computer

    View full-size slide

  6. It’s  the  internet’s  fault

    View full-size slide

  7. Developer  !=  web  developer

    View full-size slide

  8. HTTP?  HUH?

    View full-size slide

  9. What  do  you  do  when  things  go  wrong?

    View full-size slide

  10. Do  a  complete  rewrite  !

    View full-size slide

  11. Absolutely  
    nothing!

    View full-size slide

  12. Throw  servers  
    at  the  problem

    View full-size slide

  13. Bigger  box

    View full-size slide

  14. More  boxes

    View full-size slide

  15. Reduce  
    impact

    View full-size slide

  16. What  kind  of  infrastructure  do  you  need?

    View full-size slide

  17. One  big  
    box?

    View full-size slide

  18. Scale  across  
    100  nodes?

    View full-size slide

  19. That  big  F5  
    loadbalancer?

    View full-size slide

  20. Only  the  DB  
    gets  
    hammered

    View full-size slide

  21. Lots  of  staCc  
    traffic

    View full-size slide

  22. Shared  hosCng  
    will  do  ...  
    except  during  the  
    month  of  the  event

    View full-size slide

  23. SaaS
    PaaS
    IaaS

    View full-size slide

  24. DB  &  
    webserver?
    Or  specialized  tools?

    View full-size slide

  25. m
    ulC-­‐server  setup
    About  a

    View full-size slide

  26. m
    ulC-­‐server  setup
    About  a
    Loadbalancing

    View full-size slide

  27. m
    ulC-­‐server  setup
    About  a
    What  about  uploaded  files?

    View full-size slide

  28. m
    ulC-­‐server  setup
    About  a
    What  about  sessions?

    View full-size slide

  29. m
    ulC-­‐server  setup
    About  a
    Database  replicaCon

    View full-size slide

  30. rt_sigaction(SIGQUIT,  {0x7f11489295f0,  [QUIT],  SA_RESTORER|SA_INTERRUPT,  0x7f114d583f
    rt_sigprocmask(SIG_UNBLOCK,  [QUIT],  NULL,  8)  =  0
    rt_sigprocmask(SIG_BLOCK,  [TERM],  NULL,  8)  =  0
    rt_sigaction(SIGTERM,  {0x7f11489295f0,  [TERM],  SA_RESTORER|SA_INTERRUPT,  0x7f114d583f
    rt_sigprocmask(SIG_UNBLOCK,  [TERM],  NULL,  8)  =  0
    rt_sigprocmask(SIG_BLOCK,  [XCPU],  NULL,  8)  =  0
    rt_sigaction(SIGXCPU,  {0x7f11489295f0,  [XCPU],  SA_RESTORER|SA_INTERRUPT,  0x7f114d583f
    rt_sigprocmask(SIG_UNBLOCK,  [XCPU],  NULL,  8)  =  0
    rt_sigprocmask(SIG_BLOCK,  [XFSZ],  NULL,  8)  =  0
    rt_sigaction(SIGXFSZ,  {0x7f11489295f0,  [XFSZ],  SA_RESTORER|SA_INTERRUPT,  0x7f114d583f
    rt_sigprocmask(SIG_UNBLOCK,  [XFSZ],  NULL,  8)  =  0
    open("/proc/meminfo",  O_RDONLY)                  =  3
    fstat(3,  {st_mode=S_IFREG|0444,  st_size=0,  ...})  =  0
    mmap(NULL,  4096,  PROT_READ|PROT_WRITE,  MAP_PRIVATE|MAP_ANONYMOUS,  -­‐1,  0)  =  0x7f115022
    read(3,  "MemTotal:                2097152  kB\nMemFr"...,  1024)  =  560
    close(3)                                                                =  0
    munmap(0x7f1150225000,  4096)                        =  0
    getrlimit(RLIMIT_NOFILE,  {rlim_cur=1024,  rlim_max=1024})  =  0
    brk(0x1ae1000)                                                    =  0x1ae1000
    brk(0x1b02000)                                                    =  0x1b02000
    socket(PF_FILE,  SOCK_STREAM,  0)                  =  3
    fcntl(3,  F_SETFL,  O_RDWR|O_NONBLOCK)        =  0
    connect(3,  {sa_family=AF_FILE,  path="/var/run/nscd/socket"...},  110)  =  -­‐1  ECONNREFUSE
    close(3)                                                                =  0
    socket(PF_FILE,  SOCK_STREAM,  0)                  =  3
    fcntl(3,  F_SETFL,  O_RDWR|O_NONBLOCK)        =  0
    connect(3,  {sa_family=AF_FILE,  path="/var/run/nscd/socket"...},  110)  =  -­‐1  ECONNREFUSE
    close(3)                                                                =  0
    open("/etc/services",  O_RDONLY|O_CLOEXEC)  =  3
    fstat(3,  {st_mode=S_IFREG|0644,  st_size=18480,  ...})  =  0
    System
    calls

    View full-size slide

  31. rt_sigaction(SIGQUIT,  {0x7f11489295f0,  [QUIT],  SA_RESTORER|SA_INTERRUPT,  0x7f114d583f
    rt_sigprocmask(SIG_UNBLOCK,  [QUIT],  NULL,  8)  =  0
    rt_sigprocmask(SIG_BLOCK,  [TERM],  NULL,  8)  =  0
    rt_sigaction(SIGTERM,  {0x7f11489295f0,  [TERM],  SA_RESTORER|SA_INTERRUPT,  0x7f114d583f
    rt_sigprocmask(SIG_UNBLOCK,  [TERM],  NULL,  8)  =  0
    rt_sigprocmask(SIG_BLOCK,  [XCPU],  NULL,  8)  =  0
    rt_sigaction(SIGXCPU,  {0x7f11489295f0,  [XCPU],  SA_RESTORER|SA_INTERRUPT,  0x7f114d583f
    rt_sigprocmask(SIG_UNBLOCK,  [XCPU],  NULL,  8)  =  0
    rt_sigprocmask(SIG_BLOCK,  [XFSZ],  NULL,  8)  =  0
    rt_sigaction(SIGXFSZ,  {0x7f11489295f0,  [XFSZ],  SA_RESTORER|SA_INTERRUPT,  0x7f114d583f
    rt_sigprocmask(SIG_UNBLOCK,  [XFSZ],  NULL,  8)  =  0
    open("/proc/meminfo",  O_RDONLY)                  =  3
    fstat(3,  {st_mode=S_IFREG|0444,  st_size=0,  ...})  =  0
    mmap(NULL,  4096,  PROT_READ|PROT_WRITE,  MAP_PRIVATE|MAP_ANONYMOUS,  -­‐1,  0)  =  0x7f115022
    read(3,  "MemTotal:                2097152  kB\nMemFr"...,  1024)  =  560
    close(3)                                                                =  0
    munmap(0x7f1150225000,  4096)                        =  0
    getrlimit(RLIMIT_NOFILE,  {rlim_cur=1024,  rlim_max=1024})  =  0
    brk(0x1ae1000)                                                    =  0x1ae1000
    brk(0x1b02000)                                                    =  0x1b02000
    socket(PF_FILE,  SOCK_STREAM,  0)                  =  3
    fcntl(3,  F_SETFL,  O_RDWR|O_NONBLOCK)        =  0
    connect(3,  {sa_family=AF_FILE,  path="/var/run/nscd/socket"...},  110)  =  -­‐1  ECONNREFUSE
    close(3)                                                                =  0
    socket(PF_FILE,  SOCK_STREAM,  0)                  =  3
    fcntl(3,  F_SETFL,  O_RDWR|O_NONBLOCK)        =  0
    connect(3,  {sa_family=AF_FILE,  path="/var/run/nscd/socket"...},  110)  =  -­‐1  ECONNREFUSE
    close(3)                                                                =  0
    open("/etc/services",  O_RDONLY|O_CLOEXEC)  =  3
    fstat(3,  {st_mode=S_IFREG|0644,  st_size=18480,  ...})  =  0

    View full-size slide

  32. Modular  
    architecture

    View full-size slide

  33. Connection  
    handling
    strategy

    View full-size slide

  34. Path  
    lookups

    View full-size slide

  35. Is  caching  
    the  
    answer?

    View full-size slide

  36. Frontend Backend
    Data  
    cache
    Opcode  
    cache
    Page  
    cache
    APC
    Memcached
    SQLite
    File
    Redis
    +more
    +more

    View full-size slide

  37. What?
    When  not?
    How  long?
    CompaCbility
    Limited  size

    View full-size slide

  38. Do  you  have  a  
    data  access  
    strategy?

    View full-size slide

  39. Distributed  
    cache

    View full-size slide

  40. memcached.sess_prefix = "memc.sess.key."
    session.save_path="127.0.0.1:11211"
    session.save_handler = memcached
    Also  
    for  session  
    clustering

    View full-size slide

  41. Reverse  
    (caching)  
    proxies

    View full-size slide

  42. Protects  your  
    servers

    View full-size slide

  43. Put  ‘em  before  
    your  
    webserver

    View full-size slide

  44. They  honor  
    your  caching  
    headers

    View full-size slide

  45. Content
    Delivery
    Network

    View full-size slide

  46. I like Varnish

    View full-size slide

  47. Exceptional  
    performance

    View full-size slide

  48. Open  source  
    software

    View full-size slide

  49. Varnish  
    Configuration  
    Language

    View full-size slide

  50. Supports  
    ESI

    View full-size slide

  51. Can  handle  
    purging  &  
    banning

    View full-size slide

  52. backend default {
    .host = "127.0.0.1";
    .port = "8080";
    }
    acl purge {
    "localhost";
    "127.0.0.1";
    "some.host.name.com";
    "1.2.3.4";
    }

    View full-size slide

  53. 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);
    }

    View full-size slide

  54. 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;
    }
    }

    View full-size slide

  55. 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;
    }

    View full-size slide

  56. 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;
    }
    }

    View full-size slide

  57. 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";
    }
    }

    View full-size slide

  58. Webserver    
    performance

    View full-size slide

  59. Apache  vs  Nginx

    View full-size slide

  60. Prefork  or  worker  mode
    Async,  event-­‐driven  workers
    Apache
    Nginx

    View full-size slide

  61. Evented  non-­‐blocking  I/O
    We’ll  call  
    you  back!

    View full-size slide

  62. Blocking
    var  results  =  db.query("SELECT  *  FROM  tablename");
    //use  results  
    Non-­‐blocking
    db.query("SELECT  *  FROM  tablename"  ,  function  (results)  {  
    //use  results  
    });  
    //do  something  else  

    View full-size slide

  63. Example
    var  http  =  require('http');
    http.createServer(function  (req,  res)  {
       res.writeHead(200,  {'Content-­‐Type':  'text/plain'});
       res.end('Hello  World\n');
    }).listen(1337,  '127.0.0.1');
    console.log('Server  running  at  http://127.0.0.1:1337/');

    View full-size slide

  64. We  can  do  it  in  PHP  too

    View full-size slide

  65. Example
    require 'vendor/autoload.php';
    $app = function ($request, $response) {
    $response->writeHead(200, array('Content-
    Type' => 'text/plain'));
    $response->end("Hello World\n");
    };
    $loop = React\EventLoop\Factory::create();
    $socket = new React\Socket\Server($loop);
    $http = new React\Http\Server($socket, $loop);
    $http->on('request', $app);
    echo "Server running at http://127.0.0.1:1337\n";
    $socket->listen(1337);
    $loop->run();

    View full-size slide

  66. Real  /me  data
    Ajax
    Websockets

    View full-size slide

  67. Websockets
    var conn = new
    WebSocket('ws://
    some.host');
    conn.onmessage =
    function(e) {
    console.log(e.data);
    };
    conn.send('Hello World!');
    Client

    View full-size slide

  68. Websockets
    Server
    Ratchet:  
    websocket  
    framework  
    on  top  of  
    React

    View full-size slide

  69. namespace MyApp;
    use Ratchet\MessageComponentInterface;
    use Ratchet\ConnectionInterface;
    class Chat implements MessageComponentInterface {
    protected $clients;
    public function __construct() {
    $this->clients = new \SplObjectStorage;
    }
    public function onOpen(ConnectionInterface $conn) {
    $this->clients->attach($conn);
    }
    public function onMessage(ConnectionInterface $from, $msg) {
    foreach ($this->clients as $client) {
    if ($from !== $client) {
    $client->send('Response: '.$msg);
    }
    }
    }
    public function onClose(ConnectionInterface $conn) {
    $this->clients->detach($conn);
    }
    public function onError(ConnectionInterface $conn, \Exception $e) {
    echo "An error has occurred: {$e->getMessage()}\n";
    $conn->close();
    }
    }

    View full-size slide

  70. require __DIR__.'/vendor/autoload.php';
    require 'chat.php';
    use Ratchet\WebSocket\WsServer;
    use Ratchet\Server\IoServer;
    use MyApp\Chat;
    $ws = new WsServer(new Chat());
    $ws->disableVersion(0);
    $server = IoServer::factory($ws,80,'1.2.3.4');
    $server->run();

    View full-size slide

  71. FPM
    hJp://www.php.net/manual/en/install.fpm.configuraOon.php

    View full-size slide

  72. [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
    [email protected]
    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

    View full-size slide

  73. 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;
    }

    View full-size slide

  74. 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";
    }
    }

    View full-size slide

  75. Offloading
    Resources

    View full-size slide

  76. fastcgi_finish_request();

    View full-size slide

  77. Disconnects  from  webserver
    ConCnues  async  processing

    View full-size slide

  78. # Reverse Worker Code
    $worker= new GearmanWorker();
    $worker->addServer();
    $worker->addFunction("reverse",
    "my_reverse_function");
    while ($worker->work());
    function my_reverse_function($job)
    {
    return strrev($job->workload());
    }
    # Reverse Client Code
    $client= new GearmanClient();
    $client->addServer();
    print $client->do("reverse", "Hello World!");

    View full-size slide

  79. # Reverse Client Code
    $client= new GearmanClient();
    $client->addServer();
    print $client->do("reverse", "Hello World!");

    View full-size slide

  80. Don’t  be  clueless

    View full-size slide

  81. Apply  the  tricks

    View full-size slide

  82. And  don’t  forget  to  refactor  aPerwards

    View full-size slide

  83. And  then  relax  ...  and  be  happy

    View full-size slide