SlideShare une entreprise Scribd logo
1  sur  62
Solving anything in VCL
Andrew Betts, Financial Times
Who is this guy?
1. Helped build the original HTML5 web
app for the FT
2. Created our Origami component
system
3. Ran FT Labs for 3 years
4. Now working with Nikkei to rebuild
nikkei.com
5. Also W3C Technical Architecture
Group
6. Live in Tokyo, Japan
2
Pic of me.
Nikkei
1. Largest business
newspaper in Japan
2. Globally better known for
the Nikkei 225 stock
index
3. Around 3 million readers
4
5
6
7
8
Coding on the edge
9
Benefits of edge code
10
1. Smarter routing
2. Faster authentication
3. Bandwidth management
4. Higher cache hit ratio
Edge side includes
11
<esi:include src="http://example.com/1.html"
alt="http://bak.example.com/2.html" onerror="continue"/>
index.html
my-news.html
Cache-control: max-age=86400
Cache-control: private
Server
The VCL way
1. Request and response bodies are opaque
2. Everything happens in metadata
3. Very restricted: No loops or variables
4. Extensible: some useful Fastly extensions include geo-ip and crypto
5. Incredibly powerful when used creatively
12
SOA Routing
Send requests to multiple
microservice backends
This is great if...
You have a microservice architecture
Many backends, one domain
You add/remove services regularly
1
SOA Routing in VCL
14
Front page
Article page
Timeline
Content API
Choose a backend
based on a path match
of the request URL
/article/123
SOA Routing in VCL
15
[
{
name,
paths,
host,
useSsl,
}, …
]
{{#each backends}}
backend {{name}} {
.port = "{{p}}";
.host = "{{h}}";
}
{{/each}}
let vclContent =
vclTemplate(data);
fs.writeFileSync(
vclFilePath,
vclContent,
'UTF-8'
);
services.json
Defines all the backends
and paths that they
control.
routing.vcl.handlebars
VCL template with
Handlebars placeholders
for backends & routing
build.js
Task script to merge
service data into VCL
template
SOA Routing: key tools and techniques
● Choose a backend:
set req.backend = {{backendName}};
● Match a route pattern:
if (req.url ~ "{{pattern}}")
● Remember to set a Host header:
set req.http.Host = "{{backendhost}}";
● Upload to Fastly using FT Fastly tools
○ https://github.com/Financial-Times/fastly-tools
16
service-registry.json
17
[
{
"name": "front-page",
"paths": [
"/(?qs)",
"/.resources/front/(**)(?qs)"
],
"hosts": [ "my-backend.ap-northeast-1.elasticbeanstalk.com" ]
},
{
"name": "article-page",
...
}
]
Common regex patterns simplified
into shortcuts
routing.vcl.handlebars
18
{{#each backends}}
backend {{name}} {
.port = "{{port}}";
.host = "{{host}}";
.ssl = {{use_ssl}};
.probe = {
.request = "GET / HTTP/1.1" "Host: {{host}}"
"Connection: close";
}
}
{{/each}}
sub vcl_recv {
{{#each routes}}
if (req.url ~ "{{pattern}}") {
set req.backend = {{backend}};
{{#if target}}
set req.url = regsub(req.url,
"{{pattern}}", "{{target}}");
{{/if}}
{{!-- Fastly doesn't support the host_header
property in backend definitions --}}
set req.http.Host = "{{backendhost}}";
}
{{/each}}
return(lookup);
}
build.js
19
const vclTemplate = handlebars.compile(fs.readFileSync('routing.vcl.handlebars'),
'UTF-8'));
const services = require('services.json');
// ... transform `services` into `viewData`
let vclContent = vclTemplate(viewData);
fs.writeFileSync(vclFilePath, vclContent, 'UTF-8');
UA Targeting
Return user-agent specific
responses without destroying
your cache hit ratio
This is great if...
You have a response that is tailored
to different device types
There are a virtually infinite number of
User-Agent values
2
21
Polyfill screenshot
UA Targeting
22
/normalizeUA
/polyfill.js?ua=ie/11
/polyfill.js
Add the normalised User-
Agent to the URL and
restart the original request
Add a Vary: User-Agent
header to the response
before sending it back to
the browser
We call this a
preflight request
UA targeting: key tools and techniques
● Remember something using request headers:
set req.http.tmpOrigURL = req.url;
● Change the URL of the backend request:
set req.url = "/api/normalizeUA?ua=" req.http.User-Agent;
● Reconstruct original URL adding a backend response header:
set req.url = req.http.tmpOrigURL "?ua=" resp.http.NormUA;
● Restart to send the request back to vcl_recv:
restart;
23
ua-targeting.vcl
24
sub vcl_recv {
if (req.url ~ "^/v2/polyfill." && req.url
!~ "[?&]ua=") {
set req.http.X-Orig-URL = req.url;
set req.url = "/v2/normalizeUa?ua="
urlencode(req.http.User-Agent);
}
}
sub vcl_deliver {
if (req.url ~ "^/vd/normalizeUa" && resp.status == 200 &&
req.http.X-Orig-URL) {
set req.http.Fastly-force-Shield = "1";
if (req.http.X-Orig-URL ~ "?") {
set req.url = req.http.X-Orig-URL "&ua=" resp.http.UA;
} else {
set req.url = req.http.X-Orig-URL "?ua="
resp.http.UA;
}
restart;
} else if (req.url ~ "^/vd/polyfill..*[?&]ua=" &&
req.http.X-Orig-URL && req.http.X-Orig-URL !~ "[?&]ua=") {
add resp.http.Vary = "User-Agent";
}
return(deliver);
}
Authentication
Implement integration with your
federated identity system
entirely in VCL
This is great if...
You have a federated login system
using a protocol like OAuth
You want to annotate requests with a
simple verified authentication state
3
Magic circa 2001
26
<?php
echo $_SERVER['PHP_AUTH_USER'];
?>
http://intranet/my/example/app
New magic circa 2016
27
app.get('/', (req, res) => {
res.end(req.get('Nikkei-UserID'));
});
Authentication
28
/article/123
Nikkei-UserID: andrew.betts
Nikkei-UserRank: premium
Vary: Nikkei-UserRank
Article
Cookie: Auth=a139fm24...
Cache-control: private
Authentication: key tools and techniques
● Get a cookie by name: req.http.Cookie:MySiteAuth
● Base64 normalisation:
digest.base64url_decode(), digest.base64_decode
● Extract the parts of a JSON Web Token (JWT):
regsub({{cookie}}, "(^[^.]+).[^.]+.[^.]+$", "1");
● Check JWT signature: digest.hmac_sha256_base64()
● Set trusted headers for backend use:
req.http.Nikkei-UserID = regsub({{jwt}}, {{pattern}}, "1");
29
authentication.vcl
30
if (req.http.Cookie:NikkeiAuth) {
set req.http.tmpHeader = regsub(req.http.Cookie:NikkeiAuth, "(^[^.]+).[^.]+.[^.]+$", "1");
set req.http.tmpPayload = regsub(req.http.Cookie:NikkeiAuth, "^[^.]+.([^.]+).[^.]+$", "1");
set req.http.tmpRequestSig = digest.base64url_decode(
regsub(req.http.Cookie:NikkeiAuth, "^[^.]+.[^.]+.([^.]+)$", "1")
);
set req.http.tmpCorrectSig = digest.base64_decode(
digest.hmac_sha256_base64("{{jwt_secret}}", req.http.tmpHeader "." req.http.tmpPayload)
);
if (req.http.tmpRequestSig != req.http.tmpCorrectSig) {
error 754 "/login; NikkeiAuth=deleted; expires=Thu, 01 Jan 1970 00:00:00 GMT";
}
... continues ...
authentication.vcl (cont)
31
set req.http.tmpPayload = digest.base64_decode(req.http.tmpPayload);
set req.http.Nikkei-UserID = regsub(req.http.tmpPayload, {"^.*?"sub"s*:s*"(w+)".*?$"}, "1");
set req.http.Nikkei-Rank = regsub(req.http.tmpPayload, {"^.*?"ds_rank"s*:s*"(w+)".*?$"}, "1");
unset req.http.base64_header;
unset req.http.base64_payload;
unset req.http.signature;
unset req.http.valid_signature;
unset req.http.payload;
} else {
set req.http.Nikkei-UserID = "anonymous";
set req.http.Nikkei-Rank = "anonymous";
}
Feature flags
Dark deployments and easy A/B
testing without reducing front
end perf or cache efficiency
This is great if...
You want to serve different versions
of your site to different users
Test new features internally on prod
before releasing them to the world
4
33
34
Now you see it...
Feature flags parts
35
● A flags registry - a JSON file will be fine
○ Include all possible values of each flag and what percentage of the audience it applies to
○ Publish it statically - S3 is good for that
● A flag toggler tool
○ Reads the JSON, renders a table, writes an override cookie with chosen values
● An API
○ Reads the JSON, responds to requests by calculating a user's position number on a 0-100
line and matches them with appropriate flag values
Feature flags
36
Flags API
Article
Merge the flags response with the override cookie,
set as HTTP header, restart original request...
/article/123
Cookie: Flgs-
Override= Foo=10;
/api/flags?userid=6453
Flgs: highlights=true; Foo=42;
Flgs: highlights=true; Foo=42; Foo=10
Vary: Flgs
ExpressJS flags middleware
37
app.get('/', (req, res) => {
if (req.flags.has('highlights')) {
// Enable highlights feature
}
});
HTTP/1.1 200 OK
Vary: Nikkei-Flags
...
Dynamic backends
Override backend rules at
runtime without updating your
VCL
This is great if...
You have a bug you can't reproduce
without the request going through
the CDN
You want to test a local dev version of
a service with live integrations
5
Dynamic backends
39
Developer
laptopDynamic backend
proxy
(node-http-proxy)
Check forwarded IP is
whitelisted or auth
header is also present
GET /article/123
Backend-Override: article -> fc57848a.ngrok.io
ngrok
fc57848a
.ngrok.io
Dynamic backends: key tools and techniques
● Extract backend to override:
set req.http.tmpORBackend =
regsub(req.http.Backend-Override, "s*->.*$", "");
● Check whether current backend matches
if (req.http.tmpORBackend == req.http.tmpCurrentBackend) {
● Use node-http-proxy for the proxy app
○ Remember res.setHeader('Vary', 'Backend-Override');
○ I use {xfwd: false, changeOrigin: true, hostRewrite: true}
40
Debug headers
Collect request lifecycle
information in a single HTTP
response header
This is great if...
You find it hard to understand what
path the request is taking through
your VCL
You have restarts in your VCL and
need to see all the individual
backend requests, not just the last
one
6
42
The VCL
flow
43
The VCL
flow
44
The VCL
flow
Debug journey
45
vcl_recv {
set req.http.tmpLog = if (req.restarts == 0, "", req.http.tmpLog ";");
# ... routing ...
set req.http.tmpLog = req.http.tmpLog " {{backend}}:" req.url;
}
vcl_fetch { set req.http.tmpLog = req.http.tmpLog " fetch"; ... }
vcl_hit { set req.http.tmpLog = req.http.tmpLog " hit"; ... }
vcl_miss { set req.http.tmpLog = req.http.tmpLog " miss"; ... }
vcl_pass { set req.http.tmpLog = req.http.tmpLog " pass"; ... }
vcl_deliver {
set resp.http.CDN-Process-Log = req.http.tmpLog;
}
Debug journey
46
CDN-Process-Log:
apigw:/flags/v1/rnikkei/allocate?output=diff&segid=foo&rank=X
HIT (hits=2 ttl=1.204/5.000 age=4 swr=300.000 sie=604800.000);
rnikkei_front_0:/ MISS (hits=0 ttl=1.000/1.000 age=0 swr=300.000
sie=86400.000)
RUM++
Resource Timing API + data
Fastly exposes in VCL. And no
backend.
This is great if...
You want to track down hotspots of
slow response times
You'd like to understand how
successfully end users are being
matched to their nearest PoPs
7
Resource timing on front end
48
var rec = window.performance.getEntriesByType("resource")
.find(rec => rec.name.indexOf('[URL]') !== -1)
;
(new Image()).src = '/sendBeacon'+
'?dns='+(rec.domainLookupEnd-rec.domainLookupStart)+
'&connect='+(rec.connectEnd-rec.connectStart)+
'&req='+(rec.responseStart-rec.requestStart)+
'&resp='+(rec.responseEnd-rec.responseStart)
;
Add CDN data in VCL & respond with synthetic
49
sub vcl_recv {
if (req.url ~ "^/sendBeacon") {
error 204 "No content";
}
}
RUM++
50
/sendBeacon?foo=42&...
204 No Content
51
Crunch the data
52
Beyond ASCII
Use these encoding tips to
embed non-ASCII content in
your VCL file.
This is great if...
Your users don't speak English, but
you can only write ASCII in VCL
files
8
Everyone does UTF-8 now, right?
54
synthetic {"Responsive Nikkeiアルファプログラムのメンバーの皆様、ア
ルファバージョンのサイトにアクセスできない場合、
rnfeedback@nex.nikkei.co.jp までその旨連絡ください。"};
55
Quick conversion
56
"string"
.split('')
.map(
char => char.codePointAt(0) < 128 ?
char :
"&#"+char.codePointAt(0)+";"
)
.join('')
;
"Fixed"
57
synthetic {"Responsive
Nikkei&#12450;&#12523;&#12501;&#12449;&#12503;&#12525;&#12464;&#
12521;&#12512;&#12398;&#12513;&#12531;&#12496;&#12540;&#12398;&#
30342;&#27096;&#12289;&#12450;&#12523;&#12501;&#12449;&#12496;&#
12540;&#12472;&#12519;&#12531;&#12398;&#12469;&#12452;&#12488;&#
12395;&#12450;&#12463;&#12475;&#12473;&#12391;&#12365;&#12394;&#
12356;&#22580;&#21512;&#12289;rnfeedback@nex.nikkei.co.jp
&#12414;&#12391;&#12381;&#12398;&#26088;&#36899;&#32097;&#12367;
&#12384;&#12373;&#12356;&#12290;"};
"Fixed"
58
synthetic digest.base64decode(
{"IlJlc3BvbnNpdmUgTmlra2Vp44Ki44Or44OV44Kh44OX44Ot44Kw44Op44Og44
Gu44Oh44Oz44OQ44O844Gu55qG5qeY44CB44Ki44Or44OV44Kh44OQ44O844K444
On44Oz44Gu44K144Kk44OI44Gr44Ki44Kv44K744K544Gn44GN44Gq44GE5aC05Z
CI44CBcm5mZWVkYmFja0BuZXgubmlra2VpLmNvLmpwIOOBvuOBp+OBneOBruaXqO
mAo+e1oeOBj+OBoOOBleOBhOOAgiI="});
59
I have 68 backends
60
Varnishlog to the rescue
A way to submit a varnish
transaction ID to the API,
and get all varnishlog
events relating to that
transaction, including
related (backend)
transactions
61
> fastly log 1467852934
17 SessionOpen c 66.249.72.22 47013 :80
17 ReqStart c 66.249.72.22 47013
1467852934
17 RxRequest c GET
17 RxURL c /articles/123
17 RxProtocol c HTTP/1.1
17 RxHeader c Host: www.example.com
...
Thanks for listening
62
Andrew Betts
andrew.betts@ft.com
@triblondon
Get the slides
bit.ly/ft-fastly-altitude-2016

Contenu connexe

En vedette

En vedette (20)

10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!
 
What’s New in Amazon Aurora
What’s New in Amazon AuroraWhat’s New in Amazon Aurora
What’s New in Amazon Aurora
 
神に近づくx/net/context (Finding God with x/net/context)
神に近づくx/net/context (Finding God with x/net/context)神に近づくx/net/context (Finding God with x/net/context)
神に近づくx/net/context (Finding God with x/net/context)
 
Apache Spark Streaming + Kafka 0.10 with Joan Viladrosariera
Apache Spark Streaming + Kafka 0.10 with Joan ViladrosarieraApache Spark Streaming + Kafka 0.10 with Joan Viladrosariera
Apache Spark Streaming + Kafka 0.10 with Joan Viladrosariera
 
An introduction and future of Ruby coverage library
An introduction and future of Ruby coverage libraryAn introduction and future of Ruby coverage library
An introduction and future of Ruby coverage library
 
SLOのすすめ
SLOのすすめSLOのすすめ
SLOのすすめ
 
Spiderストレージエンジンの使い方と利用事例 他ストレージエンジンの紹介
Spiderストレージエンジンの使い方と利用事例 他ストレージエンジンの紹介Spiderストレージエンジンの使い方と利用事例 他ストレージエンジンの紹介
Spiderストレージエンジンの使い方と利用事例 他ストレージエンジンの紹介
 
ScalaからGoへ
ScalaからGoへScalaからGoへ
ScalaからGoへ
 
AndApp開発における全て #denatechcon
AndApp開発における全て #denatechconAndApp開発における全て #denatechcon
AndApp開発における全て #denatechcon
 
Blockchain on Go
Blockchain on GoBlockchain on Go
Blockchain on Go
 
AWS X-Rayによるアプリケーションの分析とデバッグ
AWS X-Rayによるアプリケーションの分析とデバッグAWS X-Rayによるアプリケーションの分析とデバッグ
AWS X-Rayによるアプリケーションの分析とデバッグ
 
Streaming Data Analytics with Amazon Redshift and Kinesis Firehose
Streaming Data Analytics with Amazon Redshift and Kinesis FirehoseStreaming Data Analytics with Amazon Redshift and Kinesis Firehose
Streaming Data Analytics with Amazon Redshift and Kinesis Firehose
 
MongoDBの可能性の話
MongoDBの可能性の話MongoDBの可能性の話
MongoDBの可能性の話
 
golang.tokyo #6 (in Japanese)
golang.tokyo #6 (in Japanese)golang.tokyo #6 (in Japanese)
golang.tokyo #6 (in Japanese)
 
Operations: Production Readiness Review – How to stop bad things from Happening
Operations: Production Readiness Review – How to stop bad things from HappeningOperations: Production Readiness Review – How to stop bad things from Happening
Operations: Production Readiness Review – How to stop bad things from Happening
 
Microservices at Mercari
Microservices at MercariMicroservices at Mercari
Microservices at Mercari
 
Fast and Reliable Swift APIs with gRPC
Fast and Reliable Swift APIs with gRPCFast and Reliable Swift APIs with gRPC
Fast and Reliable Swift APIs with gRPC
 
Swaggerでのapi開発よもやま話
Swaggerでのapi開発よもやま話Swaggerでのapi開発よもやま話
Swaggerでのapi開発よもやま話
 
メルカリアッテの実務で使えた、GAE/Goの開発を効率的にする方法
メルカリアッテの実務で使えた、GAE/Goの開発を効率的にする方法メルカリアッテの実務で使えた、GAE/Goの開発を効率的にする方法
メルカリアッテの実務で使えた、GAE/Goの開発を効率的にする方法
 
So You Wanna Go Fast?
So You Wanna Go Fast?So You Wanna Go Fast?
So You Wanna Go Fast?
 

Similaire à Solving anything in VCL

Developing your first application using FIWARE
Developing your first application using FIWAREDeveloping your first application using FIWARE
Developing your first application using FIWARE
FIWARE
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Mobile webapplication development
Mobile webapplication developmentMobile webapplication development
Mobile webapplication development
Ganesh Gembali
 

Similaire à Solving anything in VCL (20)

Real World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS ApplicationReal World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS Application
 
Developing your first application using FIWARE
Developing your first application using FIWAREDeveloping your first application using FIWARE
Developing your first application using FIWARE
 
RESTful Web Applications with Apache Sling
RESTful Web Applications with Apache SlingRESTful Web Applications with Apache Sling
RESTful Web Applications with Apache Sling
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Load Balancing Applications with NGINX in a CoreOS Cluster
Load Balancing Applications with NGINX in a CoreOS ClusterLoad Balancing Applications with NGINX in a CoreOS Cluster
Load Balancing Applications with NGINX in a CoreOS Cluster
 
Real World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js ApplicationsReal World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js Applications
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6
 
[W3C HTML5 2016] Angular + ES6
[W3C HTML5 2016] Angular + ES6[W3C HTML5 2016] Angular + ES6
[W3C HTML5 2016] Angular + ES6
 
2016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES62016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES6
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
 
Sanjeev ghai 12
Sanjeev ghai 12Sanjeev ghai 12
Sanjeev ghai 12
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NET
 
Play Framework
Play FrameworkPlay Framework
Play Framework
 
Building and Scaling Node.js Applications
Building and Scaling Node.js ApplicationsBuilding and Scaling Node.js Applications
Building and Scaling Node.js Applications
 
6 tips for improving ruby performance
6 tips for improving ruby performance6 tips for improving ruby performance
6 tips for improving ruby performance
 
Play Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and ScalaPlay Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and Scala
 
Mobile webapplication development
Mobile webapplication developmentMobile webapplication development
Mobile webapplication development
 
Meetup 2022 - APIs with Quarkus.pdf
Meetup 2022 - APIs with Quarkus.pdfMeetup 2022 - APIs with Quarkus.pdf
Meetup 2022 - APIs with Quarkus.pdf
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
 

Plus de Fastly

Plus de Fastly (20)

Revisiting HTTP/2
Revisiting HTTP/2Revisiting HTTP/2
Revisiting HTTP/2
 
Altitude San Francisco 2018: Preparing for Video Streaming Events at Scale
Altitude San Francisco 2018: Preparing for Video Streaming Events at ScaleAltitude San Francisco 2018: Preparing for Video Streaming Events at Scale
Altitude San Francisco 2018: Preparing for Video Streaming Events at Scale
 
Altitude San Francisco 2018: Building the Souther Hemisphere of the Internet
Altitude San Francisco 2018: Building the Souther Hemisphere of the InternetAltitude San Francisco 2018: Building the Souther Hemisphere of the Internet
Altitude San Francisco 2018: Building the Souther Hemisphere of the Internet
 
Altitude San Francisco 2018: The World Cup Stream
Altitude San Francisco 2018: The World Cup StreamAltitude San Francisco 2018: The World Cup Stream
Altitude San Francisco 2018: The World Cup Stream
 
Altitude San Francisco 2018: We Own Our Destiny
Altitude San Francisco 2018: We Own Our DestinyAltitude San Francisco 2018: We Own Our Destiny
Altitude San Francisco 2018: We Own Our Destiny
 
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...
 
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless Migration
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless MigrationAltitude San Francisco 2018: Moving Off the Monolith: A Seamless Migration
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless Migration
 
Altitude San Francisco 2018: Bringing TLS to GitHub Pages
Altitude San Francisco 2018: Bringing TLS to GitHub PagesAltitude San Francisco 2018: Bringing TLS to GitHub Pages
Altitude San Francisco 2018: Bringing TLS to GitHub Pages
 
Altitude San Francisco 2018: HTTP Invalidation Workshop
Altitude San Francisco 2018: HTTP Invalidation WorkshopAltitude San Francisco 2018: HTTP Invalidation Workshop
Altitude San Francisco 2018: HTTP Invalidation Workshop
 
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and Woe
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and WoeAltitude San Francisco 2018: HTTP/2 Tales: Discovery and Woe
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and Woe
 
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...
 
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per day
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per dayAltitude San Francisco 2018: Scaling Ethereum to 10B requests per day
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per day
 
Altitude San Francisco 2018: Authentication at the Edge
Altitude San Francisco 2018: Authentication at the EdgeAltitude San Francisco 2018: Authentication at the Edge
Altitude San Francisco 2018: Authentication at the Edge
 
Altitude San Francisco 2018: WebAssembly Tools & Applications
Altitude San Francisco 2018: WebAssembly Tools & ApplicationsAltitude San Francisco 2018: WebAssembly Tools & Applications
Altitude San Francisco 2018: WebAssembly Tools & Applications
 
Altitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly WorkshopAltitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly Workshop
 
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORK
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORKAltitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORK
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORK
 
Altitude San Francisco 2018: WAF Workshop
Altitude San Francisco 2018: WAF WorkshopAltitude San Francisco 2018: WAF Workshop
Altitude San Francisco 2018: WAF Workshop
 
Altitude San Francisco 2018: Logging at the Edge
Altitude San Francisco 2018: Logging at the Edge Altitude San Francisco 2018: Logging at the Edge
Altitude San Francisco 2018: Logging at the Edge
 
Altitude San Francisco 2018: Video Workshop Docs
Altitude San Francisco 2018: Video Workshop DocsAltitude San Francisco 2018: Video Workshop Docs
Altitude San Francisco 2018: Video Workshop Docs
 
Altitude San Francisco 2018: Programming the Edge
Altitude San Francisco 2018: Programming the EdgeAltitude San Francisco 2018: Programming the Edge
Altitude San Francisco 2018: Programming the Edge
 

Dernier

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Dernier (20)

presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 

Solving anything in VCL

  • 1. Solving anything in VCL Andrew Betts, Financial Times
  • 2. Who is this guy? 1. Helped build the original HTML5 web app for the FT 2. Created our Origami component system 3. Ran FT Labs for 3 years 4. Now working with Nikkei to rebuild nikkei.com 5. Also W3C Technical Architecture Group 6. Live in Tokyo, Japan 2 Pic of me.
  • 3. Nikkei 1. Largest business newspaper in Japan 2. Globally better known for the Nikkei 225 stock index 3. Around 3 million readers
  • 4. 4
  • 5. 5
  • 6. 6
  • 7. 7
  • 8. 8
  • 9. Coding on the edge 9
  • 10. Benefits of edge code 10 1. Smarter routing 2. Faster authentication 3. Bandwidth management 4. Higher cache hit ratio
  • 11. Edge side includes 11 <esi:include src="http://example.com/1.html" alt="http://bak.example.com/2.html" onerror="continue"/> index.html my-news.html Cache-control: max-age=86400 Cache-control: private Server
  • 12. The VCL way 1. Request and response bodies are opaque 2. Everything happens in metadata 3. Very restricted: No loops or variables 4. Extensible: some useful Fastly extensions include geo-ip and crypto 5. Incredibly powerful when used creatively 12
  • 13. SOA Routing Send requests to multiple microservice backends This is great if... You have a microservice architecture Many backends, one domain You add/remove services regularly 1
  • 14. SOA Routing in VCL 14 Front page Article page Timeline Content API Choose a backend based on a path match of the request URL /article/123
  • 15. SOA Routing in VCL 15 [ { name, paths, host, useSsl, }, … ] {{#each backends}} backend {{name}} { .port = "{{p}}"; .host = "{{h}}"; } {{/each}} let vclContent = vclTemplate(data); fs.writeFileSync( vclFilePath, vclContent, 'UTF-8' ); services.json Defines all the backends and paths that they control. routing.vcl.handlebars VCL template with Handlebars placeholders for backends & routing build.js Task script to merge service data into VCL template
  • 16. SOA Routing: key tools and techniques ● Choose a backend: set req.backend = {{backendName}}; ● Match a route pattern: if (req.url ~ "{{pattern}}") ● Remember to set a Host header: set req.http.Host = "{{backendhost}}"; ● Upload to Fastly using FT Fastly tools ○ https://github.com/Financial-Times/fastly-tools 16
  • 17. service-registry.json 17 [ { "name": "front-page", "paths": [ "/(?qs)", "/.resources/front/(**)(?qs)" ], "hosts": [ "my-backend.ap-northeast-1.elasticbeanstalk.com" ] }, { "name": "article-page", ... } ] Common regex patterns simplified into shortcuts
  • 18. routing.vcl.handlebars 18 {{#each backends}} backend {{name}} { .port = "{{port}}"; .host = "{{host}}"; .ssl = {{use_ssl}}; .probe = { .request = "GET / HTTP/1.1" "Host: {{host}}" "Connection: close"; } } {{/each}} sub vcl_recv { {{#each routes}} if (req.url ~ "{{pattern}}") { set req.backend = {{backend}}; {{#if target}} set req.url = regsub(req.url, "{{pattern}}", "{{target}}"); {{/if}} {{!-- Fastly doesn't support the host_header property in backend definitions --}} set req.http.Host = "{{backendhost}}"; } {{/each}} return(lookup); }
  • 19. build.js 19 const vclTemplate = handlebars.compile(fs.readFileSync('routing.vcl.handlebars'), 'UTF-8')); const services = require('services.json'); // ... transform `services` into `viewData` let vclContent = vclTemplate(viewData); fs.writeFileSync(vclFilePath, vclContent, 'UTF-8');
  • 20. UA Targeting Return user-agent specific responses without destroying your cache hit ratio This is great if... You have a response that is tailored to different device types There are a virtually infinite number of User-Agent values 2
  • 22. UA Targeting 22 /normalizeUA /polyfill.js?ua=ie/11 /polyfill.js Add the normalised User- Agent to the URL and restart the original request Add a Vary: User-Agent header to the response before sending it back to the browser We call this a preflight request
  • 23. UA targeting: key tools and techniques ● Remember something using request headers: set req.http.tmpOrigURL = req.url; ● Change the URL of the backend request: set req.url = "/api/normalizeUA?ua=" req.http.User-Agent; ● Reconstruct original URL adding a backend response header: set req.url = req.http.tmpOrigURL "?ua=" resp.http.NormUA; ● Restart to send the request back to vcl_recv: restart; 23
  • 24. ua-targeting.vcl 24 sub vcl_recv { if (req.url ~ "^/v2/polyfill." && req.url !~ "[?&]ua=") { set req.http.X-Orig-URL = req.url; set req.url = "/v2/normalizeUa?ua=" urlencode(req.http.User-Agent); } } sub vcl_deliver { if (req.url ~ "^/vd/normalizeUa" && resp.status == 200 && req.http.X-Orig-URL) { set req.http.Fastly-force-Shield = "1"; if (req.http.X-Orig-URL ~ "?") { set req.url = req.http.X-Orig-URL "&ua=" resp.http.UA; } else { set req.url = req.http.X-Orig-URL "?ua=" resp.http.UA; } restart; } else if (req.url ~ "^/vd/polyfill..*[?&]ua=" && req.http.X-Orig-URL && req.http.X-Orig-URL !~ "[?&]ua=") { add resp.http.Vary = "User-Agent"; } return(deliver); }
  • 25. Authentication Implement integration with your federated identity system entirely in VCL This is great if... You have a federated login system using a protocol like OAuth You want to annotate requests with a simple verified authentication state 3
  • 26. Magic circa 2001 26 <?php echo $_SERVER['PHP_AUTH_USER']; ?> http://intranet/my/example/app
  • 27. New magic circa 2016 27 app.get('/', (req, res) => { res.end(req.get('Nikkei-UserID')); });
  • 28. Authentication 28 /article/123 Nikkei-UserID: andrew.betts Nikkei-UserRank: premium Vary: Nikkei-UserRank Article Cookie: Auth=a139fm24... Cache-control: private
  • 29. Authentication: key tools and techniques ● Get a cookie by name: req.http.Cookie:MySiteAuth ● Base64 normalisation: digest.base64url_decode(), digest.base64_decode ● Extract the parts of a JSON Web Token (JWT): regsub({{cookie}}, "(^[^.]+).[^.]+.[^.]+$", "1"); ● Check JWT signature: digest.hmac_sha256_base64() ● Set trusted headers for backend use: req.http.Nikkei-UserID = regsub({{jwt}}, {{pattern}}, "1"); 29
  • 30. authentication.vcl 30 if (req.http.Cookie:NikkeiAuth) { set req.http.tmpHeader = regsub(req.http.Cookie:NikkeiAuth, "(^[^.]+).[^.]+.[^.]+$", "1"); set req.http.tmpPayload = regsub(req.http.Cookie:NikkeiAuth, "^[^.]+.([^.]+).[^.]+$", "1"); set req.http.tmpRequestSig = digest.base64url_decode( regsub(req.http.Cookie:NikkeiAuth, "^[^.]+.[^.]+.([^.]+)$", "1") ); set req.http.tmpCorrectSig = digest.base64_decode( digest.hmac_sha256_base64("{{jwt_secret}}", req.http.tmpHeader "." req.http.tmpPayload) ); if (req.http.tmpRequestSig != req.http.tmpCorrectSig) { error 754 "/login; NikkeiAuth=deleted; expires=Thu, 01 Jan 1970 00:00:00 GMT"; } ... continues ...
  • 31. authentication.vcl (cont) 31 set req.http.tmpPayload = digest.base64_decode(req.http.tmpPayload); set req.http.Nikkei-UserID = regsub(req.http.tmpPayload, {"^.*?"sub"s*:s*"(w+)".*?$"}, "1"); set req.http.Nikkei-Rank = regsub(req.http.tmpPayload, {"^.*?"ds_rank"s*:s*"(w+)".*?$"}, "1"); unset req.http.base64_header; unset req.http.base64_payload; unset req.http.signature; unset req.http.valid_signature; unset req.http.payload; } else { set req.http.Nikkei-UserID = "anonymous"; set req.http.Nikkei-Rank = "anonymous"; }
  • 32. Feature flags Dark deployments and easy A/B testing without reducing front end perf or cache efficiency This is great if... You want to serve different versions of your site to different users Test new features internally on prod before releasing them to the world 4
  • 33. 33
  • 34. 34 Now you see it...
  • 35. Feature flags parts 35 ● A flags registry - a JSON file will be fine ○ Include all possible values of each flag and what percentage of the audience it applies to ○ Publish it statically - S3 is good for that ● A flag toggler tool ○ Reads the JSON, renders a table, writes an override cookie with chosen values ● An API ○ Reads the JSON, responds to requests by calculating a user's position number on a 0-100 line and matches them with appropriate flag values
  • 36. Feature flags 36 Flags API Article Merge the flags response with the override cookie, set as HTTP header, restart original request... /article/123 Cookie: Flgs- Override= Foo=10; /api/flags?userid=6453 Flgs: highlights=true; Foo=42; Flgs: highlights=true; Foo=42; Foo=10 Vary: Flgs
  • 37. ExpressJS flags middleware 37 app.get('/', (req, res) => { if (req.flags.has('highlights')) { // Enable highlights feature } }); HTTP/1.1 200 OK Vary: Nikkei-Flags ...
  • 38. Dynamic backends Override backend rules at runtime without updating your VCL This is great if... You have a bug you can't reproduce without the request going through the CDN You want to test a local dev version of a service with live integrations 5
  • 39. Dynamic backends 39 Developer laptopDynamic backend proxy (node-http-proxy) Check forwarded IP is whitelisted or auth header is also present GET /article/123 Backend-Override: article -> fc57848a.ngrok.io ngrok fc57848a .ngrok.io
  • 40. Dynamic backends: key tools and techniques ● Extract backend to override: set req.http.tmpORBackend = regsub(req.http.Backend-Override, "s*->.*$", ""); ● Check whether current backend matches if (req.http.tmpORBackend == req.http.tmpCurrentBackend) { ● Use node-http-proxy for the proxy app ○ Remember res.setHeader('Vary', 'Backend-Override'); ○ I use {xfwd: false, changeOrigin: true, hostRewrite: true} 40
  • 41. Debug headers Collect request lifecycle information in a single HTTP response header This is great if... You find it hard to understand what path the request is taking through your VCL You have restarts in your VCL and need to see all the individual backend requests, not just the last one 6
  • 45. Debug journey 45 vcl_recv { set req.http.tmpLog = if (req.restarts == 0, "", req.http.tmpLog ";"); # ... routing ... set req.http.tmpLog = req.http.tmpLog " {{backend}}:" req.url; } vcl_fetch { set req.http.tmpLog = req.http.tmpLog " fetch"; ... } vcl_hit { set req.http.tmpLog = req.http.tmpLog " hit"; ... } vcl_miss { set req.http.tmpLog = req.http.tmpLog " miss"; ... } vcl_pass { set req.http.tmpLog = req.http.tmpLog " pass"; ... } vcl_deliver { set resp.http.CDN-Process-Log = req.http.tmpLog; }
  • 46. Debug journey 46 CDN-Process-Log: apigw:/flags/v1/rnikkei/allocate?output=diff&segid=foo&rank=X HIT (hits=2 ttl=1.204/5.000 age=4 swr=300.000 sie=604800.000); rnikkei_front_0:/ MISS (hits=0 ttl=1.000/1.000 age=0 swr=300.000 sie=86400.000)
  • 47. RUM++ Resource Timing API + data Fastly exposes in VCL. And no backend. This is great if... You want to track down hotspots of slow response times You'd like to understand how successfully end users are being matched to their nearest PoPs 7
  • 48. Resource timing on front end 48 var rec = window.performance.getEntriesByType("resource") .find(rec => rec.name.indexOf('[URL]') !== -1) ; (new Image()).src = '/sendBeacon'+ '?dns='+(rec.domainLookupEnd-rec.domainLookupStart)+ '&connect='+(rec.connectEnd-rec.connectStart)+ '&req='+(rec.responseStart-rec.requestStart)+ '&resp='+(rec.responseEnd-rec.responseStart) ;
  • 49. Add CDN data in VCL & respond with synthetic 49 sub vcl_recv { if (req.url ~ "^/sendBeacon") { error 204 "No content"; } }
  • 51. 51
  • 53. Beyond ASCII Use these encoding tips to embed non-ASCII content in your VCL file. This is great if... Your users don't speak English, but you can only write ASCII in VCL files 8
  • 54. Everyone does UTF-8 now, right? 54 synthetic {"Responsive Nikkeiアルファプログラムのメンバーの皆様、ア ルファバージョンのサイトにアクセスできない場合、 rnfeedback@nex.nikkei.co.jp までその旨連絡ください。"};
  • 55. 55
  • 56. Quick conversion 56 "string" .split('') .map( char => char.codePointAt(0) < 128 ? char : "&#"+char.codePointAt(0)+";" ) .join('') ;
  • 59. 59
  • 60. I have 68 backends 60
  • 61. Varnishlog to the rescue A way to submit a varnish transaction ID to the API, and get all varnishlog events relating to that transaction, including related (backend) transactions 61 > fastly log 1467852934 17 SessionOpen c 66.249.72.22 47013 :80 17 ReqStart c 66.249.72.22 47013 1467852934 17 RxRequest c GET 17 RxURL c /articles/123 17 RxProtocol c HTTP/1.1 17 RxHeader c Host: www.example.com ...
  • 62. Thanks for listening 62 Andrew Betts andrew.betts@ft.com @triblondon Get the slides bit.ly/ft-fastly-altitude-2016