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

Accelerating OTT video platforms with Varnish -...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for Thijs Feryn Thijs Feryn
February 04, 2020

Accelerating OTT video platforms with Varnish - London Video Tech meetup 2020

Slides for my OTT video acceleration talk at the London Video Technology meetup February 2020 edition: https://feryn.eu/speaking/accelerating-ott-video-platforms-varnish-london-video-technology-meetup-2020/

Avatar for Thijs Feryn

Thijs Feryn

February 04, 2020

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. WHY IS VARNISH SO POWERFUL? ✓ EXTREMELY LOW RESOURCE ✓

    EXTREMELY STABLE ✓ 100 GBIT PER SERVER ✓ REQUEST COALESCING ✓ VARNISH CONFIGURATION LANGUAGE ✓ VMODS ✓ COMPLIES TO HTTP BEST PRACTICES
  2. vcl 4.1; backend default { .host = "origin"; .port =

    "80"; } sub vcl_backend_response { if(bereq.url == "/vod/master.m3u8" ){ set beresp.grace = 1h; } }
  3. vcl 4.1; backend origin { .host = "1.2.3.4"; .port =

    "80"; } sub vcl_recv { if(req.url ~ "^/(live|vod)/") { unset req.http.authorization; unset req.http.cookie; } } sub vcl_backend_response { if(bereq.url ~ "^/(live|vod)/") { unset beresp.http.set-cookie; set beresp.grace = 5s; } if(bereq.url ~ "^/live/.*\.m3u8") { set beresp.ttl = 1ms; } if(bereq.url ~ "^/vod/.*\.m3u8") { set beresp.ttl = 3600s; } }
  4. LIVE ✓ LOW LATENCY ✓ CONSTANT PLAYLIST UPDATES ✓ LOW

    TTL ON PLAYLISTS ✓ ONLY THE LAST X SEGMENTS ARE REQUIRED ✓ SEGMENT SIZE TRADEOFF
  5. VOD ✓ NO PLAYLIST UPDATES ✓ HIGH TTL ON PLAYLISTS

    ✓ PRE-FETCHING POSSIBLE ✓ ALL SEGMENTS ARE REQUIRED ✓ STORAGE REQUIREMENTS
  6. WHERE VARNISH STORES ITS OBJECTS ✓ MEMORY ✓ DISK ✓

    MASSIVE STORAGE ENGINE (ENTERPRISE ONLY)
  7. MSE ✓ MIX OF MEMORY AND DISK ✓ SMARTER LRU

    ✓ PRE-ALLOCATED LARGE FILES ON DISK ✓ LESS DISK FRAGMENTATION ✓ INTELLIGENT STORAGE ROUTING
  8. env: { id = "myenv"; memcache_size = "100G"; books =

    ( { id = "book1"; directory = "/var/lib/mse/book1"; database_size = "1G"; stores = ( { id = "store-1-1"; filename = "/var/lib/mse/stores/disk1/store-1-1.dat"; size = "2T"; tags = ( "slow", "sata" ); }, { tags = ( "fast", "ssd" ); id = "store-1-2"; filename = "/var/lib/mse/stores/disk2/store-1-2.dat"; size = "500G"; } ); }); default_stores = "none"; }; MSE.CONF
  9. vcl 4.1; import mse; sub vcl_backend_response { if (beresp.ttl <

    120s) { mse.set_stores("none"); } else { if (beresp.http.Transfer-Encoding ~ "chunked" || beresp.http.Content-Length > 1M) { mse.set_stores("sata"); } else { mse.set_stores("fast"); } } }
  10. vcl 4.1; backend default { .host = "1.2.3.4"; .port =

    "80"; } sub vcl_recv { if(req.url ~ "^/live/enc.key") { if (req.http.Authorization != "Basic YWRtaW46YWRtaW4=") { return (synth(401, "Restricted")); } } unset req.http.Authorization; } sub vcl_synth { if (resp.status == 401) { set resp.http.WWW-Authenticate = {"Basic realm="Restricted area""}; } }
  11. vcl 4.1; import cookieplus; import redis; import kvstore; backend default

    { .host = "origin"; .port = "80"; } sub vcl_init { new authorized_sessions = kvstore.init(); new db = redis.db( location="redis:6379", type=master, connection_timeout=500, shared_connections=false, max_connections=1); }
  12. sub vcl_recv { if(req.url ~ "^/live/enc.key") { if(authorized_sessions.get(cookieplus.get("PHPSESSID"),"empty") == "empty")

    { db.command("GET"); db.push("PHPREDIS_SESSION:"+cookieplus.get("PHPSESSID")); db.execute(); if(db.get_string_reply() !~ "authorized\|b\:1\;") { authorized_sessions.set(cookieplus.get("PHPSESSID"),"false"); return (synth(401, "Not Authorized")); } else { authorized_sessions.set(cookieplus.get("PHPSESSID"),"true", 10s); } } elseif(authorized_sessions.get(cookieplus.get("PHPSESSID")) == "false") { return (synth(401, "Not Authorized")); } } }
  13. vcl 4.1; import mmdb; backend default { .host = "192.0.2.11";

    .port = "8080"; } # create a database object sub vcl_init { new geodb = mmdb.init("/path/to/db"); } sub vcl_recv { # retrieve the name of the request's origin set req.http.Country-Name = geodb.country_name(client.ip); # if the country doesn't come from Germany or Belgium, deny access if (req.http.Country-Name != "Germany" || req.http.Country-Name != "Belgium") { return (synth(403, "Sorry, only available in Germany and Belgium")); } } Geo blocking
  14. vcl 4.1; import geodirector; import mmdb; backend us { .host

    = "us.example.com"; .port = "80"; } backend uk { .host = "uk.example.com"; .port = "80"; } backend be { .host = "be.example.com"; .port = "80"; } sub vcl_init { new geodb = mmdb.init("/path/to/db"); }
  15. sub vcl_recv { set req.http.Country-Code = geodb.country_code(client.ip); if(req.http.Country-Code == "US")

    { set req.backend_hint = us; } elseif(req.http.Country-Code == "GB") { set req.backend_hint = uk; } else { set req.backend_hint = be; } } Geo backend selection
  16. vcl 4.1; import file; backend default { .host = "origin";

    .port = "80"; } sub vcl_init { new root = file.init("/var/www/html/"); } sub vcl_backend_fetch { set bereq.backend = root.backend(); }
  17. vcl 4.1; import http; backend default { .host = "origin";

    .port = "80"; } sub vcl_recv { if (req.url ~ "^/vod/.+\.ts$") { http.init(0); http.req_set_max_loops(0,1); http.req_copy_headers(0); http.req_set_method(0, "HEAD"); set req.http.x-next-url = http.prefetch_next_url(); http.req_set_url(0, req.http.x-next-url); http.req_send_and_finish(0); } }
  18. vcl 4.1; import vsthrottle; import tcp; backend default { .host

    = "origin"; .port = "80"; } sub vcl_recv { if (vsthrottle.is_denied(client.identity, 15, 10s, 60s)) { # Client has exceeded 15 reqs per 10s or get blocked for 60s return (synth(429, "Too Many Requests")); } # Download at 1 MB/s tcp.set_socket_pace(1000); }