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. View Slide

  2. Hi  
    my  name  
    is  Thijs

    View Slide

  3. THIJS

    View Slide

  4. View Slide

  5. TAZE

    View Slide

  6. Excited  
    to  be  
    here!

    View Slide

  7. I’m  
    an  evangelist  at

    View Slide

  8. I’m  
    a  board  member  
    at

    View Slide

  9. View Slide

  10. View Slide

  11. It  works  on  my  computer

    View Slide

  12. View Slide

  13. It’s  the  internet’s  fault

    View Slide

  14. Developer  !=  web  developer

    View Slide

  15. HTTP?  HUH?

    View Slide

  16. View Slide

  17. View Slide

  18. View Slide

  19. What  do  you  do  when  things  go  wrong?

    View Slide

  20. Do  a  complete  rewrite  !

    View Slide

  21. Absolutely  
    nothing!

    View Slide

  22. Throw  servers  
    at  the  problem

    View Slide

  23. Bigger  box

    View Slide

  24. More  boxes

    View Slide

  25. Reduce  
    impact

    View Slide

  26. What  kind  of  infrastructure  do  you  need?

    View Slide

  27. One  big  
    box?

    View Slide

  28. Scale  across  
    100  nodes?

    View Slide

  29. That  big  F5  
    loadbalancer?

    View Slide

  30. Only  the  DB  
    gets  
    hammered

    View Slide

  31. Lots  of  staCc  
    traffic

    View Slide

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

    View Slide

  33. SaaS
    PaaS
    IaaS

    View Slide

  34. DB  &  
    webserver?
    Or  specialized  tools?

    View Slide

  35. m
    ulC-­‐server  setup
    About  a

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  40. Impact

    View Slide

  41. 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 Slide

  42. 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 Slide

  43. CPU
    RAM
    IO

    View Slide

  44. Modular  
    architecture

    View Slide

  45. Connection  
    handling
    strategy

    View Slide

  46. Path  
    lookups

    View Slide

  47. Caching

    View Slide

  48. Is  caching  
    the  
    answer?

    View Slide

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

    View Slide

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

    View Slide

  51. APC

    View Slide

  52. Do  you  have  a  
    data  access  
    strategy?

    View Slide

  53. Distributed  
    cache

    View Slide

  54. View Slide

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

    View Slide

  56. View Slide

  57. Reverse  
    (caching)  
    proxies

    View Slide

  58. Protects  your  
    servers

    View Slide

  59. Put  ‘em  before  
    your  
    webserver

    View Slide

  60. They  honor  
    your  caching  
    headers

    View Slide

  61. View Slide

  62. View Slide

  63. Content
    Delivery
    Network

    View Slide

  64. View Slide

  65. View Slide

  66. I like Varnish

    View Slide

  67. Exceptional  
    performance

    View Slide

  68. Open  source  
    software

    View Slide

  69. Varnish  
    Configuration  
    Language

    View Slide

  70. Supports  
    ESI

    View Slide

  71. Can  handle  
    purging  &  
    banning

    View Slide

  72. 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 Slide

  73. 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 Slide

  74. 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 Slide

  75. 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 Slide

  76. 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 Slide

  77. 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 Slide

  78. Webserver    
    performance

    View Slide

  79. Apache  vs  Nginx

    View Slide

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

    View Slide

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

    View Slide

  82. 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 Slide

  83. 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 Slide

  84. We  can  do  it  in  PHP  too

    View Slide

  85. 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 Slide

  86. Real  /me  data
    Ajax
    Websockets

    View Slide

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

    View Slide

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

    View Slide

  89. 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 Slide

  90. 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 Slide

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

    View Slide

  92. [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 Slide

  93. 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 Slide

  94. 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 Slide

  95. Offloading
    Resources

    View Slide

  96. fastcgi_finish_request();

    View Slide

  97. Disconnects  from  webserver
    ConCnues  async  processing

    View Slide

  98. View Slide

  99. View Slide

  100. # 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 Slide

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

    View Slide

  102. Don’t  be  clueless

    View Slide

  103. Apply  the  tricks

    View Slide

  104. And  don’t  forget  to  refactor  aPerwards

    View Slide

  105. And  then  relax  ...  and  be  happy

    View Slide

  106. View Slide