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

Accelerating OTT video platforms with Varnish -...

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/

Thijs Feryn

February 04, 2020
Tweet

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