Velocity China 2012 Proactive WPO

Preview:

DESCRIPTION

Web Performance is a vigilant task and even well monitored websites frequently get out of performance monitoring radar resulting in performance regression pushed to end users. Real User Monitoring is an essential tool but it's not enough as users will be ultimately the ones raising the red flag for eventual performance regression introduced after every release cycle. YSlow has been helping the industry websites performance by analyzing and suggesting the appropriate fix through browsers extensions manually run from productions end points. Now YSlow powered by NodeJS and PhantomJS is capable of been seamlessly plugged in the Continuous Integration pipeline raising the red flag for performance regression in the building process, assuring the website minimum performance standards and avoiding unnecessary end user bad experience. Besides YSlow as a way to prevent regression, at Twitter we strive to keep and improve performance of every new release through automated branch performance comparison tool powered by WebPageTest and WebPageTest API Wrapper which gives accurate metrics to avoid even milliseconds of performance regression in production.

Citation preview

Proactive WPO@marcelduran

velocity@marcelduran.com

about:me

I'm not here

I'm from here on

V is for Vigilante

http://usa-moscow.blogspot.com/2010/09/more-hot-water.html

Performance Radarhttp://www.flickr.com/photos/benfrantzdale/1056282822/

“if you can’t measure it, you can’t improve it”

— Lord Kelvin

worst case: no instrumentshttp://www.flickr.com/photos/timothyhackworth/753783003/

build test

deploy

users

review

reactive

better case: RUMhttp://www.flickr.com/photos/pj/6116201547/

Real User Measurementshttp://lognormal.com/features/

github.com//boomerang

lognormal

build test

deploy

users

monitor

reactive

YSlow manually

YSlow automationhttp://www.flickr.com/photos/snazzyguy/3381047684/

+

much better: RUM + YSlow (CI)http://donq.com/recipes/rum-sour

+

build test

deploymonitor

users

wpo

proactive

jul/07

+174k users+3.3mi downloadsTop 25 2bi add-ons downloaded

jul/07 mar/11

~171k users

jul/07 jun/11mar/11

jul/07 jun/11mar/11 aug/11

~86k users

jul/07 jun/11mar/11 aug/11

oct/11

jul/07 jun/11mar/11 aug/11

oct/11 dec/11

jul/07 jun/11mar/11 aug/11

oct/11 feb/12dec/11

first 24 hours437

37so far

91977

5th anniversaryhttp://www.flickr.com/photos/spool32/5045502202

jul/07 jun/11mar/11 aug/11

oct/11 feb/12dec/11 apr/12

jul/07 jun/11mar/11 aug/11

oct/11 feb/12dec/11 apr/12 jun/12

YSlow Command Line

$ npm install yslow -g

$ yslow --help Usage: yslow [options] [file ...]

Options:

-h, --help output usage information -V, --version output the version number -i, --info <info> specify the information to display/log

(basic|grade|stats|comps|all) [basic] -f, --format <format> specify the output results format

(json|xml|plain) [json] -r, --ruleset <ruleset> specify the YSlow performance ruleset to be used

(ydefault|yslow1|yblog) [ydefault] -b, --beacon <url> specify an URL to log the results -d, --dict include dictionary of results fields -v, --verbose output beacon response information

Examples:

yslow file.har yslow -i grade -f xml -b http://server.com/beacon file1.har file2.har yslow -info all --format plain /tmp/*.har yslow -i basic --rulseset yslow1 -d < file.har curl example.com/file.har | yslow -i grade -b http://server.com/beacon -v

HAR file

