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

't Oncachebare cachen

Thijs Feryn
December 10, 2019

't Oncachebare cachen

A talk about caching personalized data in Varnish, presented at the december 2019 edition of the PHPWVL meetup.

This presentation was delivered in the local dialect of the area. The slides are also in that dialect.

See https://feryn.eu/speaking/t-oncachebare-cachen/ for more information about this presentation.

Thijs Feryn

December 10, 2019
Tweet

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. 'T ONCACHEBARE CACHEN
    DOOR THIJS FERYN
    MET VARNISH

    View Slide

  2. Trage websites
    SUCKN

    View Slide

  3. DE MENSCHN EN GÈREN
    DAT RAPT GOAT EN DAT
    MAKT OOK DEEL UUT VAN
    DE USER EXPERIENCE

    View Slide

  4. TRAGE EN PLAT
    IS VERRE 'T ZELFSTE

    View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. MET SERVERS
    SMIETEN

    View Slide

  9. MO' MONEY
    MO' SERVERS
    MO' PROBLEMS
    WITJEWEL
    KÈREL

    View Slide

  10. EFTJES KI KIEKEN NO DE TRAAGSTE DELEN

    View Slide

  11. OPTIMALISEREN

    View Slide

  12. ACHTER EEN ENDE KOM JE TENDN

    View Slide

  13. CACHE

    View Slide

  14. HEY, IK ZIEN THIJS

    View Slide

  15. View Slide

  16. View Slide

  17. View Slide

  18. IK ZIEN
    EVANHELIST
    BIE

    View Slide

  19. View Slide

  20. View Slide

  21. View Slide

  22. 4,800,000 WEBSITES
    19% VAN DE TOP 10K WEBSITES

    View Slide

  23. View Slide

  24. IK ZIEN @THIJSFERYN

    View Slide

  25. View Slide

  26. View Slide

  27. NORMAAL
    GEBRUKER SERVER

    View Slide

  28. MET VARNISH
    GEBRUKER VARNISH SERVER

    View Slide

  29. View Slide

  30. View Slide

  31. DE CACHE CONTROLEREN
    Expires: Sat, 09 Sep 2017 14:30:00 GMT
    Cache-control: public, max-age=3600, s-maxage=86400
    Cache-control: private, no-cache, no-store
    Vary: Accept-Language

    View Slide

  32. STATE

    View Slide

  33. STATE
    ~
    HEBRUKERSSPECIFIEKE DATA
    COOKIES
    AUTH
    HEADERS

    View Slide

  34. 'T IS JUSTE VOE JOEN
    EN NIEMAND ANDERS
    NIET
    GECACHED
    EJT
    VERSTOAN?

    View Slide

  35. VARNISH CONFIGURATION LANGUAGE

    View Slide

  36. vcl 4.1;
    sub vcl_recv {
    if (req.http.Cookie) {
    set req.http.Cookie = ";" + req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    set req.http.Cookie = regsuball(req.http.Cookie,
    ";(SESS[a-z0-9]+|SSESS[a-z0-9]+|NO_CACHE)=", "; \1=");
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
    if (req.http.Cookie == "") {
    unset req.http.Cookie;
    }
    else {
    return (pass);
    }
    }
    }
    OLENE EEN
    PAAR COOKIES
    OEDEN

    View Slide

  37. sub vcl_recv {
    if (req.http.Cookie) {
    set req.http.Cookie = ";" + req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    set req.http.Cookie = regsuball(req.http.Cookie, ";(language)=", "; \1=");
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
    if (req.http.cookie ~ "^\s*$") {
    unset req.http.cookie;
    return(pass);
    }
    return(hash);
    }
    }
    sub vcl_hash {
    hash_data(regsub( req.http.Cookie, "^.*language=([^;]*);*.*$", "\1" ));
    }
    COOKIE
    CACHE
    VARIATIE

    View Slide

  38. vcl 4.1;
    import cookieplus;
    sub vcl_recv {
    cookieplus.keep("language");
    cookieplus.write();
    }
    sub vcl_hash {
    hash_data(cookieplus.get("language"));
    }
    VMOD_COOKIE

    View Slide

  39. BEVAT
    HEBRUKERSHEHEVENS

    View Slide

  40. NIET CACHEN

    View Slide

  41. PLACEHOLDERS

    View Slide

  42. APARTE
    HTTP REQUEST

    View Slide

  43. AJAX

    View Slide

  44. ✓CLIENT-SIDE
    ✓WE KEN' DA
    ✓PARALLEL VERWERKT
    ✓GRACEFUL
    DEGRADATION
    -DE BROWSER MOET ER
    Z'N PLAN MEE TREKN
    -EXTRA ROUNDTRIPS
    -BITJE TRAGER
    AJAX

    View Slide

  45. EDGE-SIDE INCLUDES ESI

    View Slide


  46. View Slide

  47. ESI
    ✓ PLACEHOLDER
    ✓ VERWERKT DEUR VARNISH
    ✓ OUTPUT IS EEN COMPOSITIE VAN BLOCKS
    ✓ STATE PER BLOCK
    ✓ TTL PER BLOCK

    View Slide

  48. sub vcl_recv {
    set req.http.Surrogate-Capability = "key=ESI/1.0";
    }
    sub vcl_backend_response {
    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
    unset beresp.http.Surrogate-Control;
    set beresp.do_esi = true;
    }
    }

    View Slide

  49. ✓SERVER-SIDE
    ✓GESTANDAARDISEERD
    ✓VERWERKT ON THE
    “EDGE”, NIET IN DE
    BROWSER
    ✓IN 'T ALHEMEEN RAPPER
    -SEQUENTIEEL*
    -EEN DERAN, OL DERAN
    -BEPERKTE IMPLEMENTATIE
    IN VARNISH
    -WE KENNEN DA NIE ZO
    GOED
    ESI PARALLEL IN
    ENTERPRISE

    View Slide

  50. NIET-CACHEBARE ROUTES ZIEN
    NOG OSSAN EEN TERE PLEKKE

    View Slide

  51. NIET ZOMAAR EEN CACHE
    NIET ZOMAAR "TE NEMEN OF TE LATEN"

    View Slide

  52. EEN HTTP
    BLOKKENDOZE

    View Slide

  53. BESLISSINGEN PAKKEN
    "ON THE EDGE"

    View Slide

  54. vcl 4.1;
    import cookieplus;
    import redis;
    import synthbackend;
    sub vcl_init
    {
    new db = redis.db(
    location="redis:6379",
    type=master,
    connection_timeout=500,
    shared_connections=false,
    max_connections=1);
    }
    sub vcl_recv
    {
    set req.http.X-Login = "false";
    set req.http.x-session = cookieplus.get("PHPSESSID","guest");
    if(req.http.x-session != "guest") {
    db.command("EXISTS");
    db.push("sf_s"+cookieplus.get("PHPSESSID"));
    db.execute();
    if(db.get_integer_reply() == 1) {
    set req.http.X-Login = "true";
    }
    }
    }
    SYNTHETIC HTTP

    View Slide

  55. sub vcl_backend_fetch
    {
    if(bereq.url == "/session") {
    if(bereq.http.X-Login != "true") {
    set bereq.backend = synthbackend.from_string("{}");
    return(fetch);
    }
    db.command("EVAL");
    db.push({"
    local session = redis.call('GET', KEYS[1])
    if session == nil then
    return '{}'
    end
    local result = string.gsub(session, '[%c]', '')
    local username = string.gsub(result,'.+Userusername\";s:[0-9]+:\"([^\"]+)\";.+','%1')
    if username == nil then
    return '{}'
    end
    return '{"username":"'.. username ..'"}'
    "});
    db.push(1);
    db.push("sf_s"+cookieplus.get("PHPSESSID"));
    db.execute();
    set bereq.backend = synthbackend.from_string(db.get_string_reply());
    }
    }
    sub vcl_backend_response
    {
    if(bereq.url == "/session") {
    set beresp.http.Content-Type = "application/json; charset=utf-8";
    set beresp.ttl = 3600s;
    set beresp.http.vary = "x-session";
    }
    }
    REDIS LUA
    CODE

    View Slide

  56. GEBRUKER
    GET /session
    Cookie: PHPSESSID=7er3hjKal8u235c87u6ih0vz8Y
    HTTP/1.1 200 OK
    Content-Length: 31
    Content-Type: application/json; charset=utf-8
    X-Varnish: 163854 196622
    Age: 27
    {"username":"thijs"}
    VARNISH

    View Slide

  57. JE ZIET ER VET MEE
    ✓ AJAX CALL
    ✓ LADEN VIA ESI EN VERWERKEN VIA LOKALE
    JAVASCRIPT
    ✓ EDGESTASH

    View Slide

  58. {{ EDGESTASH }}
    VARNISH
    MODULE DIE MUSTACHE
    SYNTAX VERWERKT "ON
    THE EDGE"

    View Slide

  59. vcl 4.1;
    import edgestash;
    backend default
    {
    .host = "1.1.1.1";
    .port = "80";
    }
    sub vcl_backend_response {
    if (bereq.url == "/session") {
    edgestash.index_json();
    } else if (bereq.url == "/") {
    edgestash.parse_response();
    }
    }
    sub vcl_deliver {
    if (req.url == "/" && edgestash.is_edgestash()) {
    edgestash.add_json_url("/session");
    edgestash.execute();
    }
    }
    EDGESTASH

    View Slide

  60. EDGESTASH
    {"username":"Thijs"}
    {{ username }}
    Thijs

    View Slide

  61. BITJE MEER FLEXIBILITEIT

    View Slide

  62. Surrogate-Control: edgestash="EDGESTASH/2.1"
    Link: ; rel=edgestash

    View Slide

  63. vcl 4.1;
    import edgestash;
    import std;
    backend default
    {
    .host = "1.1.1.1";
    }
    sub vcl_recv
    {
    set req.http.Surrogate-Capability={"edgestash="EDGESTASH/2.1""};
    }
    sub vcl_backend_response
    {
    if(beresp.http.Link) {
    std.collect(beresp.http.Link,",");
    }
    if(beresp.http.Link ~ "<([^>]+)>; rel=edgestash") {
    set beresp.http.x-edgestash-json-urls = regsuball(beresp.http.Link,"(?(?=<[^>]+>; rel=edgestash)<([^>]+)>;
    rel=edgestash|<([^>]+)>; rel=[a-z]+, )","\1");
    }
    if(beresp.http.Surrogate-Control) {
    std.collect(beresp.http.Surrogate-Control);
    }
    if(beresp.http.Surrogate-Control ~ {".*="EDGESTASH/2\.[0-9]+".*"}) {
    edgestash.parse_response();
    }
    }
    EDGESTASH

    View Slide

  64. sub vcl_deliver
    {
    if(edgestash.is_edgestash() && resp.http.x-edgestash-json-urls) {
    edgestash.add_json_url_csv(resp.http.x-edgestash-json-urls);
    edgestash.execute();
    }
    unset resp.http.Link;
    unset resp.http.x-edgestash-json-urls;
    unset resp.http.surrogate-control;
    }
    EDGESTASH

    View Slide

  65. View Slide

  66. COMPOSER REQUIRE THIJSFERYN/EDGESTASH-TWIG-BUNDLE

    View Slide

  67. {{ edgestash('username','/session') }}
    {{ username | edgestash('username','/session') }}

    View Slide


  68. {% if isEdgestash() %}
    //Edgestash-supported logic
    {% else %}
    //Regular Twig logic
    {% endif %}

    View Slide

  69. {{ edgestash('#username', '/session') }}
    Welcome {{ edgestash('username') }}
    {{ edgestash('/username') }}
    {{ edgestash('^username') }}
    Welcome guest
    {{ edgestash('/username') }

    View Slide


  70. {{ edgestash('#.', '/users') }}
    {{ edgestash('username') }}
    {{ edgestash('/.') }}

    View Slide

  71. View Slide

  72. VANAF $0.20/TER EURE + 14 DAGEN VOE NIET

    View Slide

  73. View Slide

  74. View Slide

  75. HTTPS://FERYN.EU
    HTTPS://TWITTER.COM/THIJSFERYN
    HTTPS://INSTAGRAM.COM/THIJSFERYN

    View Slide