class: center, middle
.blue[Metal]
A Fast, Dynamic Origin Server
↓
.blue[Hammer]
.orange[A Better Server Load Generation Tool]
↓
.width80[ ![Network Diagram](./Network_Diagram.png) ] Winter Guerra August, 2014 --- .left-column[ ## What is Hammer? ] .right-column[ Hammer is a load generation tool that simulates HTTP load across an Akamai network. .center[![Network Diagram](./Network_Diagram.png)] This is especially useful for dev, lab, and QA teams that need to test their server software using realistic load before deploying new distributions into the wild. ] --- .left-column[ ## What is Hammer? ## Why does Hammer Exist? ] .right-column[ Hammer exists because my team needed a fast, zero-setup method of generating load against Ghost servers. Current load generators in SQA did not quite fit my team's requirements because: * Current software load generators are too resource intensive * They require complex build dependencies and build chains * They are not cross platform compatible
.green[*However, Hammer provides a solution to all the problems listed above.*] ] --- .left-column[ ## What is Hammer? ## Why does Hammer Exist? ## What makes Hammer Different? ] .right-column[ Currently, Hammer excels in generating load by featuring: * .green[Over 2.7x] load generation capacity vs current tools.red[*] * .green[Reduction in COGS].blue[*] through improved efficiency * Support for HTTP/1.1 "chunked" requests * An innovative asynchronous and clustered Node.js backend * Completely cross-platform interpreted CoffeeScript source code .green[*No compiling required!*] * A user-friendly RESTful tasking API * Transparent "Behavior Driven Development" unit and regression tests
.footnote[ .red[\\*] *Measured by Ghost CPU utilization while under load from Hammer and Metal* .blue[\\*] *COGS: Cost of goods and services. Eg. Operating cost.* ] ] --- class: tall ## How Does Hammer's Performance Compare?
--- class: tall ## How Does Hammer's Performance Compare?
--- .left-column[ ## Under the Hood of Hammer's Technology ] .right-column[ Hammer runs on Node.js, an asynchronous server-side JavaScript framework. Node.js allows Hammer to generate load more efficiently by handling all IO requests asynchronously. Hammer also benefits from these Node.js modules: * .blue[*Mocha*], .blue[*SuperTest*], and .blue[*Expect.js*] for unit tests. * .blue[*Q*] for complex promise tree resolution. * .blue[*Express*] for the RESTful API interface. * .blue[*CoffeeScript*] for improved async callback readability. * .blue[*Cluster*] for parallelization of Hammer's workload. * .blue[*Groc*] for automated documentation generation. ] --- class: inverse, center, middle ### *Now, onto my second internship project:* ## Metal - A fast, dynamic origin server .orange[(Written because Hammer was too powerful for SQA's original origin server...)] --- class: center, middle
.blue[Metal]
.orange[A Fast, Dynamic Origin Server
] ↓
.blue[Hammer]
A Better Server Load Generation Tool
↓
.width80[ ![Network Diagram](./Network_Diagram.png) ] Winter Guerra August, 2014 --- .left-column[ ## What is Metal? ] .right-column[ Metal is a fast, dynamic origin server that runs on Node.js. #### Metal can simulate websites with the following: * Large amounts of dynamic pages * Millions of large videos or files * And unlimited music/video streaming content #### In terms of .green[*content cacheability*], Metal can simulate: * Expirable, but semi-cacheable content * Uncacheable content * And completely static cacheable content .blue[ *In addition (due to Metal's dynamic nature), using Metal allows for Hammer to easily leverage .green[cache-thrashing] attacks to achieve higher test load on a Ghost server.* ] ] --- .left-column[ ## What is Metal? ## Why Does Metal Exist? ] .right-column[ Normally, QA teams would use off the shelf origin servers such as Apache and Jetty to simulate customer cloud setups for Ghost traffic testing. However, Apache and Jetty are not very good at simulating realistic customer setups for the following reasons: * Both server softwares require preloading of all desired test content *(movies, files, images, scripts, etc...)* * .red[This takes up space on the origin server and is a hassle to generate and manage] * Are not good at simulating arbitrary HTTP response codes *(`4xx`, `5xx`, etc...)* * Are not good at simulating different types of cacheable/uncacheable content. *(`cache-control: no-cache`, etc...)* .green[*However, Metal makes all these scenarios possible with zero configuration!*] ] --- .left-column[ ## What is Metal? ## Why Does Metal Exist? ## How Can I Use Metal? ] .right-column[ Using Metal as an origin server, simulating upstream files is as easy as requesting a simple url! Let's ask for a .blue[*large*] file: ```bash origin="origin.platform.qa.akamai.com" curl -v "$origin/random_data_varied/1gb" ``` For .blue[*tiny*] files: ```bash curl -v "$origin/random_data_varied/12b" ``` For simulating .blue[HTTP `404`] pages that respond with data: ```bash curl -v "$origin/random_data_varied/12b/response_code/404" ``` For testing handling of .blue[*cacheable/uncacheable*] files: ```bash curl -v "$origin/somepath/cache_control/10/hours/cache_it.js" # The file below is uncacheable! curl -v "$origin/cache_control/0/seconds/not_cacheable.html" ``` What about files with .blue[different MIME-types]? ```bash curl -v "$origin/random_data_varied/50b/someBinaryFile.bin" curl -v "$origin/random_data_varied/50b/someMovieFile.mov" ``` ] --- .left-column[ ## Deeper Under the Hood of Metal's Technology: ### - Node.js & CoffeeScript ] .right-column[ Metal is innovative in that it uses *Node.js*, a server-side JavaScript platform, and *CoffeeScript* (a derivative of JavaScript) to run its services. By using Node.js and CoffeeScript, Metal is completely cross platform compatible. Here's a small example of how Node.js and CoffeeScript make Metal's code easy to read: ```coffeescript startWebserver: (app, credentials) => # Boot up webserver worker @httpServer = http.createServer(app) @httpsServer = https.createServer(credentials, @app) @httpServer.listen(80) @httpsServer.listen(443) ``` ] --- .left-column[ ## Deeper Under the Hood of Metal's Technology: ### - Node.js & CoffeeScript ### - Express.js & Custom Middleware ] .right-column[ To extend the functionality of the Node.js framework, Metal uses a popular package called *Express.js*. Using *Express.js*, Metal takes advantage of JavaScript's callback functionality to create small understandable anonymous "middleware" functions that simplify request parsing. Here's an example of the Metal middleware that handles preprocessing and advertising of the `Accept-Ranges: bytes` feature of Metal: ```coffeescript # Allow us to accept HTTP range requests. # This will respond with HTTP `206 Partial Request` # only when a partial request is made. router.use (req, res, next) -> # Advertise our new feature! res.set('Accept-Ranges', 'bytes') if req.get('Range')? res.status(206) # Handle range requests next() ``` ] --- .left-column[ ## Deeper Under the Hood of Metal's Technology: ### - Node.js & CoffeeScript ### - Express.js & Custom Middleware ### - Q Promises ] .right-column[ To help deal with complex chains of async callbacks, both Metal and Hammer use the *Q* promise framework to provide high level abstraction of async functions. Here's an example of Metal and Hammer's async startup script, written using Q: ```coffeescript class Initialize constructor: (@paths, @callback, @debug) -> run: () => # Find which user the server will be running as. @searchForDeescalatedUser() # Make log files. chown them to our deescalated user. .then(@makeLogDirectories) # Deescalate server's privs .then(@deescalate) .done(@callback) ``` Here's an example of a async function using Q promise abstraction: ```coffeescript searchForUser: (user) => deferred = Q.defer() # Check if user exists by running a unix command. exec "id -u #{user}", (error, stdout, stderr) -> if not error deferred.resolve(user) else deferred.reject() return d.promise ``` ] --- .left-column[ ## Deeper Under the Hood of Metal's Technology: ### - Node.js & CoffeeScript ### - Express.js & Custom Middleware ### - Q Promises ### - Mocha & SuperTest BDD Testing ] .right-column[ To ensure quality, Metal uses the *Mocha* CoffeeScript test framework alongside *SuperTest* and *expect.js* to perform easy to understand unit and regression tests on Metal's codebase. Currently, *all* features of Metal have regression tests, while some also have deeper unit tests. Here's an example of some of Metal's regression tests: ```coffeescript describe 'Deployed Origin Server', () => before (done) -> # Spin up a local Metal server # ...... it 'should serve up 1MB static web pages', (done) -> request.get('/random_data_same/1mb/') .buffer() .expect(200) .end (err, res) -> throw err if err expect(res.text.length).to.be 1024**2 done() ``` *Resulting Test Output:* ```bash Deployed Origin Server ✓ should serve up 1MB static web pages 1 passing (5s) ``` ]