www.autoscout24.com
www.autoscout24.com | www.thoughtworks.com
A High-Performance Solution
To Microservices UI Composition
NDC Oslo | June 8, 2016 | Arif Wider & Alexey Gravanov
AutoScout24
2
PL
S
RUS
UA
RO
CZ
D
NL
B
F
A
HR
I
E
BG
TR
17countries
2.4m+cars & motos
~3bpage impressions
per month
Motivation
Project Tatsu
4
Project Tatsu
From a .NET Monolith to AWS-hosted Microservices
Project Tatsu: Goals
5
• Reduce time to market
• Release new features quickly (for test or production)
• Enable teams to innovate independently
Autonomous Teams, Loosely Coupled Services
6
Allow for cross-functional teams that are able to independently
create, improve, and run their services.
 Avoid tight coupling as much as possible!
Don't Compromise Page Performance
7
• Achieve PageSpeed Insights score of 95+
• Strive for low latency
• Benefit from caching whenever possible
tricky to combine with
high team autonomy
Breaking the Monolith
The API Gateway Pattern
8
API Gateway Pattern: AutoScout24 Homepage
9
API Gateway Pattern
10
Home
Header/
Footer
Ads
API Gateway
Mobile
apps
 Great for
page performance :)
API Gateway Pattern: Drawbacks
11
Home
Header/
Footer
Ads
API Gateway
Mobile
apps
no truly independent
vertical feature releases
because of “UI monolith“
 Bad for
team autonomy :(
Breaking the Monolith
The UI Composition Pattern
12
UI Composition Pattern
13
HomeAds
Header/Footer
one service =
one vertical slice
 Great for
team autonomy :)
Challenges of UI Composition
14
• Combine HTML
• Let services deliver their own styles and JavaScript
• Page structure must not break page performance
• Request latency needs to stay low
• Independent and integration testing of UI components
 Tricky for
