david wei and changhao jiang presentation
TRANSCRIPT
(c) 2009 Facebook, Inc. or its licensors. "Facebook" is a registered trademark of Facebook, Inc.. All rights reserved. 1.0
Adaptive Static Resource Optimization
AJAXian Conference 2009Sep 15, 2009 Boston, MA
David Wei and Changhao Jiang
1 Optimization has to be adaptive
2 Adaptive Packager: Internals
3 Adaptive Packager: Operations
4 Lesson learnt
Agenda
Optimization has to be adaptive!
Facebook: a site powered by AJAXChallenges day-to-day
• Deep Integration
• Viral Adoption
• Agile Development
Why we need adaptive packaging?• Day 1: Some smart engineers start a project!
<Print css tag for feature A>
<Print css tag for feature B>
<Print css tag for feature C>
<print HTML of feature A>
<print HTML of feature B>
<print HTML of feature C>
…
“Let’s write a new page with features A, B and C!”
Why we need adaptive packaging?• Day 2: Some smart engineers run YSlow and
thinks…
<Print css tag for feature A>
<Print css tag for feature B>
<Print css tag for feature C>
<print HTML of feature A>
<print HTML of feature B>
<print HTML of feature C>
…
“A & B & C are always used; let’s package them together!”
Why we need adaptive packaging?• Day 2: Awesome!
<Print css tag for feature A&B&C>
<print HTML of feature A>
<print HTML of feature B>
<print HTML of feature C>
…
Why we need adaptive packaging?• Day 3: feature C evolves…
<Print css tag for feature A & B & C>
<print HTML of feature A>
<print HTML of feature B>
If (users_signup_for_C()) { <print HTML of feature C>}
…
Why we need adaptive packaging?• Day 3:
<Print css tag for feature A & B & C>
<print HTML of feature A>
<print HTML of feature B>
If (users_signup_for_C()) { <print HTML of feature C>}
…
A&B are always used, while C is not. ..
Why we need adaptive packaging?• Day 4: feature C is deprecated
<Print css tag for feature A & B & C>
<print HTML of feature A>
<print HTML of feature B>
// no one uses C { <print HTML of feature C>}
…
Why we need adaptive packaging?• Day 4: we start to send unused bits
<Print css tag for feature A & B & C>
<print HTML of feature A>
<print HTML of feature B>
// no one uses C { <print HTML of feature C>}
…
It is hard to remember we should remove C here.
Why we need adaptive packaging?• One months later…
<Print css tag for feature A & B & C & D & E & F & G…>
if (F is used) <print HTML of feature F>
<print HTML of feature G>
if (F is not used) { <print HTML of feature E>}
…
Thousands of dead CSS rules in the package.
Static Resource Management @ FacebookChallenges:
• Deep Integration
• Viral Adoption
• Agile Development
Responses:
• Separate requirement declaration and delivery of static resources
• Requirement declaration: lives with HTML generation
• Delivery: Globally optimized based on trace analysis
Adaptive Packager: Internals
Static Resource Management
• Back to Day 1:
require_static(A_css); <render HTML of feature A>
require_static(B_css); <render HTML of feature B>
require_static(C_css);<render HTML of feature C>
<deliver all required CSS>
<print all rendered HTML>
Separate Declaration from actual Delivery
Global Optimization on Delivery
Requirement Declaration lives with HTML
Offline analysisPackager: Global JS/CSS Optimization
Online process
require_static(A_css); <render HTML of feature A>
require_static(B_css); <render HTML of feature B>
require_static(C_css); <render HTML of feature C>
<deliver all required CSS>
<print all rendered HTML>
Usage Pattern logs
Packaging algorithm
“Optimal” packages
Packager: modelsCost/Benefit tradeoff model:
▪ To package two CSS/JS files A & B:
▪ Cost: for page requests that only uses A, we waste the bytes of B (bandwidth)
▪ Benefit: for page requests that uses both A and B: we save one round trip (latency )
▪ Maximize “Profit” (Benefit – Cost)
▪ Future: Users with different network connections have different packaging solutions
Usage Pattern logs
Packaging algorithm
“Optimal” packages
Packager: modelsPotential extensions (and trade-offs):
▪ Consider all resources used in user browsing sessions, instead of user page loads
▪ first page slower, subsequent pages faster
▪ Consider cache probability: new files change more
▪ New user slower, old users faster
▪ Consider other costs:
▪ CSS rules
▪ JS executions
▪ HTTP header overheads
Usage Pattern logs
Packaging algorithm
“Optimal” packages
Packager: algorithmA classic optimization problem:
▪ Algorithms:
▪ Greedy algorithm
▪ Simulated Annealing
▪ Clustering algorithms
▪ Trade-off between offline computation cost and accuracy:
▪ Greedy is good enough for us
Usage Pattern logs
Packaging algorithm
“Optimal” packages
Adaptive Performance Optimization: moreTrace-based analysis for:
• JS / CSS package optimization, image spriting
• Progressive rendering for common JS/CSS/Images
• Prioritization of resource delivery
Adaptive Packager: Operations
Packager: DeploymentFully deployed since Nov 2008
• Weekly based on previous week’s usage pattern (>100K unique usage patterns)
• Javascript and CSS packaging only (image soon)
• Efficiency monitors: size of wasted JS/CSS bytes; JS/CSS pkg numbers
Packager: scalable with developmentNov 2008 => May 2009
Date# of JS files
# of JS bytes
# of pkg at a
home.php
# of bytes at a
home.php
Nov 2008 461 4.4 MB 29 629 KB
May 2009 729 5.9 MB 14 560 KB
Packager: scalable with developmentNov 2008 => May 2009
Date# of JS files
# of JS bytes
# of pkg at a
home.php
# of bytes at a
home.php
Nov 2008 461 4.4 MB 29 629 KB
May 2009 729 5.9 MB 14 560 KB
'js/careers/jobs.js’, 'js/lib/ui/timeeditor.js’, 'resume/js/resumepro.js’, 'resume/js/resumesection.js’
Packager: scalable with developmentNov 2008 => May 2009
Date # CSS files# of CSS
bytes
# of pkg at a
home.php
# of bytes at a
home.php
Nov 2008 487 1.7 MB 24 69 KB
May 2009 706 1.9 MB 15 64 KB
Date# of JS files
# of JS bytes
# of pkg at a
home.php
# of bytes at a
home.php
Nov 2008 461 4.4 MB 29 629 KB
May 2009 729 5.9 MB 14 560 KB
Packager: Experimental Image SpritingThe puzzle of image spriting:
• Thousands of virtual gifts with static images, which to sprite?
Packager: Experimental Image SpritingThe puzzle of image spriting:
• The answer is…
Packager: Experimental Image SpritingData set: ~3500 images in the code base at this
time
• comparing to <1500 js/css files
Lesson learnt
Human errors are unavoidableAutomatic analysis is preferable:
require_static(A_css); //forgot to remove the require_static
require_static(B_css); <render HTML of feature B>
require_static(C_css); <render HTML of feature C>
<deliver all required CSS>
<print all rendered HTML>
Regression detection can be trickierA measurement framework is necessary:
“The page has 10KB more Javascripts!”
• Regression introduced by Packager? Or by developers? Or by feature adoption with new usage patterns?
• Which feature introduces it?
Summary
▪ Performance optimization has to be adaptive
▪ Good interfaces help a lot
▪ This is an emerging area -- long way to go
Thank you!