MOBILE API AND CACHING Making the most of your APIs
Dec 04, 2014
MOBILE API AND CACHINGMaking the most of your APIs
PERFORMANCE MATTERS.
MOBILE APPLICATIONAVERAGE API RESPONSE TIME.
1.24seconds
source: New Relic
TIME SPENT.
SERVER 20%
NETWORK 80%
BASIC MATHEMATICS.
session durationrequest duration = requests
per session
WILDLY INACCURATE TESTS.Check my balance43 requests in 70 seconds
Check-in46 requests in 30 seconds
Open a message 24 requests in 40 seconds
AVERAGE:
0.92second
THE HARD STUFF.
•INCREASE SESSION TIME. •REDUCE REQUEST TIME.
DOING MORE.
session durationrequest duration = requests
per session
MAKE FEWER REQUESTS PER ACTION.
BE SPECIFIC.
WEB BROWSER CACHES EVERYTHINGUNLESS TOLD OTHERWISE.
MOBILE APPLICATIONCACHES NOTHINGUNLESS TOLD OTHERWISE.
BASIC REQUIREMENT.
ONE =objectONE
URI
FOLLOWING JSON API GUIDELINES HELPS ENSURE OBJECT TO URI EQUIVALENCY.http://jsonapi.org
HTTP, FOR YOU IT WORKS.
GET /collections/12 HTTP/1.1 Host: flipbit.dev !HTTP/1.1 200 OK Date: Thu, 17 Oct 2013 01:42:00 GMT Accept-Ranges: bytes Content-Type: application/vnd.api+json Content-Length: 42 Connection: keep-alive Location: http://flipbit.dev/collections/12
GET /collections/12 HTTP/1.1 Host: flipbit.dev !HTTP/1.1 200 OK Date: Thu, 17 Oct 2013 01:42:00 GMT Last-Modified: Thu, 17 Oct 2013 01:38:57 GMT ETag: "b79f914dde3ab5e3095372de46591b46" Expires: Thu, 24 Oct 2013 01:38:57 GMT Cache-Control: max-age=604800, private Accept-Ranges: bytes Content-Type: application/vnd.api+json Content-Length: 42 Connection: keep-alive Location: http://flipbit.dev/collections/12
GET /collections/12 HTTP/1.1 Host: flipbit.dev If-Modified-Since: Thu, 10 Oct 2013 20:14:48 GMT If-None-Match: "a1846ac92492d2347c6235b4d2611184" !HTTP/1.1 200 OK Date: Thu, 17 Oct 2013 01:42:00 GMT Last-Modified: Thu, 17 Oct 2013 01:38:57 GMT ETag: "b79f914dde3ab5e3095372de46591b46" Expires: Thu, 24 Oct 2013 01:38:57 GMT Cache-Control: max-age=604800, private Accept-Ranges: bytes Content-Type: application/vnd.api+json Content-Length: 42 Connection: keep-alive Location: http://flipbit.dev/collections/12
CACHE-CONTROL ON AMAZON S3.
GET /buket.mycompany.com/welcome.json HTTP/1.1 Host: s3.amazonaws.com !HTTP/1.1 200 OK x-amz-id-2: UleVE3wbOPZa2EW+RpWj834yy5OOMLNmi/w… x-amz-request-id: 4ADBB2EBF80F5D46 Date: Thu, 17 Oct 2013 01:42:00 GMT Last-Modified: Thu, 17 Oct 2013 01:38:57 GMT ETag: "b79f914dde3ab5e3095372de46591b46" Accept-Ranges: bytes Content-Type: application/octet-stream Content-Length: 23 Connection: keep-alive Server: AmazonS3
GET /buket.mycompany.com/welcome.json HTTP/1.1 Host: s3.amazonaws.com !HTTP/1.1 200 OK x-amz-id-2: UleVE3wbOPZa2EW+RpWj834yy5OOMLNmi/w… x-amz-request-id: 4ADBB2EBF80F5D46 Date: Thu, 17 Oct 2013 01:42:00 GMT Last-Modified: Thu, 17 Oct 2013 01:38:57 GMT ETag: “b79f914dde3ab5e3095372de46591b46" Cache-Control: ??? Expires: ??? Accept-Ranges: bytes Content-Type: application/octet-stream Content-Length: 23 Connection: keep-alive Server: AmazonS3
CACHING IS UNCERTAIN.
•There’s no cache-control header so it’s left to the client to decide.
•iOS most likely will cache between 6 hours and 1 day and will always revalidate.
•Android it depends, but most likely won’t cache.
DON’T LET THE CLIENT DECIDE.
•Add the x-amz-meta-Cache-Control header when doing a PUT to S3.
•It’s recommended to use a max-age of at least one month.
•Don’t use x-amz-meta-Expires. The object will not be cached after its expiry date.
CACHE-CONTROL WITH RUBY ON RAILS.
GET /collections/12 HTTP/1.1 Host: app.mycompany.com !Cache-Control: max-age=0, private, must-revalidate Content-Type: application/json; charset=utf-8 ETag: "4a200c9d8fb14925e7461d63b59f4e82" Server: nginx/1.2.3 + Phusion Passenger 3.0.17 (mod_rails/mod_rack) Set-Cookie: request_method=GET; path=/ Status: 200 Content-Length: 144 Connection: Close
FIXING CACHE-CONTROL.class FlipsController < ApplicationController respond_to :json ! def index # ... ! # Last-Modified and ETag flipbit_etag = Digest::MD5.digest(@flipbit.to_s).to_s fresh_when last_modified: DateTime.now, etag: flipbit_etag ! # Cache-Control expires_in 3.day, :must_revalidate => false, :public => true # ... end end
GET /collections/12 HTTP/1.1 Host: app.mycompany.com !Cache-Control: max-age=86400, public Content-Type: application/json; charset=utf-8 ETag: "4a200c9d8fb14925e7461d63b59f4e82" Server: nginx/1.2.3 + Phusion Passenger 3.0.17 (mod_rails/mod_rack) Set-Cookie: request_method=GET; path=/ Status: 200 Content-Length: 144 Connection: Close
CACHING IS BETTER.
•iOS will honour the cache-control header as long as there’s cache space.
•Android apache’s HttpClient does not handle caching, android-query does.
CACHING ON THE DEVICE.
NEVER HARD CODE CACHE LOGIC.
MAKE SURE YOU HAVE ENOUGH STORAGE.
CACHE ON iOS.- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSUInteger mb = 1024*1024; ! // Configure NSURLCache with larger storage [NSURLCache setSharedURLCache: [[NSURLCache alloc] initWithMemoryCapacity:(50*mb) diskCapacity:(100*mb) diskPath:nil] ]; ! // ... // ... return YES; }
MAKE EVERY ROUND-TRIP COUNT.
BONUS MATERIAL.Amazon S3 performance.
S3 GET PERFORMANCE.
•Make sure you set your Cache-Control headers using x-amz-meta-Cache-Control.
•Intensive objects benefit from CloudFront by a factor of 2 or more.
S3 PUT PERFORMANCE.
•Avoid sequential keys. S3 stores key names in alphabetical order; key name dictates which partition the key is stored in.http://bit.ly/s3performance
AVOID DATES AS PREFIX.examplebucket/2013-26-05-15-00-00/cust1234234/photo1.jpg examplebucket/2013-26-05-15-00-00/cust3857422/photo2.jpg examplebucket/2013-26-05-15-00-00/cust1248473/photo2.jpg examplebucket/2013-26-05-15-00-00/cust8474937/photo2.jpg examplebucket/2013-26-05-15-00-00/cust1248473/photo3.jpg ... examplebucket/2013-26-05-15-00-01/cust1248473/photo4.jpg examplebucket/2013-26-05-15-00-01/cust1248473/photo5.jpg examplebucket/2013-26-05-15-00-01/cust1248473/photo6.jpg examplebucket/2013-26-05-15-00-01/cust1248473/photo7.jpg ...
USE HASH AS PREFIX.examplebucket/232a-2013-26-05-15-00-00/cust1234234/photo1.jpg examplebucket/7b54-2013-26-05-15-00-00/cust3857422/photo2.jpg examplebucket/921c-2013-26-05-15-00-00/cust1248473/photo2.jpg examplebucket/ba65-2013-26-05-15-00-00/cust8474937/photo2.jpg examplebucket/8761-2013-26-05-15-00-00/cust1248473/photo3.jpg examplebucket/2e4f-2013-26-05-15-00-01/cust1248473/photo4.jpg examplebucket/9810-2013-26-05-15-00-01/cust1248473/photo5.jpg examplebucket/7e34-2013-26-05-15-00-01/cust1248473/photo6.jpg examplebucket/c34a-2013-26-05-15-00-01/cust1248473/photo7.jpg ...
SHARING A BUCKET?examplebucket/my_beautiful_app/40434b70/avatar.jpg examplebucket/my_beautiful_app/4ee66b70/avatar.jpg examplebucket/my_beautiful_app/753da383/avatar.jpg examplebucket/my_beautiful_app/91255df0/avatar.jpg examplebucket/my_beautiful_app/98e26030/avatar.jpg examplebucket/my_very_nice_app/a2cb3fdb/video.mpg examplebucket/my_very_nice_app/cf763412/video.mpg examplebucket/my_very_nice_app/d6e93451/video.mpg examplebucket/my_very_nice_app/e68f7670/video.mpg ...
USE SHORT FIXED PREFIX!examplebucket/mba/40434b70/avatar.jpg examplebucket/mba/4ee66b70/avatar.jpg examplebucket/mba/753da383/avatar.jpg examplebucket/mba/91255df0/avatar.jpg examplebucket/mba/98e26030/avatar.jpg examplebucket/mvna/a2cb3fdb/video.mpg examplebucket/mvna/cf763412/video.mpg examplebucket/mvna/d6e93451/video.mpg examplebucket/mvna/e68f7670/video.mpg ...