page performance!
First Attempt
Varnish & ESI
Varnish & ESI
16
ESI Include
17
<html>
<head>
<title>AutoScout24</title>
<!-- CSS of page -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
</head>
<body>
<!-- ESI include of header -->
<esi:include src="http://content.as24.com/fragment/header_de_DE" />
Lorem ipsum....
<!-- JavaScript of page -->
<script src="/assets/home/66ee72f9-main.min.js"></script>
</body>
</html>
ESI Include Resolved
18
<html>
<head>
<title>AutoScout24</title>
<!-- CSS of page -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
</head>
<body>
<!-- CSS of fragment -->
<link rel="stylesheet" href="http://content.as24.com/assets/08ffaf28-main.min.css" />
<ul><li>Home</li><li>Search</li><li>Sell</li></ul>
<!-- JavaScript of fragment -->
<script src="http://content.as24.com/assets/26ed612f-main.min.js"></script>
Lorem ipsum....
<!-- JavaScript of page -->
<script src="/assets/home/66ee72f9-main.min.js"></script>
</body>
</html>
 Bad page speed :(
Multiple ESI Includes
19
<html>
<head>
<title>AutoScout24</title>
<!-- CSS of page -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
<!-- ESI include for header CSS -->
<esi:include src="http://content.example.com/fragment/header_styles" />
</head>
<body>
<!-- ESI include for header -->
<esi:include src="http://content.example.com/fragment/header_de_DE" />
Lorem ipsum....
<!-- JavaScript for page -->
<script src="/assets/home/66ee72f9-main.min.js"></script>
<!-- ESI include for header JavaScript -->
<esi:include src="http://content.example.com/fragment/header_scripts" />
</body>
</html>
Multiple ESI Includes Resolved
20
<html>
<head>
<title>AutoScout24</title>
<!-- CSS for page -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
<!-- CSS for header -->
<link rel="stylesheet" href="http://content.example.com/assets/08ffaf28-main.css" />
</head>
<body>
<ul><li>Home</li><li>Search</li><li>Sell</li></ul>
Lorem ipsum....
<!-- JavaScript for page -->
<script src="/assets/home/66ee72f9-main.min.js"></script>
<!-- JavaScript for header -->
<script src="http://content.example.com/assets/26ed612f-main.js"></script>
</body>
</html>
 Asset version inconsistency :(
Varnish & ESI: Issues
21
• Bad page performance because of page structure
• Attempts to optimize the page structure led to increased
complexity regarding the asset handling
• High burden on the content providing teams
• Combining assets with ESI adds complexity
• AWS ELB as Varnish backend wasn’t working
Requirements for a better solution
22
• References to asset URIs need to be included in HTML snippet
• Therefore post-processing of references is required
• Support for combined assets
• Support for inlining CSS/JS
• Support for shared cache between instances
Jigsaw
How to solve it
Jigsaw Components
24
Request Flow
25
Request Flow
26
Request Flow
27
Request Flow
28
Request Flow
29
Pages
30
are publicly accessible
get called from the client
include fragments
could be cacheable
define contracts
are parts of a page
get called from Nginx SSI
could include fragments
should be cacheable
adhere to contracts
Fragments
SSI Include
31
<html>
<head>
<title>AutoScout24</title>
<!-- Minified and combined css used by this page (not by the fragments) -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
</head>
<body>
<!--#include virtual="/headerservice/fragment/header_de_DE" -->
Lorem ipsum....
<!-- Minified and combined javascript used by this page -->
<script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script>
</body>
</html>
SSI Include Resolved
32
<html>
<head>
<title>AutoScout24</title>
<!-- Minified and combined css used by this page (not by the fragments) -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
</head>
<body>
<head>
<!-- Minified and combined css used by this fragment -->
<link rel="stylesheet" href="/assets/headerservice/08ffaf28-main.min.css" />
</head>
<ul><li>Home</li><li>Search</li><li>Sell</li></ul>
<script type="text/javascript" src="/assets/headerservice/26ed612f-main.js"></script>
Lorem ipsum....
<!-- Minified and combined javascript used by this page -->
<script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script>
</body>
</html>
ngx_pagespeed: combine heads
33
<html>
<head>
<title>AutoScout24</title>
<!-- Minified and combined css used by this page (not by the fragments) -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
<link rel="stylesheet" href="/assets/headerservice/08ffaf28-main.min.css" />
</head>
<body>
<ul><li>Home</li><li>Search</li><li>Sell</li></ul>
<script type="text/javascript" src="/assets/headerservice/26ed612f-main.js"></script>
Lorem ipsum....
<!-- Minified and combined javascript used by this page -->
<script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script>
</body>
</html>
ngx_pagespeed: combine CSS & JS
34
<html>
<head>
<title>AutoScout24</title>
<!-- Minified and combined css by pagespeed -->
<link rel="stylesheet" href="/assets/home,,_ebacb8194-main.min.css
+headerservice,,_08ffaf28-main.min.css" />
</head>
<body>
<ul><li>Home</li><li>Search</li><li>Sell</li></ul>
Lorem ipsum....
<!-- Minified and combined js by pagespeed -->
<script type="text/javascript" href="/assets/home,,_ebacb8194-main.min.js
+headerservice,,_08ffaf28-main.min.js" defer async />
</body>
</html>
Page Performance of Composed Page
35
Page Performance of Composed Page
36
Caching
37
Recap
38
nginx Proxy Cache
39
• Caches responses from upstream services
• Respects cache headers from upstream services
• Supports cache key control via Vary Header
• AWS ElastiCache (memcached, via ngx_srcache module)
Pagespeed Cache
40
• Caches generated assets
• AWS ElastiCache (memcached)
• state is externalized to AWS
• allows for stateless web server machines
• no cache synchronization
• no cold cache
Jigsaw Caching of Assets
41
Jigsaw Caching of Documents
42
Jigsaw Caching of Documents with Vary Header
43
Testing
Local Testing
45
Local Testing
46
Jigsaw Header
Footer
Homepage
Development machine
HeaderJigsaw
Jigsaw Best Practice Analyzer
47
• Checks HTML code for anti-patterns
• defer async
• page barriers (inline scripts)
• CSS outside of <head>
• stylesheet refs with different attributes
• Can run in a deployment pipeline
Things yet to be solved
48
• Authentication
• Native mobile apps
Conclusion
Features of the UI Composition Solution
50
• Teams are in full control of their service's UI and do not need to
rely on others when changing it
• Fragments have a simple structure with head, body and script
parts
• Page performance is not compromised
• Jigsaw serves as an effective cache layer
• Fragments can be tested in isolation, and in integration with
other pages or fragments
• It’s live and serves thousands of requests per second flawlessly :)
www.autoscout24.com
www.autoscout24.com | www.thoughtworks.com
Thank you!
Questions?
Contact:
awider@thoughtworks.com
agravanov@autoscout24.com (@gravanov)

A High-Performance Solution To Microservices UI Composition

  • 1.
    www.autoscout24.com www.autoscout24.com | www.thoughtworks.com AHigh-Performance Solution To Microservices UI Composition NDC Oslo | June 8, 2016 | Arif Wider & Alexey Gravanov
  • 2.
  • 3.
  • 4.
    4 Project Tatsu From a.NET Monolith to AWS-hosted Microservices
  • 5.
    Project Tatsu: Goals 5 •Reduce time to market • Release new features quickly (for test or production) • Enable teams to innovate independently
  • 6.
    Autonomous Teams, LooselyCoupled Services 6 Allow for cross-functional teams that are able to independently create, improve, and run their services.  Avoid tight coupling as much as possible!
  • 7.
    Don't Compromise PagePerformance 7 • Achieve PageSpeed Insights score of 95+ • Strive for low latency • Benefit from caching whenever possible tricky to combine with high team autonomy
  • 8.
    Breaking the Monolith TheAPI Gateway Pattern 8
  • 9.
    API Gateway Pattern:AutoScout24 Homepage 9
  • 10.
    API Gateway Pattern 10 Home Header/ Footer Ads APIGateway Mobile apps  Great for page performance :)
  • 11.
    API Gateway Pattern:Drawbacks 11 Home Header/ Footer Ads API Gateway Mobile apps no truly independent vertical feature releases because of “UI monolith“  Bad for team autonomy :(
  • 12.
    Breaking the Monolith TheUI Composition Pattern 12
  • 13.
    UI Composition Pattern 13 HomeAds Header/Footer oneservice = one vertical slice  Great for team autonomy :)
  • 14.
    Challenges of UIComposition 14 • Combine HTML • Let services deliver their own styles and JavaScript • Page structure must not break page performance • Request latency needs to stay low • Independent and integration testing of UI components  Tricky for page performance!
  • 15.
  • 16.
  • 17.
    ESI Include 17 <html> <head> <title>AutoScout24</title> <!-- CSSof page --> <link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" /> </head> <body> <!-- ESI include of header --> <esi:include src="http://content.as24.com/fragment/header_de_DE" /> Lorem ipsum.... <!-- JavaScript of page --> <script src="/assets/home/66ee72f9-main.min.js"></script> </body> </html>
  • 18.
    ESI Include Resolved 18 <html> <head> <title>AutoScout24</title> <!--CSS of page --> <link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" /> </head> <body> <!-- CSS of fragment --> <link rel="stylesheet" href="http://content.as24.com/assets/08ffaf28-main.min.css" /> <ul><li>Home</li><li>Search</li><li>Sell</li></ul> <!-- JavaScript of fragment --> <script src="http://content.as24.com/assets/26ed612f-main.min.js"></script> Lorem ipsum.... <!-- JavaScript of page --> <script src="/assets/home/66ee72f9-main.min.js"></script> </body> </html>  Bad page speed :(
  • 19.
    Multiple ESI Includes 19 <html> <head> <title>AutoScout24</title> <!--CSS of page --> <link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" /> <!-- ESI include for header CSS --> <esi:include src="http://content.example.com/fragment/header_styles" /> </head> <body> <!-- ESI include for header --> <esi:include src="http://content.example.com/fragment/header_de_DE" /> Lorem ipsum.... <!-- JavaScript for page --> <script src="/assets/home/66ee72f9-main.min.js"></script> <!-- ESI include for header JavaScript --> <esi:include src="http://content.example.com/fragment/header_scripts" /> </body> </html>
  • 20.
    Multiple ESI IncludesResolved 20 <html> <head> <title>AutoScout24</title> <!-- CSS for page --> <link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" /> <!-- CSS for header --> <link rel="stylesheet" href="http://content.example.com/assets/08ffaf28-main.css" /> </head> <body> <ul><li>Home</li><li>Search</li><li>Sell</li></ul> Lorem ipsum.... <!-- JavaScript for page --> <script src="/assets/home/66ee72f9-main.min.js"></script> <!-- JavaScript for header --> <script src="http://content.example.com/assets/26ed612f-main.js"></script> </body> </html>  Asset version inconsistency :(
  • 21.
    Varnish & ESI:Issues 21 • Bad page performance because of page structure • Attempts to optimize the page structure led to increased complexity regarding the asset handling • High burden on the content providing teams • Combining assets with ESI adds complexity • AWS ELB as Varnish backend wasn’t working
  • 22.
    Requirements for abetter solution 22 • References to asset URIs need to be included in HTML snippet • Therefore post-processing of references is required • Support for combined assets • Support for inlining CSS/JS • Support for shared cache between instances
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
    Pages 30 are publicly accessible getcalled from the client include fragments could be cacheable define contracts are parts of a page get called from Nginx SSI could include fragments should be cacheable adhere to contracts Fragments
  • 31.
    SSI Include 31 <html> <head> <title>AutoScout24</title> <!-- Minifiedand combined css used by this page (not by the fragments) --> <link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" /> </head> <body> <!--#include virtual="/headerservice/fragment/header_de_DE" --> Lorem ipsum.... <!-- Minified and combined javascript used by this page --> <script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script> </body> </html>
  • 32.
    SSI Include Resolved 32 <html> <head> <title>AutoScout24</title> <!--Minified and combined css used by this page (not by the fragments) --> <link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" /> </head> <body> <head> <!-- Minified and combined css used by this fragment --> <link rel="stylesheet" href="/assets/headerservice/08ffaf28-main.min.css" /> </head> <ul><li>Home</li><li>Search</li><li>Sell</li></ul> <script type="text/javascript" src="/assets/headerservice/26ed612f-main.js"></script> Lorem ipsum.... <!-- Minified and combined javascript used by this page --> <script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script> </body> </html>
  • 33.
    ngx_pagespeed: combine heads 33 <html> <head> <title>AutoScout24</title> <!--Minified and combined css used by this page (not by the fragments) --> <link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" /> <link rel="stylesheet" href="/assets/headerservice/08ffaf28-main.min.css" /> </head> <body> <ul><li>Home</li><li>Search</li><li>Sell</li></ul> <script type="text/javascript" src="/assets/headerservice/26ed612f-main.js"></script> Lorem ipsum.... <!-- Minified and combined javascript used by this page --> <script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script> </body> </html>
  • 34.
    ngx_pagespeed: combine CSS& JS 34 <html> <head> <title>AutoScout24</title> <!-- Minified and combined css by pagespeed --> <link rel="stylesheet" href="/assets/home,,_ebacb8194-main.min.css +headerservice,,_08ffaf28-main.min.css" /> </head> <body> <ul><li>Home</li><li>Search</li><li>Sell</li></ul> Lorem ipsum.... <!-- Minified and combined js by pagespeed --> <script type="text/javascript" href="/assets/home,,_ebacb8194-main.min.js +headerservice,,_08ffaf28-main.min.js" defer async /> </body> </html>
  • 35.
    Page Performance ofComposed Page 35
  • 36.
    Page Performance ofComposed Page 36
  • 37.
  • 38.
  • 39.
    nginx Proxy Cache 39 •Caches responses from upstream services • Respects cache headers from upstream services • Supports cache key control via Vary Header • AWS ElastiCache (memcached, via ngx_srcache module)
  • 40.
    Pagespeed Cache 40 • Cachesgenerated assets • AWS ElastiCache (memcached) • state is externalized to AWS • allows for stateless web server machines • no cache synchronization • no cold cache
  • 41.
  • 42.
    Jigsaw Caching ofDocuments 42
  • 43.
    Jigsaw Caching ofDocuments with Vary Header 43
  • 44.
  • 45.
  • 46.
  • 47.
    Jigsaw Best PracticeAnalyzer 47 • Checks HTML code for anti-patterns • defer async • page barriers (inline scripts) • CSS outside of <head> • stylesheet refs with different attributes • Can run in a deployment pipeline
  • 48.
    Things yet tobe solved 48 • Authentication • Native mobile apps
  • 49.
  • 50.
    Features of theUI Composition Solution 50 • Teams are in full control of their service's UI and do not need to rely on others when changing it • Fragments have a simple structure with head, body and script parts • Page performance is not compromised • Jigsaw serves as an effective cache layer • Fragments can be tested in isolation, and in integration with other pages or fragments • It’s live and serves thousands of requests per second flawlessly :)
  • 51.
    www.autoscout24.com www.autoscout24.com | www.thoughtworks.com Thankyou! Questions? Contact: awider@thoughtworks.com agravanov@autoscout24.com (@gravanov)