{ "log": { "version": "1.1", "pages": [ { "startedDateTime": "2012-08-16T18:27:29.000+00:00", "id": "page_1_0", "pageTimings": { "onLoad": 13701, . . .

$ yslow file.har$ yslow file1.har file2.har file3.har$ yslow my-har-files/*.har$ yslow < file.har$ curl http://foo.com/file.har | yslow

-f, --format <format> (json|xml|plain)

$ yslow foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981 }

$ yslow --format plain foo.com.harsize: 96.4K (98725 bytes)overall score: B (89)url: http://www.foo.com/# of requests: 9ruleset: ydefaultpage load time: 981

$ yslow --format xml foo.com.har<?xml version="1.0" encoding="UTF-8"?><results> <w>98725</w> <o>89</o> <u>http://www.foo.com/</u> <r>9</r> <i>ydefault</i> <lt>981</lt></results>

-i, --info <info> (basic|grade|stats|comps|all)

$ yslow foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981 }

$ yslow --info grade foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981, g: { ynumreq: { score: 92, components: [] }, ycdn: { score: 80, components: ['a.com', 'b.com'] }, ... yfavicon: { score: 100, components: [] } }}

$ yslow --info stats foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981, stats: { doc: { r: 1, w: 18419 }, css: { r: 2, w: 20951 }, image: { r: 3, w: 29553 }, js: { r: 2, w: 10852 }, cssimage: { r: 1, w: 18950 } }}

$ yslow --info comps foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981, comps: [ {type:'doc', url:'foo.com', size:1841, resp:41, gzip:613}, {type:'css', url:'bar.css', size:3062, resp:98, gzip:989}, ... {type:'js', url:'baz.js', size:2445, resp:86, gzip:834} ]}

$ yslow --info all foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981, g: { ynumreq: { score: 92, components: [] }, ... } stats: { doc: { r: 1, w: 18419 }, css: { r: 2, w: 20951 }, ... } comps: [ {type:'doc', url:'foo.com', size:1841, resp:41, gzip:613}, ... ]}

-d, --dict

$ yslow -i basic --dict foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981, dictionary: { w: 'size', o: 'overall score', u: 'url', r: 'total number of requests', i: 'id of the ruleset used', lt: 'page load time', grades: '100 >= A >= 90 > B >= 80 > C >= 70 > D >= 60 > E >= 50 > F >= 0 > N/A = -1' }}

-r, --ruleset <ruleset>(ydefault | yslow1 | yblog)

Minimize HTTP RequestsUse a Content Delivery NetworkAvoid empty src or hrefAdd an Expires or a Cache-Control HeaderGzip ComponentsPut StyleSheets at the TopPut Scripts at the BottomAvoid CSS ExpressionsMake JavaScript and CSS ExternalReduce DNS LookupsMinify JavaScript and CSSAvoid RedirectsRemove Duplicate ScriptsConfigure ETagsMake AJAX CacheableUse GET for AJAX RequestsReduce the Number of DOM ElementsNo 404sReduce Cookie SizeUse Cookie-Free Domains for ComponentsAvoid FiltersDo Not Scale Images in HTMLMake favicon.ico Small and Cacheable

ydefault(aka YSlow V2)

23 rules

Minimize HTTP RequestsUse a Content Delivery NetworkAdd an Expires or a Cache-Control HeaderGzip ComponentsPut StyleSheets at the TopPut Scripts at the BottomAvoid CSS ExpressionsMake JavaScript and CSS ExternalReduce DNS LookupsMinify JavaScript and CSSAvoid RedirectsRemove Duplicate ScriptsConfigure ETags

yslow1(aka YSlow V1/classic)

13 rules

Minimize HTTP RequestsAvoid empty src or hrefGzip ComponentsPut StyleSheets at the TopPut Scripts at the BottomAvoid CSS ExpressionsReduce DNS LookupsMinify JavaScript and CSSAvoid RedirectsRemove Duplicate ScriptsReduce the Number of DOM ElementsNo 404sAvoid FiltersDo Not Scale Images in HTMLMake favicon.ico Small and Cacheable

yblog(aka small site/blog)

15 rules

-b, --beacon <url>-v, --verbose

$ yslow --beacon http://server.com/ foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981 }

$ yslow -b http://server.com/ --verbose foo.com.har{ w: 98725, o: 89, u: 'foo.com', r: 9, i: 'ydefault', lt: 981, beacon: { status: 200, headers: { "content-type": 'text/html; charset=utf-8', "date": 'Thu, 02 Aug 2012 17:23:33 GMT', "content-length": '3', "connection": 'close' }, body: 'ok\n' }}

before after

Case: Y! Continuous Deployment

before after

No Performance Test Suite

BOO!

YSlow for PhantomJShttp://www.flickr.com/photos/pedroferrer/3615212504

$ phantomjs yslow.js http://yslow.org

-f, --format <format>

( json | xml | plain | tap | junit )

$ phantomjs yslow.js -i basic --format tap http://yslow.org

TAP version 131..1ok 1 B (88) overall score

$ phantomjs yslow.js -i grade --format tap http://yslow.org

TAP version 131..24ok 1 B (88) overall scorenot ok 2 C (72) ynumreq: Make fewer HTTP requests --- message: This page has 7 external Javascript scripts ...ok 3 C (70) ycdn: Use a Content Delivery Network (CDN) --- message: There are 3 static components not on CDN. offenders: - "yslow.org: 1 component, 8.0K (8.0K GZip)" - "fonts.googleapis.com: 1 component, 1.0K (1.0K GZip)" - "widgets.twimg.com: 1 component, 0.8K" ...ok 4 A (100) yemptysrc: Avoid empty src or hrefnot ok 5 F (12) yexpires: Add Expires headers --- message: There are 5 static components without a far-future expiration date. offenders: - "http://yslow.org/stylesheets/styles-min.css"...

$ phantomjs yslow.js -i basic --format junit http://yslow.org

<?xml version="1.0" encoding="UTF-8" ?><testsuites> <testsuite name="YSlow" tests="1" failures="1"> <testcase name="overall score" status="C (79)"> <failure/> </testcase> </testsuite></testsuites>

-t, --threshold <score>( [0-100] | [A-F] | {json} )

default: 80

-t B-t 75-t '{"overall": "C", "ycdn": "F"}'-t '{"ycdn": "F", "yexpires": 75}'

-u, --ua "<user agent>"

e.g: -u "Mozilla/4.0 (compatible; MSIE 6)"

-vp, --viewport <WxH>

e.g: -vp 640x960

-ch, --headers <JSON>

e.g: -ch '{"Cookie": "foo=bar"}'

-c, --console <level>(0: none | 1: msg | 2: msg+line+source)

YSlow + CI = BFF

node.js server

local HAR file uploadcurl http://yslow.nodester.com/ -F 'har=@localfile.har'

remote HAR filecurl 'http://yslow.nodester.com/?har=http://server.com/foo.har'

HAR {json} stringcurl http://yslow.nodester.com/ -d 'har={"log":{"version":"1.1", ... }}'

+ +

curl "http://yslow.nodester.com/?har=http%3A%2F%2Fwww.webpagetest.org%2Fexport.php%3Ftest%3D120627_MC_5WD

&i=grade&b=http%3A%2F%2Fwww.showslow.com%2Fbeacon%2Fyslow%2F&v=1"

High Performance

A A A A ...

best: RUM + (YSlow + WPT) CIhttp://donq.com/recipes/rum-sour/

++

WebPageTest

build test

deploy

monitor

wpo

perf

users

proactive

performance boxes

branch A branch Bprod

...

branches comparison

vs

Xms

prod

X+100ms

branch A

X-50ms

branch B

http://marcelduran.com/webpagetest-api

github.com/marcelduran/webpagetest-api

++

+vs

/getyslow

@yslowyslow.org

slides icons: http://www.iconfinder.com/

谢谢