Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
30,000,000 Requests in a Hour in the Cloud
Search
Terrence Ryan
September 03, 2016
410
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
30,000,000 Requests in a Hour in the Cloud
Terrence Ryan
September 03, 2016
More Decks by Terrence Ryan
See All by Terrence Ryan
Vms, Serverless, or Containers
tpryan
0
670
Go for PHP Developers
tpryan
2
1.1k
Navigating Google Cloud Platform
tpryan
0
490
Which Engine?
tpryan
0
420
Introduction to Containers and Kubernetes
tpryan
2
420
Cloud Next 2017 Roundup
tpryan
2
200
LAMP in Containers
tpryan
1
330
GCP and IoT
tpryan
0
520
Introduction to Machine Learning
tpryan
0
310
Featured
See All Featured
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
560
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
For a Future-Friendly Web
brad_frost
183
10k
AI: The stuff that nobody shows you
jnunemaker
PRO
10
1.1k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
YesSQL, Process and Tooling at Scale
rocio
174
15k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
The browser strikes back
jonoalderson
0
1.7k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Done Done
chrislema
187
17k
How to Talk to Developers About Accessibility
jct
2
560
Transcript
‹#› @tpryan Terrence Ryan Developer Advocate 30,000,000 Requests An Hour
In The Cloud
‹#› @tpryan Who are you?
‹#› @tpryan 01 Introduction What was I trying to do
None
‹#› @tpryan Demo: App Engine
‹#› @tpryan App Engine • Writes to Firebase • Writes
to Cloud Storage • Run the Visualizer
‹#› @tpryan Compute Engine • Load Generators • Apache Bench
• Remote Command Execution
‹#› @tpryan Firebase • Realtime Display • Tracking all load
‹#› @tpryan Cloud Storage • Proof of activity • Object
notification
‹#› @tpryan App Engine • Process Notifications from Cloud Storage
‹#› @tpryan Planned / //Write to Firebase //Write to Cloud
Storage //Receive realtime //updates /visualizer /storage //Write to Firebase //Display updates //Store file //Send Notification http://load-demo.appspot.com
‹#› @tpryan Actual / //Write to Firebase //Write to Cloud
Storage //Receive realtime //updates /visualizer /storage //Write to Firebase //Display updates //Store file //Send Notification http://load-demo.appspot.com
@briandorsey 30,000,000 requests in one hour
@briandorsey What do you call a site that gets 30,000,000
hits an hour?
@briandorsey
@briandorsey I should try and do that and mean it
‹#› @tpryan 02 Ramping up What is Google Cloud Platform
@briandorsey 30,000,000 qph /60/60 8,333 qps
@briandorsey Ramp the demo up to 8,333 qps
‹#› @tpryan Demo: App Engine
‹#› @tpryan URLFetch • Network abstraction layer for http •
Most service calls
‹#› @tpryan Source Code $instance = $_SERVER['INSTANCE_ID']; $urlToPatch = $fbBaseURL
. "appengine/" . $instance . ".json"; $urlToPost = $fbBaseURL . "appengine/" . $instance . “/sessions.json"; $instance_data = new stdClass(); $instance_data->instance = $instance; $instance_data->updated = time(); $instance_json = json_encode($instance_data); $ch = curl_init(); $output = patch($ch, $urlToPatch, $instance_json); $output = post($ch, $urlToPost, $instance_json); $name = json_decode($output)->name; $filename = $gcsBaseURL . $instance . "/file" . $name . ".txt"; file_put_contents($filename, $name); $instance = $_SERVER['INSTANCE_ID']; $urlToPatch = $fbBaseURL . "appengine/" . $instance . ".json"; $urlToPost = $fbBaseURL . "appengine/" . $instance . “/sessions.json"; $instance_data = new stdClass(); $instance_data->instance = $instance; $instance_data->updated = time(); $instance_json = json_encode($instance_data); $ch = curl_init(); $output = patch($ch, $urlToPatch, $instance_json); $output = post($ch, $urlToPost, $instance_json); $name = json_decode($output)->name; $filename = $gcsBaseURL . $instance . "/file" . $name . ".txt"; file_put_contents($filename, $name);
‹#› @tpryan Source Code function patch($ch, $url, $json){ curl_setopt($ch, CURLOPT_URL,
$url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH"); curl_setopt($ch, CURLOPT_POSTFIELDS, $json); return curl_exec($ch); } function post($ch, $url, $json){ curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $json); return curl_exec($ch); }
‹#› @tpryan
‹#› @tpryan
‹#› @tpryan
@briandorsey 660,000 qpm /60 11,000 qps /3 3,666 qps
‹#› @tpryan 03 Fix 1 Sockets
‹#› @tpryan
‹#› @tpryan
‹#› @tpryan
‹#› @tpryan Demo: App Engine
‹#› @tpryan Reasons for failure • Sockets are lighter •
But implementation is not configurable • So write your own socket client?
‹#› @tpryan 04 Fix 2 Memcache
‹#› @tpryan Assumptions • Visualization needs to be realtime •
But does it?
‹#› @tpryan Memcache on App Engine
‹#› @tpryan Pseudo Code // store instances request count //
Get list of keys // Display request counts Bad Idea
‹#› @tpryan
‹#› @tpryan Source Code $memcache = new Memcached; $instance =
$_SERVER['INSTANCE_ID']; $request = $_SERVER['REQUEST_LOG_ID']; $result = $memcache->increment($instance); if ($result == 1 ){ $result = $memcache->append("instances", "|" . $instance); if ($memcache->getResultCode() == 14){ $result = $memcache->set("instances", $instance); } } $filename = $gcsBaseURL . $instance . "/file" . $request . ".txt"; file_put_contents($filename, $filename);
‹#› @tpryan Close but no cigar • Losing instances •
Analysis revealed: • All requests were firing • All requests were registering • Cause: Memcache strings were getting too long
‹#› @tpryan Source Code $memcache = new Memcached; $instance =
$_SERVER['INSTANCE_ID']; $request = $_SERVER['REQUEST_LOG_ID']; $memcache->increment("total"); $result = $memcache->increment($instance); if ($result == 1 ){ $result = $memcache->append("instances", "|" . $instance); if ($memcache->getResultCode() == 14){ $result = $memcache->set("instances", $instance); } } $filename = $gcsBaseURL . $instance . "/file" . $request . ".txt"; file_put_contents($filename, $filename); $memcache = new Memcached; $instance = $_SERVER['INSTANCE_ID']; $request = $_SERVER['REQUEST_LOG_ID']; $memcache->increment("total"); $result = $memcache->increment($instance); if ($result == 1 ){ $result = $memcache->append("instances", "|" . $instance); if ($memcache->getResultCode() == 14){ $result = $memcache->set("instances", $instance); } } $filename = $gcsBaseURL . $instance . "/file" . $request . ".txt"; file_put_contents($filename, $filename);
‹#› @tpryan Source Code function whichInstanceList($instance){ $last = substr($instance, -1);
return "instances-" . $last; }
‹#› @tpryan Demo: App Engine
‹#› @tpryan 05 Conclusion What did I learn
@briandorsey Wait, you’re giving up realtime without a fight?
‹#› @tpryan 05 Fix 3 Brining back the realtime
‹#› @tpryan Current / //Write to Memcache //Write to Cloud
Storage //Receive realtime //updates /visualizer http://load-demo.appspot.com //Display Updates //Store request details
‹#› @tpryan Current / //Write to Memcache //Write to Cloud
Storage //Receive realtime //updates /visualizer http://load-demo.appspot.com //Display Updates //Store request details //Read memcache //Write to Firebase /realtime.php
‹#› @tpryan Pseudo Code // Get list of instances //
Get list of number of requests for each instance // Send data for each request to firebase Bad Idea
‹#› @tpryan How Firebase works • appengine • instance1 •
request1 • request2 • request3 • request4 • request5 • request6 • instance2
‹#› @tpryan How Firebase works { "appengine": { "instance1": {
"request1": "", "request2": "", "request3": "", "request4": "", "request5": "", "request6": "" }, "instance2": {} } }
‹#› @tpryan How Firebase works { "appengine": { "instance1": {
"request1": "", "request2": "", "request3": "", "request4": "", "request5": "", "request6": "" }, "instance2": {} } } /appengine/instance1/request2.json GET POST PATCH
‹#› @tpryan How Firebase works { "appengine": { "instance1": {
"request1": "", "request2": "", "request3": "", "request4": "", "request5": "", "request6": "" }, "instance2": {} } } /appengine/instance1.json GET POST PATCH
‹#› @tpryan How Firebase works { "appengine": { "instance1": {
"request1": "", "request2": "", "request3": "", "request4": "", "request5": "", "request6": "" }, "instance2": {} } } /appengine.json GET POST PATCH
‹#› @tpryan
‹#› @tpryan Batch Memcache calls getMulti()
‹#› @tpryan Let’s send too much stuff • appengine •
00c61b117c1d99526c06775beef85526a00dbdd295ffef80dbe702a836b0 • request1 • 00c61b117c1d99526c06775beef85526a00dbdd295ffef80dbe702a836b0 • request2 • 00c61b117c1d99526c06775beef85526a00dbdd295ffef80dbe702a836b0 • request3 • 00c61b117c1d99526c06775beef85526a00dbdd295ffef80dbe702a836b0 • request4 • 00c61b117c1d99526c06775beef85526a00dbdd295ffef80dbe702a836b0 • request5 • 00c61b117c1d99526c06775beef85526a00dbdd295ffef80dbe702a836b0 • request6 • 00c61b117c1d99526c06775beef85526a00dbdd295ffef80dbe702a836b0 • 00c61b117cf44784cd0c142018b2ada185ce6d3472a963342388ef123a30
‹#› @tpryan Let’s send too much stuff • appengine •
00c61b117c1d99526c06775beef85526a00dbdd295ffef80dbe702a836b0 • 6 • 00c61b117cf44784cd0c142018b2ada185ce6d3472a963342388ef123a30 • 1
‹#› @tpryan
‹#› @tpryan
‹#› @tpryan
‹#› @tpryan
‹#› @tpryan
‹#› @tpryan Source Code $task1 = new PushTask('/realtime.php'); $task1->add("realtimesynch");
‹#› @tpryan Demo: App Engine
‹#› @tpryan 06 Conclusion What did I learn
@briandorsey Safety Quotas are not just something to be gotten
around
@briandorsey Bundle up data calls when you can
@briandorsey Be prepared to make compromises
@briandorsey Time for a language change?
‹#› @tpryan Thank You terrenceryan.com @tpryan This preso: http://bit.ly/tpryan-30m