Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
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
650
Go for PHP Developers
tpryan
2
1.1k
Navigating Google Cloud Platform
tpryan
0
460
Which Engine?
tpryan
0
410
Introduction to Containers and Kubernetes
tpryan
2
410
Cloud Next 2017 Roundup
tpryan
2
200
LAMP in Containers
tpryan
1
320
GCP and IoT
tpryan
0
510
Introduction to Machine Learning
tpryan
0
300
Featured
See All Featured
ラッコキーワード サービス紹介資料
rakko
1
3.6M
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
360
Everyday Curiosity
cassininazir
0
220
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.1k
A Tale of Four Properties
chriscoyier
163
24k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
190
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
How to Talk to Developers About Accessibility
jct
2
220
Game over? The fight for quality and originality in the time of robots
wayneb77
1
190
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
280
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
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