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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Terrence Ryan
September 03, 2016
420
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
500
Which Engine?
tpryan
0
420
Introduction to Containers and Kubernetes
tpryan
2
430
Cloud Next 2017 Roundup
tpryan
2
210
LAMP in Containers
tpryan
1
340
GCP and IoT
tpryan
0
520
Introduction to Machine Learning
tpryan
0
310
Featured
See All Featured
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.9k
The agentic SEO stack - context over prompts
schlessera
0
970
First, design no harm
axbom
PRO
2
1.3k
RailsConf 2023
tenderlove
30
1.6k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
270
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.9k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
Navigating Weather and Climate Data
rabernat
0
560
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Fantastic passwords and where to find them - at NoRuKo
philnash
53
4k
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