SlideShare a Scribd company logo
Evolution of the Netflix API
QCon San Francisco - November 2013
Ben Christensen

Software Engineer – Edge & Playback Services at Netflix
@benjchristensen
!
!
!
!
http://techblog.netflix.com/
Watch the video with slide
synchronization on InfoQ.com!
http://www.infoq.com/presentations
/netflix-api-evolution

InfoQ.com: News & Community Site
• 750,000 unique visitors/month
• Published in 4 languages (English, Chinese, Japanese and Brazilian
Portuguese)
• Post content from our QCon conferences
• News 15-20 / week
• Articles 3-4 / week
• Presentations (videos) 12-15 / week
• Interviews 2-3 / week
• Books 1 / month
Presented at QCon San Francisco
www.qconsf.com
Purpose of QCon
- to empower software development by facilitating the spread of
knowledge and innovation
Strategy
- practitioner-driven conference designed for YOU: influencers of
change and innovation in your teams
- speakers and topics driving the evolution and innovation
- connecting and catalyzing the influencers and innovators
Highlights
- attended by more than 12,000 delegates since 2007
- held in 9 cities worldwide
More than 40 million Subscribers
in 50+ Countries and Territories
Netflix accounts for 33% of Peak Downstream
Internet Traffic in North America

Netflix subscribers are watching
more than 1 billion hours a month
API traffic has grown from
~20 million/day in 2010 to >2 billion/day
millions of API requests per day

2000

1500

1000

500

0
2010

2011

2012

Today
Discovery

Streaming
Netflix API

Streaming
At the start …

millions of API requests per day

2000

1500

1000

500

0
2008

2009

2010

2011

2012

Today
2008 API Launch
Targeted 100% at External Developers
Open API

Netflix Devices
2008 API Launch
Targeted 100% at External Developers

Purpose
A “Thousand Flowers” of
3rd party innovation
!

Audience
External Developers
Pre-Cloud Architecture
API

Service

Service

Service

Oracle

Service
In 2011 …

millions of API requests per day

2000

1500

1000

500

0
2008

2009

2010

2011

2012

Today
99.9% Netflix Devices
Open API

Netflix Devices
Targeted at Internal Developers
Open API

Netflix Devices
Targeted at Internal Developers

Purpose
Enable Netflix Experience
!

Audience
Netflix Device and UI Teams
Scale & Resilience
!

Performance & Innovation
Scale & Resilience
!

Performance & Innovation
Netflix API

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J

Dependency M

Dependency P

Dependency I

Dependency K

Dependency N

Dependency Q

Dependency L

Dependency O

Dependency R
Netflix API

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J

Dependency M

Dependency P

Dependency I

Dependency K

Dependency N

Dependency Q

Dependency L

Dependency O

Dependency R
AWS
Availability Zone

AWS
Availability Zone

AWS
Availability Zone
User Request

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J
Dependency M

Dependency P

Dependency I

Dependency K
Dependency N

Dependency Q

Dependency L
Dependency O

Dependency R
User Request

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J
Dependency M

Dependency P

Dependency I

Dependency K
Dependency N

Dependency Q

Dependency L
Dependency O

Dependency R

User request
blocked by
latency in
single
network call
Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J

Dependency M
Dependency P

Dependency I

Dependency K

Dependency N
Dependency Q

Dependency L

Dependency O
Dependency R

User Request

User Request

User Request

User Request

User Request

User Request

User Request

.............................................

At high
volume
all request
threads can
block in
seconds
!

Dozens of dependencies.
!

One going bad takes everything down.
!

30
99.99%

= 99.7% uptime
!

0.3% of 1 billion = 3,000,000 failures
!

2+ hours downtime/month
!
!
!

Reality is generally worse.
CONSTRAINTS

Speed of Iteration
!

Client Libraries
!

Mixed Environment
CONSTRAINTS

Speed of Iteration
!

Client Libraries
!

Mixed Environment
CONSTRAINTS

Speed of Iteration
!

Client Libraries
!

Mixed Environment
CONSTRAINTS

Speed of Iteration
!

Client Libraries
!

Mixed Environment
Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J

Dependency M
Dependency P

Dependency I

Dependency K

Dependency N
Dependency Q

Dependency L

Dependency O
Dependency R

User Request

User Request

User Request

User Request

User Request

User Request

User Request

.............................................
User Request

User Request

User Request

Logic - argument validation, caches, metrics, logging,
multivariate testing, routing, etc
Serialization - URL and/or body generation

Network Request - TCP/HTTP, latency, 4xx, 5xx, etc

.............................................
Deserialization - JSON/XML/Thrift/Protobuf/etc

Dependency B

cy D

Dependency C

Dependency E

dency G

ependency J
Dependency M

Logic - validation, decoration, object model, caching,
metrics, logging, etc

Dependency F

Dependency H
Dependency K
Dependency N

Dependency I
Dependency L
Dependency O
> 80% of requests rejected

Median
Latency
[Sat Jun 30 04:01:37 2012] [error] proxy: HTTP: disabled connection for (127.0.0.1)

"Timeout guard" daemon prio=10 tid=0x00002aaacd5e5000 nid=0x3aac runnable [0x00002aaac388f000] java.lang.Thread.State: RUNNABLE!
at java.net.PlainSocketImpl.socketConnect(Native Method)!
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)!
- locked <0x000000055c7e8bd8> (a java.net.SocksSocketImpl)!
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)!
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)!
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:391)!
at java.net.Socket.connect(Socket.java:579)!
at java.net.Socket.connect(Socket.java:528)!
at java.net.Socket.(Socket.java:425)!
at java.net.Socket.(Socket.java:280)!
at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:80)!
at org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory$1.doit(ControllerThreadSocketFactory.java:91)!
at org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory$SocketTask.run(ControllerThreadSocketFactory.java:158) at java.lang.Thread.run(Thread.java:722)
User Request

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J
Dependency M

Dependency P

Dependency I

Dependency K
Dependency N

Dependency Q

Dependency L
Dependency O

Dependency R
User Request

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J
Dependency M

Dependency P

Dependency I

Dependency K
Dependency N

Dependency Q

Dependency L
Dependency O

Dependency R
User Request

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J
Dependency M

Dependency P

Dependency I

Dependency K
Dependency N

Dependency Q

Dependency L
Dependency O

Dependency R
User Request

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J
Dependency M

Dependency P

Dependency I

Dependency K
Dependency N

Dependency Q

Dependency L
Dependency O

Dependency R
circle color and size represent
health and traffic volume
circle color and size represent
health and traffic volume

2 minutes of request rate to
show relative changes in traffic
circle color and size represent
health and traffic volume

2 minutes of request rate to
show relative changes in traffic
hosts reporting from cluster
circle color and size represent
health and traffic volume

2 minutes of request rate to
show relative changes in traffic
hosts reporting from cluster

last minute latency percentiles
circle color and size represent
health and traffic volume

2 minutes of request rate to
show relative changes in traffic
hosts reporting from cluster

Circuit-breaker
status
last minute latency percentiles
circle color and size represent
health and traffic volume
Request rate
2 minutes of request rate to
show relative changes in traffic
hosts reporting from cluster

Circuit-breaker
status
last minute latency percentiles
circle color and size represent
health and traffic volume

Error percentage of
last 10 seconds
Request rate

2 minutes of request rate to
show relative changes in traffic
hosts reporting from cluster

Circuit-breaker
status
last minute latency percentiles
Error percentage of
last 10 seconds

circle color and size represent
health and traffic volume

Request rate
2 minutes of request rate to
show relative changes in traffic

Circuit-breaker
status

hosts reporting from cluster

last minute latency percentiles
Rolling 10 second counters
with 1 second granularity

Successes
Short-circuited (rejected)

Thread timeouts
Thread-pool Rejections
Failures/Exceptions
User Request

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J
Dependency M

Dependency P

Dependency I

Dependency K
Dependency N

Dependency Q

Dependency L
Dependency O

Dependency R
Zuul Routing Layer

Canary vs Baseline
Squeeze

"Coalmine"

Production
Zuul Routing Layer

Canary vs Baseline
Squeeze

"Coalmine"

Production
Zuul Routing Layer

Canary vs Baseline
Squeeze

"Coalmine"

Production
Zuul Routing Layer

Canary vs Baseline
Squeeze

"Coalmine"

Production
Zuul Routing Layer

Canary vs Baseline
Squeeze

"Coalmine"

Production
User Request

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J
Dependency M

Dependency P

Dependency I

Dependency K
Dependency N

Dependency Q

Dependency L
Dependency O

Dependency R

System
Relationship
Over
Network
without
Bulkhead
Zuul Routing Layer

Canary vs Baseline
Squeeze

"Coalmine"

Production
Zuul Routing Layer

Canary vs Baseline
Squeeze

"Coalmine"

Production
Predictive + Reactive Auto-Scaling
Scale & Resilience
!

Performance & Innovation
Netflix API

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J

Dependency M

Dependency P

Dependency I

Dependency K

Dependency N

Dependency Q

Dependency L

Dependency O

Dependency R
Netflix API

Dependency A

Dependency B

Dependency D

Dependency C

Dependency E

Dependency G

Dependency F

Dependency H

Dependency J

Dependency M

Dependency P

Dependency I

Dependency K

Dependency N

Dependency Q

Dependency L

Dependency O

Dependency R
One Size Fits All RESTful API

millions of API requests per day

2000

1500

1000

500

0
2010

2011

2012

Today
One Size Fits All RESTful API

millions of API requests per day

2000

1500

1000

500

0
2010

2011

2012

Today
One Size Fits All RESTful API
1000+ Devices
millions of API requests per day

2000

1500

1000

500

0
2010

2011

2012

Today
We wanted to re-architecture our call patterns ...
... to collapse network traffic into coarse API calls ...

nested, conditional, concurrent execution
... and we wanted to allow
anybody to create
endpoints, not just the
“API Team”
Concurrency without each engineer
reading and re-reading this →
!

(awesome book ... everybody isn’t going to - or
should have to - read it though, that’s the point)
Owner of api should retain control
of concurrency behavior.
Owner of api should retain control
of concurrency behavior.
public	
  Data	
  getData();
What if the implementation needs to change
from synchronous to asynchronous?
!

How should the client execute that method
without blocking? spawn a thread?
public	
  Data	
  getData();
public	
  void	
  getData(Callback<T>	
  c);	
  
!

public	
  Future<T>	
  getData();	
  
!

public	
  Future<List<Future<T>>>	
  getData();	
  
!
!

other options ... ?
Reactive Programming with Rx
Iterable
pull
T next()
throws Exception
returns;

Observable
push
onNext(T)
onError(Exception)
onCompleted()
(Functional) Reactive Programming with RxJava
Iterable
pull
T next()
throws Exception
returns;

Observable
push
onNext(T)
onError(Exception)
onCompleted()
(Functional) Reactive Programming with RxJava
Iterable
pull
T next()
throws Exception
returns;

Observable
push
onNext(T)
onError(Exception)
onCompleted()
(Functional) Reactive Programming with RxJava
Iterable
pull
T next()
throws Exception
returns;

Observable
push
onNext(T)
onError(Exception)
onCompleted()
Iterable
pull
T next()
throws Exception
returns;
!
	
  //	
  Iterable<String>	
  	
  
	
  //	
  that	
  contains	
  75	
  Strings	
  
	
  getDataFromLocalMemory()	
  
	
  	
  .skip(10)	
  
	
  	
  .take(5)	
  
	
  	
  .map({	
  s	
  -­‐>	
  	
  
	
  	
  	
  return	
  s	
  +	
  "_transformed"})	
  
	
  	
  .forEach(	
  
	
  	
  	
  	
  	
  {	
  println	
  "next	
  =>	
  "	
  +	
  it})	
  

Observable
push
onNext(T)
onError(Exception)
onCompleted()
!
	
  //	
  Observable<String>	
  	
  
	
  //	
  that	
  emits	
  75	
  Strings	
  
	
  getDataFromNetwork()	
  
	
  	
  .skip(10)	
  
	
  	
  .take(5)	
  
	
  	
  .map({	
  s	
  -­‐>	
  	
  
	
  	
  	
  return	
  s	
  +	
  "_transformed"})	
  
	
  	
  .subscribe(	
  
	
  	
  	
  	
  	
  {	
  println	
  "onNext	
  =>	
  "	
  +	
  it})	
  
Iterable
pull
T next()
throws Exception
returns;
!
	
  //	
  Iterable<String>	
  	
  
	
  //	
  that	
  contains	
  75	
  Strings	
  
	
  getDataFromLocalMemory()	
  
	
  	
  .skip(10)	
  
	
  	
  .take(5)	
  
	
  	
  .map({	
  s	
  -­‐>	
  	
  
	
  	
  	
  return	
  s	
  +	
  "_transformed"})	
  
	
  	
  .forEach(	
  
	
  	
  	
  	
  	
  {	
  println	
  "onNext	
  =>	
  "	
  +	
  it})	
  

Observable
push
onNext(T)
onError(Exception)
onCompleted()
!
	
  //	
  Observable<String>	
  	
  
	
  //	
  that	
  emits	
  75	
  Strings	
  
	
  getDataFromNetwork()	
  
	
  	
  .skip(10)	
  
	
  	
  .take(5)	
  
	
  	
  .map({	
  s	
  -­‐>	
  	
  
	
  	
  	
  return	
  s	
  +	
  "_transformed"})	
  
	
  	
  .subscribe(	
  
	
  	
  	
  	
  	
  {	
  println	
  "onNext	
  =>	
  "	
  +	
  it})	
  
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

String s = getData(args);	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Iterable<String> values = getData(args);	
for (String s : values) {	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
}
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Future<String> s = getData(args);	
if (s.get().equals(x)) {	
// do something	
} else {	
// do something else	
}
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Future<String> s = getData(args);	
if (s.get().equals(x)) {	
// do something	
} else {	
// do something else	
}
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Future<String> s = getData(args);	
Futures.addCallback(s, 	
new FutureCallback<String> {	
public void onSuccess(String s) {	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
}	
	
}, executor);
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Future<String> s = getData(args);	
Futures.addCallback(s, 	
new FutureCallback<String> {	
public void onSuccess(String s) {	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
}	
	
}, executor);
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Future<String> s = getData(args);	
Futures.addCallback(s, 	
new FutureCallback<String> {	
public void onSuccess(String s) {	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
}	
	
}, executor);
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

CompletableFuture<String> s = getData(args);	
s.thenApply((v) -> {	
if (v.equals(x)) {	
// do something	
} else {	
// do something else	
}	
});
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

CompletableFuture<String> s = getData(args);	
s.thenApply((v) -> {	
if (v.equals(x)) {	
// do something	
} else {	
// do something else	
}	
});
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Future<String> s = getData(args);	
s.map({ s -> 	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
});
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Future<String> s = getData(args);	
s.map({ s -> 	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
});
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Future<String> s = getData(args);	
s.map({ s -> 	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
});
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Observable<String> s = getData(args);	
s.map({ s -> 	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
});
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Observable<String> s = getData(args);	
s.map({ s -> 	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
});
Single

Multiple

Sync

T getData()

Iterable<T> getData()

Async

Future<T> getData()

Observable<T> getData()

Observable<String> s = getData(args);	
s.map({ s -> 	
if (s.equals(x)) {	
// do something	
} else {	
// do something else	
}	
});
instead of a blocking api ...
class	
  VideoService	
  {	
  
	
  	
  	
  def	
  VideoList	
  getPersonalizedListOfMovies(userId);	
  
	
  	
  	
  def	
  VideoBookmark	
  getBookmark(userId,	
  videoId);	
  
	
  	
  	
  def	
  VideoRating	
  getRating(userId,	
  videoId);	
  
	
  	
  	
  def	
  VideoMetadata	
  getMetadata(videoId);	
  
}

... create an observable api:
class	
  VideoService	
  {	
  
	
  	
  	
  def	
  Observable<VideoList>	
  getPersonalizedListOfMovies(userId);	
  
	
  	
  	
  def	
  Observable<VideoBookmark>	
  getBookmark(userId,	
  videoId);	
  
	
  	
  	
  def	
  Observable<VideoRating>	
  getRating(userId,	
  videoId);	
  
	
  	
  	
  def	
  Observable<VideoMetadata>	
  getMetadata(videoId);	
  
}
RxJava
http://github.com/Netflix/RxJava

“a library for composing
asynchronous and event-based
programs using observable
sequences for the Java VM”
A Java port of Rx (Reactive Extensions)
https://rx.codeplex.com (.Net and Javascript by Microsoft)
client code treats all interactions
with the api as asynchronous
!
!

the api implementation chooses
whether something is
blocking or non-blocking
and
what resources it uses
Netflix API

Server

Device

Optimize for Each Device. Leverage the Server
Code
SDK for API Web Service Development
SDK for API Web Service Development
SDK for API Web Service Development
api.servletResponse.writer.print("Hello")
api.servletResponse.writer.print("Hello")

$runScript.py -e PROD sample.groovy
Hello
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
[0ms] INFO: User => NULL
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
api.servletResponse.writer.print("Hello")

$runScript.py -e PROD sample.groovy
Hello
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
[0ms] INFO: User => NULL
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
api.servletResponse.writer.print("Hello")

$runScript.py -e PROD sample.groovy
Hello
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
[0ms] INFO: User => NULL
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
api.servletResponse.writer.print("Hello")

$runScript.py -e PROD sample.groovy
Hello
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
[0ms] INFO: User => NULL
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
api.servletResponse.writer.print("Hello")

$runScript.py -e PROD sample.groovy
Hello
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
[0ms] INFO: User => NULL
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
api.servletResponse.writer.print("Hello")

$runScript.py -e PROD sample.groovy
Hello
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
[0ms] INFO: User => NULL
################################################################################################
####### Script Logger (enabled via debug=true request parameter)
################################################################################################
public class HelloEndpoint extends APIEndpoint {	
@Override	
public void execute(APIRequest api) throws Throwable {	
// get a request parameter from servlet request	
String alias = api.servletRequest.getParameter("name");	

!
// set content type and write something to servlet response	
api.servletResponse.setContentType("application/json");	
api.servletResponse.writer.print(	
JsonUtility.toJson(	
[ alias : alias, name : api.user.firstName ]	
)	
)	

!
}	
}
public class HelloEndpoint extends APIEndpoint {	
@Override	
public void execute(APIRequest api) throws Throwable {	
// get a request parameter from servlet request	
String alias = api.servletRequest.getParameter("name");	

!
// set content type and write something to servlet response	
api.servletResponse.setContentType("application/json");	
api.servletResponse.writer.print(	
JsonUtility.toJson(	
[ alias : alias, name : api.user.firstName ]	
)	
)	

!
}	
}

runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy
public class HelloEndpoint extends APIEndpoint {	
@Override	
public void execute(APIRequest api) throws Throwable {	
// get a request parameter from servlet request	
String alias = api.servletRequest.getParameter("name");	

!
// set content type and write something to servlet response	
api.servletResponse.setContentType("application/json");	
api.servletResponse.writer.print(	
JsonUtility.toJson(	
[ alias : alias, name : api.user.firstName ]	
)	
)	

!
}	
}
runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy

{"alias":"bob","name":"Old"}
public class HelloEndpoint extends APIEndpoint {	
@Override	
public void execute(APIRequest api) throws Throwable {	
// get a request parameter from servlet request	
String alias = api.servletRequest.getParameter("name");	

!
// set content type and write something to servlet response	
api.servletResponse.setContentType("application/json");	
api.servletResponse.writer.print(	
JsonUtility.toJson(	
[ alias : alias, name : api.user.firstName ]	
)	
)	

!
}	
}
runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy

{"alias":"bob","name":"Old"}
public class HelloEndpoint extends APIEndpoint {	
@Override	
public void execute(APIRequest api) throws Throwable {	
// get a request parameter from servlet request	
String alias = api.servletRequest.getParameter("name");	

!
// set content type and write something to servlet response	
api.servletResponse.setContentType("application/json");	
api.servletResponse.writer.print(	
JsonUtility.toJson(	
[ alias : alias, name : api.user.firstName ]	
)	
)	

!
}	
}
runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy

{"alias":"bob","name":"Old"}
public class HelloEndpoint extends APIEndpoint {	
@Override	
public void execute(APIRequest api) throws Throwable {	
// get a request parameter from servlet request	
String alias = api.servletRequest.getParameter("name");	

!
// set content type and write something to servlet response	
api.servletResponse.setContentType("application/json");	
api.servletResponse.writer.print(	
JsonUtility.toJson(	
[ alias : alias, name : api.user.firstName ]	
)	
)	

!
}	
}
runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy

{"alias":"bob","name":"Old"}
public class HelloEndpoint extends APIEndpoint {	
@Override	
public void execute(APIRequest api) throws Throwable {	
// get a request parameter from servlet request	
String alias = api.servletRequest.getParameter("name");	

!
// set content type and write something to servlet response	
api.servletResponse.setContentType("application/json");	
api.servletResponse.writer.print(	
JsonUtility.toJson(	
[ alias : alias, name : api.user.firstName ]	
)	
)	

!
}	
}
runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy

{"alias":"bob","name":"Old"}
public class HelloEndpoint extends APIEndpoint {	
@Override	
public void execute(APIRequest api) throws Throwable {	
// get a request parameter from servlet request	
String alias = api.servletRequest.getParameter("name");	

!
// set content type and write something to servlet response	
api.servletResponse.setContentType("application/json");	
api.servletResponse.writer.print(	
JsonUtility.toJson(	
[ alias : alias, name : api.user.firstName ]	
)	
)	

!
}	
}
runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy

{"alias":"bob","name":"Old"}
public Observable getVideoSummary(APIVideo video) {	
// get id, title	
def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)]	

!
// get bookmark	
def bookmarkObservable = getBookmark(video)	

!
// get artwork	
def artworkObservable = getArtworkImageUrl(video)	

!
// merge them and accumulate into the seed.	
return Observable.merge(bookmarkObservable, artworkObservable)	
.reduce(seed, { aggregate, current -> aggregate << current})	
.map({ [ (video.id.toString()) : it]})	
}
public Observable getVideoSummary(APIVideo video) {	
// get id, title	
def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)]	

!
// get bookmark	
def bookmarkObservable = getBookmark(video)	

!
// get artwork	
def artworkObservable = getArtworkImageUrl(video)	

!
// merge them and accumulate into the seed.	
return Observable.merge(bookmarkObservable, artworkObservable)	
.reduce(seed, { aggregate, current -> aggregate << current})	
.map({ [ (video.id.toString()) : it]})	
}
public Observable getVideoSummary(APIVideo video) {	
// get id, title	
def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)]	

!
// get bookmark	
def bookmarkObservable = getBookmark(video)	

!
// get artwork	
def artworkObservable = getArtworkImageUrl(video)	

!
// merge them and accumulate into the seed.	
return Observable.merge(bookmarkObservable, artworkObservable)	
.reduce(seed, { aggregate, current -> aggregate << current})	
.map({ [ (video.id.toString()) : it]})	
}
public Observable getVideoSummary(APIVideo video) {	
// get id, title	
def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)]	

!
// get bookmark	
def bookmarkObservable = getBookmark(video)	

!
// get artwork	
def artworkObservable = getArtworkImageUrl(video)	

!
// merge them and accumulate into the seed.	
return Observable.merge(bookmarkObservable, artworkObservable)	
.reduce(seed, { aggregate, current -> aggregate << current})	
.map({ [ (video.id.toString()) : it]})	
}
public Observable getVideoSummary(APIVideo video) {	
// get id, title	
def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)]	

!
// get bookmark	
def bookmarkObservable = getBookmark(video)	

!
// get artwork	
def artworkObservable = getArtworkImageUrl(video)	

!
// merge them and accumulate into the seed.	
return Observable.merge(bookmarkObservable, artworkObservable)	
.reduce(seed, { aggregate, current -> aggregate << current})	
.map({ [ (video.id.toString()) : it]})	
}
public Observable getVideoSummary(APIVideo video) {	
// get id, title	
def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)]	

!
// get bookmark	
def bookmarkObservable = getBookmark(video)	

!
// get artwork	
def artworkObservable = getArtworkImageUrl(video)	

!
// merge them and accumulate into the seed.	
return Observable.merge(bookmarkObservable, artworkObservable)	
.reduce(seed, { aggregate, current -> aggregate << current})	
.map({ [ (video.id.toString()) : it]})	
}
public Observable getVideoSummary(APIVideo video) {	
// get id, title	
def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)]	

!
// get bookmark	
def bookmarkObservable = getBookmark(video)	

!
// get artwork	
def artworkObservable = getArtworkImageUrl(video)	

!
// merge them and accumulate into the seed.	
return Observable.merge(bookmarkObservable, artworkObservable)	
.reduce(seed, { aggregate, current -> aggregate << current})	
.map({ [ (video.id.toString()) : it]})	
}
$ uploadScript.py -e TEST /test/hello sample.groovy
{
"active": false,
"allocationPercentage": 0,
"creationDate": "Mon Nov 11 05:38:51 UTC 2013",
"revision": 1,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ uploadScript.py -e TEST /test/hello sample.groovy
{
"active": false,
"allocationPercentage": 0,
"creationDate": "Mon Nov 11 05:38:51 UTC 2013",
"revision": 1,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ uploadScript.py -e TEST /test/hello sample.groovy
{
"active": false,
"allocationPercentage": 0,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ uploadScript.py -e TEST /test/hello sample.groovy
{
"active": false,
"allocationPercentage": 0,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ activateScript.py -e TEST --revision 2 /test/hello
{
"active": true,
"allocationPercentage": 100,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"previousRevision": null,
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ uploadScript.py -e TEST /test/hello sample.groovy
{
"active": false,
"allocationPercentage": 0,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ activateScript.py -e TEST --revision 2 /test/hello
{
"active": true,
"allocationPercentage": 100,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"previousRevision": null,
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ uploadScript.py -e TEST /test/hello sample.groovy
{
"active": false,
"allocationPercentage": 0,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ activateScript.py -e TEST --revision 2 /test/hello
{
"active": true,
"allocationPercentage": 100,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"previousRevision": null,
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ uploadScript.py -e TEST /test/hello sample.groovy
{
"active": false,
"allocationPercentage": 0,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ activateScript.py -e TEST --revision 2 /test/hello
{
"active": true,
"allocationPercentage": 100,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"previousRevision": null,
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ uploadScript.py -e TEST /test/hello sample.groovy
{
"active": false,
"allocationPercentage": 0,
"creationDate": "Mon Nov 11 05:40:26 UTC 2013",
"revision": 2,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
$ activateScript.py -e TEST --revision 3 /test/hello
{
"active": true,
"allocationPercentage": 100,
"creationDate": "Mon Nov 11 05:42:05 UTC 2013",
"previousRevision": 2,
"revision": 3,
"userAuthorizationRequired": true,
"userAuthorizationType": "https"
}
Future
millions of API requests per day

2000

1500

1000

500

0
2008

2009

2010

2011

2012

Today
/tv/home

/android/home

/ps3/home

Functional Reactive Dynamic Endpoints

Asynchronous Java API

Dependency A
10 Threads

Dependency F
10 Threads

Dependency K
15 Threads

Dependency P
10 Threads

Dependency B
8 Threads

Dependency G
10 Threads

Dependency L
4 Threads

Dependency Q
8 Threads

Dependency C
10 Threads

Dependency H
10 Threads

Dependency M
5 Threads

Dependency R
10 Threads

Dependency D
15 Threads

Dependency I
5 Threads

Dependency N
10 Threads

Dependency S
8 Threads

Dependency E
5 Threads

Dependency J
8 Threads

Dependency O
10 Threads

Dependency T
10 Threads
/tv/home

/android/home

/ps3/home

Hystrix

Functional Reactive Dynamic Endpoints

fault-isolation layer

Asynchronous Java API

Dependency A
10 Threads

Dependency F
10 Threads

Dependency K
15 Threads

Dependency P
10 Threads

Dependency B
8 Threads

Dependency G
10 Threads

Dependency L
4 Threads

Dependency Q
8 Threads

Dependency C
10 Threads

Dependency H
10 Threads

Dependency M
5 Threads

Dependency R
10 Threads

Dependency D
15 Threads

Dependency I
5 Threads

Dependency N
10 Threads

Dependency S
8 Threads

Dependency E
5 Threads

Dependency J
8 Threads

Dependency O
10 Threads

Dependency T
10 Threads
+
Observable<User>	
  u	
  =	
  new	
  GetUserCommand(id).observe();	
  
Observable<Geo>	
  g	
  =	
  new	
  GetGeoCommand(request).observe();	
  
!
Observable.zip(u,	
  g,	
  {user,	
  geo	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  [username:	
  user.getUsername(),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  currentLocation:	
  geo.getCounty()]	
  	
  	
  	
  
})

RxJava in Hystrix 1.3+
https://github.com/Netflix/Hystrix
Ben Christensen
@benjchristensen
http://www.linkedin.com/in/benjchristensen

jobs.netflix.com

!

Functional Reactive in the Netflix API with RxJava
http://techblog.netflix.com/2013/02/rxjava-netflix-api.html

!

Optimizing the Netflix API
http://techblog.netflix.com/2013/01/optimizing-netflix-api.html

!

Application Resilience in a Service-oriented Architecture
http://programming.oreilly.com/2013/06/application-resilience-in-a-service-oriented-architecture.html

!

Fault Tolerance in a High Volume, Distributed System
http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html

!

Making the Netflix API More Resilient
http://techblog.netflix.com/2011/12/making-netflix-api-more-resilient.html
Watch the video with slide synchronization on
InfoQ.com!
http://www.infoq.com/presentations/netflixapi-evolution

More Related Content

Similar to Evolution of the Netflix API

Stranger Things: The Forces that Disrupt Netflix
Stranger Things: The Forces that Disrupt NetflixStranger Things: The Forces that Disrupt Netflix
Stranger Things: The Forces that Disrupt Netflix
C4Media
 
Pros and Cons of a MicroServices Architecture talk at AWS ReInvent
Pros and Cons of a MicroServices Architecture talk at AWS ReInventPros and Cons of a MicroServices Architecture talk at AWS ReInvent
Pros and Cons of a MicroServices Architecture talk at AWS ReInvent
Sudhir Tonse
 
Mastering Chaos - A Netflix Guide to Microservices
Mastering Chaos - A Netflix Guide to MicroservicesMastering Chaos - A Netflix Guide to Microservices
Mastering Chaos - A Netflix Guide to Microservices
C4Media
 
Generating Unified APIs with Protocol Buffers and gRPC
Generating Unified APIs with Protocol Buffers and gRPCGenerating Unified APIs with Protocol Buffers and gRPC
Generating Unified APIs with Protocol Buffers and gRPC
C4Media
 
Netflix Edge Engineering Open House Presentations - June 9, 2016
Netflix Edge Engineering Open House Presentations - June 9, 2016Netflix Edge Engineering Open House Presentations - June 9, 2016
Netflix Edge Engineering Open House Presentations - June 9, 2016
Daniel Jacobson
 
QConSF2016-JoshEvans-MasteringChaosANetflixGuidetoMicroservices-compressed.pdf
QConSF2016-JoshEvans-MasteringChaosANetflixGuidetoMicroservices-compressed.pdfQConSF2016-JoshEvans-MasteringChaosANetflixGuidetoMicroservices-compressed.pdf
QConSF2016-JoshEvans-MasteringChaosANetflixGuidetoMicroservices-compressed.pdf
SimranjyotSuri
 
Next Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy MobileNext Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy Mobile
C4Media
 
Netflix Play API: Why we built an evolutionary architecture
Netflix Play API: Why we built an evolutionary architectureNetflix Play API: Why we built an evolutionary architecture
Netflix Play API: Why we built an evolutionary architecture
Suudhan Rangarajan
 
Scalable Microservices at Netflix. Challenges and Tools of the Trade
Scalable Microservices at Netflix. Challenges and Tools of the TradeScalable Microservices at Netflix. Challenges and Tools of the Trade
Scalable Microservices at Netflix. Challenges and Tools of the Trade
C4Media
 
Mastering Chaos - A Netflix Guide to Microservices
Mastering Chaos - A Netflix Guide to MicroservicesMastering Chaos - A Netflix Guide to Microservices
Mastering Chaos - A Netflix Guide to Microservices
Josh Evans
 
(PFC304) Effective Interprocess Communications in the Cloud: The Pros and Con...
(PFC304) Effective Interprocess Communications in the Cloud: The Pros and Con...(PFC304) Effective Interprocess Communications in the Cloud: The Pros and Con...
(PFC304) Effective Interprocess Communications in the Cloud: The Pros and Con...
Amazon Web Services
 
Have Your Cake and Eat It Too -- Further Dispelling the Myths of the Lambda A...
Have Your Cake and Eat It Too -- Further Dispelling the Myths of the Lambda A...Have Your Cake and Eat It Too -- Further Dispelling the Myths of the Lambda A...
Have Your Cake and Eat It Too -- Further Dispelling the Myths of the Lambda A...
C4Media
 
The Service Mesh: It's about Traffic
The Service Mesh: It's about TrafficThe Service Mesh: It's about Traffic
The Service Mesh: It's about Traffic
C4Media
 
Fault Tolerance at Speed
Fault Tolerance at SpeedFault Tolerance at Speed
Fault Tolerance at Speed
C4Media
 
Microservices: State of the Union
Microservices: State of the UnionMicroservices: State of the Union
Microservices: State of the Union
C4Media
 
Building a Bank with Go
Building a Bank with GoBuilding a Bank with Go
Building a Bank with Go
C4Media
 
Road to REST
Road to RESTRoad to REST
Road to REST
C4Media
 
Scaling Push Messaging for Millions of Devices @Netflix
Scaling Push Messaging for Millions of Devices @NetflixScaling Push Messaging for Millions of Devices @Netflix
Scaling Push Messaging for Millions of Devices @Netflix
C4Media
 
Big datadc skyfall_preso_v2
Big datadc skyfall_preso_v2Big datadc skyfall_preso_v2
Big datadc skyfall_preso_v2
abramsm
 

Similar to Evolution of the Netflix API (20)

Stranger Things: The Forces that Disrupt Netflix
Stranger Things: The Forces that Disrupt NetflixStranger Things: The Forces that Disrupt Netflix
Stranger Things: The Forces that Disrupt Netflix
 
Pros and Cons of a MicroServices Architecture talk at AWS ReInvent
Pros and Cons of a MicroServices Architecture talk at AWS ReInventPros and Cons of a MicroServices Architecture talk at AWS ReInvent
Pros and Cons of a MicroServices Architecture talk at AWS ReInvent
 
Mastering Chaos - A Netflix Guide to Microservices
Mastering Chaos - A Netflix Guide to MicroservicesMastering Chaos - A Netflix Guide to Microservices
Mastering Chaos - A Netflix Guide to Microservices
 
Generating Unified APIs with Protocol Buffers and gRPC
Generating Unified APIs with Protocol Buffers and gRPCGenerating Unified APIs with Protocol Buffers and gRPC
Generating Unified APIs with Protocol Buffers and gRPC
 
Netflix Edge Engineering Open House Presentations - June 9, 2016
Netflix Edge Engineering Open House Presentations - June 9, 2016Netflix Edge Engineering Open House Presentations - June 9, 2016
Netflix Edge Engineering Open House Presentations - June 9, 2016
 
QConSF2016-JoshEvans-MasteringChaosANetflixGuidetoMicroservices-compressed.pdf
QConSF2016-JoshEvans-MasteringChaosANetflixGuidetoMicroservices-compressed.pdfQConSF2016-JoshEvans-MasteringChaosANetflixGuidetoMicroservices-compressed.pdf
QConSF2016-JoshEvans-MasteringChaosANetflixGuidetoMicroservices-compressed.pdf
 
Next Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy MobileNext Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy Mobile
 
Netflix Play API: Why we built an evolutionary architecture
Netflix Play API: Why we built an evolutionary architectureNetflix Play API: Why we built an evolutionary architecture
Netflix Play API: Why we built an evolutionary architecture
 
Scalable Microservices at Netflix. Challenges and Tools of the Trade
Scalable Microservices at Netflix. Challenges and Tools of the TradeScalable Microservices at Netflix. Challenges and Tools of the Trade
Scalable Microservices at Netflix. Challenges and Tools of the Trade
 
Mastering Chaos - A Netflix Guide to Microservices
Mastering Chaos - A Netflix Guide to MicroservicesMastering Chaos - A Netflix Guide to Microservices
Mastering Chaos - A Netflix Guide to Microservices
 
(PFC304) Effective Interprocess Communications in the Cloud: The Pros and Con...
(PFC304) Effective Interprocess Communications in the Cloud: The Pros and Con...(PFC304) Effective Interprocess Communications in the Cloud: The Pros and Con...
(PFC304) Effective Interprocess Communications in the Cloud: The Pros and Con...
 
Have Your Cake and Eat It Too -- Further Dispelling the Myths of the Lambda A...
Have Your Cake and Eat It Too -- Further Dispelling the Myths of the Lambda A...Have Your Cake and Eat It Too -- Further Dispelling the Myths of the Lambda A...
Have Your Cake and Eat It Too -- Further Dispelling the Myths of the Lambda A...
 
The Service Mesh: It's about Traffic
The Service Mesh: It's about TrafficThe Service Mesh: It's about Traffic
The Service Mesh: It's about Traffic
 
Fault Tolerance at Speed
Fault Tolerance at SpeedFault Tolerance at Speed
Fault Tolerance at Speed
 
Microservices: State of the Union
Microservices: State of the UnionMicroservices: State of the Union
Microservices: State of the Union
 
Building a Bank with Go
Building a Bank with GoBuilding a Bank with Go
Building a Bank with Go
 
Road to REST
Road to RESTRoad to REST
Road to REST
 
Edge architecture ieee international conference on cloud engineering
Edge architecture   ieee international conference on cloud engineeringEdge architecture   ieee international conference on cloud engineering
Edge architecture ieee international conference on cloud engineering
 
Scaling Push Messaging for Millions of Devices @Netflix
Scaling Push Messaging for Millions of Devices @NetflixScaling Push Messaging for Millions of Devices @Netflix
Scaling Push Messaging for Millions of Devices @Netflix
 
Big datadc skyfall_preso_v2
Big datadc skyfall_preso_v2Big datadc skyfall_preso_v2
Big datadc skyfall_preso_v2
 

More from C4Media

Streaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live VideoStreaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live Video
C4Media
 
Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020
C4Media
 
Understand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java ApplicationsUnderstand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java Applications
C4Media
 
Kafka Needs No Keeper
Kafka Needs No KeeperKafka Needs No Keeper
Kafka Needs No Keeper
C4Media
 
High Performing Teams Act Like Owners
High Performing Teams Act Like OwnersHigh Performing Teams Act Like Owners
High Performing Teams Act Like Owners
C4Media
 
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to JavaDoes Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
C4Media
 
Service Meshes- The Ultimate Guide
Service Meshes- The Ultimate GuideService Meshes- The Ultimate Guide
Service Meshes- The Ultimate Guide
C4Media
 
Shifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDShifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CD
C4Media
 
CI/CD for Machine Learning
CI/CD for Machine LearningCI/CD for Machine Learning
CI/CD for Machine Learning
C4Media
 
Architectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsArchitectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep Systems
C4Media
 
ML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.js
C4Media
 
Build Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerBuild Your Own WebAssembly Compiler
Build Your Own WebAssembly Compiler
C4Media
 
User & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleUser & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix Scale
C4Media
 
Scaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeScaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's Edge
C4Media
 
Make Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereMake Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home Everywhere
C4Media
 
The Talk You've Been Await-ing For
The Talk You've Been Await-ing ForThe Talk You've Been Await-ing For
The Talk You've Been Await-ing For
C4Media
 
Future of Data Engineering
Future of Data EngineeringFuture of Data Engineering
Future of Data Engineering
C4Media
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
C4Media
 
Navigating Complexity: High-performance Delivery and Discovery Teams
Navigating Complexity: High-performance Delivery and Discovery TeamsNavigating Complexity: High-performance Delivery and Discovery Teams
Navigating Complexity: High-performance Delivery and Discovery Teams
C4Media
 
High Performance Cooperative Distributed Systems in Adtech
High Performance Cooperative Distributed Systems in AdtechHigh Performance Cooperative Distributed Systems in Adtech
High Performance Cooperative Distributed Systems in Adtech
C4Media
 

More from C4Media (20)

Streaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live VideoStreaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live Video
 
Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020
 
Understand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java ApplicationsUnderstand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java Applications
 
Kafka Needs No Keeper
Kafka Needs No KeeperKafka Needs No Keeper
Kafka Needs No Keeper
 
High Performing Teams Act Like Owners
High Performing Teams Act Like OwnersHigh Performing Teams Act Like Owners
High Performing Teams Act Like Owners
 
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to JavaDoes Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
 
Service Meshes- The Ultimate Guide
Service Meshes- The Ultimate GuideService Meshes- The Ultimate Guide
Service Meshes- The Ultimate Guide
 
Shifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDShifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CD
 
CI/CD for Machine Learning
CI/CD for Machine LearningCI/CD for Machine Learning
CI/CD for Machine Learning
 
Architectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsArchitectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep Systems
 
ML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.js
 
Build Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerBuild Your Own WebAssembly Compiler
Build Your Own WebAssembly Compiler
 
User & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleUser & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix Scale
 
Scaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeScaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's Edge
 
Make Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereMake Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home Everywhere
 
The Talk You've Been Await-ing For
The Talk You've Been Await-ing ForThe Talk You've Been Await-ing For
The Talk You've Been Await-ing For
 
Future of Data Engineering
Future of Data EngineeringFuture of Data Engineering
Future of Data Engineering
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
 
Navigating Complexity: High-performance Delivery and Discovery Teams
Navigating Complexity: High-performance Delivery and Discovery TeamsNavigating Complexity: High-performance Delivery and Discovery Teams
Navigating Complexity: High-performance Delivery and Discovery Teams
 
High Performance Cooperative Distributed Systems in Adtech
High Performance Cooperative Distributed Systems in AdtechHigh Performance Cooperative Distributed Systems in Adtech
High Performance Cooperative Distributed Systems in Adtech
 

Recently uploaded

SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
Peter Spielvogel
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Aggregage
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
mikeeftimakis1
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
sonjaschweigert1
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 

Recently uploaded (20)

SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 

Evolution of the Netflix API

  • 1. Evolution of the Netflix API QCon San Francisco - November 2013 Ben Christensen Software Engineer – Edge & Playback Services at Netflix @benjchristensen ! ! ! ! http://techblog.netflix.com/
  • 2. Watch the video with slide synchronization on InfoQ.com! http://www.infoq.com/presentations /netflix-api-evolution InfoQ.com: News & Community Site • 750,000 unique visitors/month • Published in 4 languages (English, Chinese, Japanese and Brazilian Portuguese) • Post content from our QCon conferences • News 15-20 / week • Articles 3-4 / week • Presentations (videos) 12-15 / week • Interviews 2-3 / week • Books 1 / month
  • 3. Presented at QCon San Francisco www.qconsf.com Purpose of QCon - to empower software development by facilitating the spread of knowledge and innovation Strategy - practitioner-driven conference designed for YOU: influencers of change and innovation in your teams - speakers and topics driving the evolution and innovation - connecting and catalyzing the influencers and innovators Highlights - attended by more than 12,000 delegates since 2007 - held in 9 cities worldwide
  • 4.
  • 5. More than 40 million Subscribers in 50+ Countries and Territories
  • 6. Netflix accounts for 33% of Peak Downstream Internet Traffic in North America Netflix subscribers are watching more than 1 billion hours a month
  • 7. API traffic has grown from ~20 million/day in 2010 to >2 billion/day millions of API requests per day 2000 1500 1000 500 0 2010 2011 2012 Today
  • 10.
  • 11. At the start … millions of API requests per day 2000 1500 1000 500 0 2008 2009 2010 2011 2012 Today
  • 12. 2008 API Launch Targeted 100% at External Developers Open API Netflix Devices
  • 13. 2008 API Launch Targeted 100% at External Developers Purpose A “Thousand Flowers” of 3rd party innovation ! Audience External Developers
  • 15. In 2011 … millions of API requests per day 2000 1500 1000 500 0 2008 2009 2010 2011 2012 Today
  • 16. 99.9% Netflix Devices Open API Netflix Devices
  • 17. Targeted at Internal Developers Open API Netflix Devices
  • 18. Targeted at Internal Developers Purpose Enable Netflix Experience ! Audience Netflix Device and UI Teams
  • 21. Netflix API Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 22. Netflix API Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 23.
  • 24.
  • 25.
  • 26.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32. User Request Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 33. User Request Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R User request blocked by latency in single network call
  • 34. Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R User Request User Request User Request User Request User Request User Request User Request ............................................. At high volume all request threads can block in seconds
  • 35. ! Dozens of dependencies. ! One going bad takes everything down. ! 30 99.99% = 99.7% uptime ! 0.3% of 1 billion = 3,000,000 failures ! 2+ hours downtime/month ! ! ! Reality is generally worse.
  • 36. CONSTRAINTS Speed of Iteration ! Client Libraries ! Mixed Environment
  • 37. CONSTRAINTS Speed of Iteration ! Client Libraries ! Mixed Environment
  • 38. CONSTRAINTS Speed of Iteration ! Client Libraries ! Mixed Environment
  • 39. CONSTRAINTS Speed of Iteration ! Client Libraries ! Mixed Environment
  • 40. Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R User Request User Request User Request User Request User Request User Request User Request .............................................
  • 41. User Request User Request User Request Logic - argument validation, caches, metrics, logging, multivariate testing, routing, etc Serialization - URL and/or body generation Network Request - TCP/HTTP, latency, 4xx, 5xx, etc ............................................. Deserialization - JSON/XML/Thrift/Protobuf/etc Dependency B cy D Dependency C Dependency E dency G ependency J Dependency M Logic - validation, decoration, object model, caching, metrics, logging, etc Dependency F Dependency H Dependency K Dependency N Dependency I Dependency L Dependency O
  • 42. > 80% of requests rejected Median Latency [Sat Jun 30 04:01:37 2012] [error] proxy: HTTP: disabled connection for (127.0.0.1) "Timeout guard" daemon prio=10 tid=0x00002aaacd5e5000 nid=0x3aac runnable [0x00002aaac388f000] java.lang.Thread.State: RUNNABLE! at java.net.PlainSocketImpl.socketConnect(Native Method)! at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)! - locked <0x000000055c7e8bd8> (a java.net.SocksSocketImpl)! at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)! at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)! at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:391)! at java.net.Socket.connect(Socket.java:579)! at java.net.Socket.connect(Socket.java:528)! at java.net.Socket.(Socket.java:425)! at java.net.Socket.(Socket.java:280)! at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:80)! at org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory$1.doit(ControllerThreadSocketFactory.java:91)! at org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory$SocketTask.run(ControllerThreadSocketFactory.java:158) at java.lang.Thread.run(Thread.java:722)
  • 43. User Request Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 44. User Request Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 45. User Request Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 46. User Request Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 47.
  • 48.
  • 49.
  • 50. circle color and size represent health and traffic volume
  • 51. circle color and size represent health and traffic volume 2 minutes of request rate to show relative changes in traffic
  • 52. circle color and size represent health and traffic volume 2 minutes of request rate to show relative changes in traffic hosts reporting from cluster
  • 53. circle color and size represent health and traffic volume 2 minutes of request rate to show relative changes in traffic hosts reporting from cluster last minute latency percentiles
  • 54. circle color and size represent health and traffic volume 2 minutes of request rate to show relative changes in traffic hosts reporting from cluster Circuit-breaker status last minute latency percentiles
  • 55. circle color and size represent health and traffic volume Request rate 2 minutes of request rate to show relative changes in traffic hosts reporting from cluster Circuit-breaker status last minute latency percentiles
  • 56. circle color and size represent health and traffic volume Error percentage of last 10 seconds Request rate 2 minutes of request rate to show relative changes in traffic hosts reporting from cluster Circuit-breaker status last minute latency percentiles
  • 57. Error percentage of last 10 seconds circle color and size represent health and traffic volume Request rate 2 minutes of request rate to show relative changes in traffic Circuit-breaker status hosts reporting from cluster last minute latency percentiles Rolling 10 second counters with 1 second granularity Successes Short-circuited (rejected) Thread timeouts Thread-pool Rejections Failures/Exceptions
  • 58. User Request Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 59.
  • 60. Zuul Routing Layer Canary vs Baseline Squeeze "Coalmine" Production
  • 61. Zuul Routing Layer Canary vs Baseline Squeeze "Coalmine" Production
  • 62. Zuul Routing Layer Canary vs Baseline Squeeze "Coalmine" Production
  • 63. Zuul Routing Layer Canary vs Baseline Squeeze "Coalmine" Production
  • 64. Zuul Routing Layer Canary vs Baseline Squeeze "Coalmine" Production
  • 65. User Request Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R System Relationship Over Network without Bulkhead
  • 66. Zuul Routing Layer Canary vs Baseline Squeeze "Coalmine" Production
  • 67. Zuul Routing Layer Canary vs Baseline Squeeze "Coalmine" Production
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76. Predictive + Reactive Auto-Scaling
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 86. Netflix API Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 87. Netflix API Dependency A Dependency B Dependency D Dependency C Dependency E Dependency G Dependency F Dependency H Dependency J Dependency M Dependency P Dependency I Dependency K Dependency N Dependency Q Dependency L Dependency O Dependency R
  • 88. One Size Fits All RESTful API millions of API requests per day 2000 1500 1000 500 0 2010 2011 2012 Today
  • 89. One Size Fits All RESTful API millions of API requests per day 2000 1500 1000 500 0 2010 2011 2012 Today
  • 90. One Size Fits All RESTful API 1000+ Devices millions of API requests per day 2000 1500 1000 500 0 2010 2011 2012 Today
  • 91. We wanted to re-architecture our call patterns ...
  • 92. ... to collapse network traffic into coarse API calls ... nested, conditional, concurrent execution
  • 93. ... and we wanted to allow anybody to create endpoints, not just the “API Team”
  • 94.
  • 95. Concurrency without each engineer reading and re-reading this → ! (awesome book ... everybody isn’t going to - or should have to - read it though, that’s the point)
  • 96. Owner of api should retain control of concurrency behavior.
  • 97. Owner of api should retain control of concurrency behavior. public  Data  getData(); What if the implementation needs to change from synchronous to asynchronous? ! How should the client execute that method without blocking? spawn a thread?
  • 98. public  Data  getData(); public  void  getData(Callback<T>  c);   ! public  Future<T>  getData();   ! public  Future<List<Future<T>>>  getData();   ! ! other options ... ?
  • 99. Reactive Programming with Rx Iterable pull T next() throws Exception returns; Observable push onNext(T) onError(Exception) onCompleted()
  • 100. (Functional) Reactive Programming with RxJava Iterable pull T next() throws Exception returns; Observable push onNext(T) onError(Exception) onCompleted()
  • 101. (Functional) Reactive Programming with RxJava Iterable pull T next() throws Exception returns; Observable push onNext(T) onError(Exception) onCompleted()
  • 102. (Functional) Reactive Programming with RxJava Iterable pull T next() throws Exception returns; Observable push onNext(T) onError(Exception) onCompleted()
  • 103. Iterable pull T next() throws Exception returns; !  //  Iterable<String>      //  that  contains  75  Strings    getDataFromLocalMemory()      .skip(10)      .take(5)      .map({  s  -­‐>          return  s  +  "_transformed"})      .forEach(            {  println  "next  =>  "  +  it})   Observable push onNext(T) onError(Exception) onCompleted() !  //  Observable<String>      //  that  emits  75  Strings    getDataFromNetwork()      .skip(10)      .take(5)      .map({  s  -­‐>          return  s  +  "_transformed"})      .subscribe(            {  println  "onNext  =>  "  +  it})  
  • 104. Iterable pull T next() throws Exception returns; !  //  Iterable<String>      //  that  contains  75  Strings    getDataFromLocalMemory()      .skip(10)      .take(5)      .map({  s  -­‐>          return  s  +  "_transformed"})      .forEach(            {  println  "onNext  =>  "  +  it})   Observable push onNext(T) onError(Exception) onCompleted() !  //  Observable<String>      //  that  emits  75  Strings    getDataFromNetwork()      .skip(10)      .take(5)      .map({  s  -­‐>          return  s  +  "_transformed"})      .subscribe(            {  println  "onNext  =>  "  +  it})  
  • 106. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() String s = getData(args); if (s.equals(x)) { // do something } else { // do something else }
  • 107. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Iterable<String> values = getData(args); for (String s : values) { if (s.equals(x)) { // do something } else { // do something else } }
  • 108. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Future<String> s = getData(args); if (s.get().equals(x)) { // do something } else { // do something else }
  • 109. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Future<String> s = getData(args); if (s.get().equals(x)) { // do something } else { // do something else }
  • 110. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Future<String> s = getData(args); Futures.addCallback(s, new FutureCallback<String> { public void onSuccess(String s) { if (s.equals(x)) { // do something } else { // do something else } } }, executor);
  • 111. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Future<String> s = getData(args); Futures.addCallback(s, new FutureCallback<String> { public void onSuccess(String s) { if (s.equals(x)) { // do something } else { // do something else } } }, executor);
  • 112. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Future<String> s = getData(args); Futures.addCallback(s, new FutureCallback<String> { public void onSuccess(String s) { if (s.equals(x)) { // do something } else { // do something else } } }, executor);
  • 113. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() CompletableFuture<String> s = getData(args); s.thenApply((v) -> { if (v.equals(x)) { // do something } else { // do something else } });
  • 114. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() CompletableFuture<String> s = getData(args); s.thenApply((v) -> { if (v.equals(x)) { // do something } else { // do something else } });
  • 115. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Future<String> s = getData(args); s.map({ s -> if (s.equals(x)) { // do something } else { // do something else } });
  • 116. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Future<String> s = getData(args); s.map({ s -> if (s.equals(x)) { // do something } else { // do something else } });
  • 117. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Future<String> s = getData(args); s.map({ s -> if (s.equals(x)) { // do something } else { // do something else } });
  • 118. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Observable<String> s = getData(args); s.map({ s -> if (s.equals(x)) { // do something } else { // do something else } });
  • 119. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Observable<String> s = getData(args); s.map({ s -> if (s.equals(x)) { // do something } else { // do something else } });
  • 120. Single Multiple Sync T getData() Iterable<T> getData() Async Future<T> getData() Observable<T> getData() Observable<String> s = getData(args); s.map({ s -> if (s.equals(x)) { // do something } else { // do something else } });
  • 121. instead of a blocking api ... class  VideoService  {        def  VideoList  getPersonalizedListOfMovies(userId);        def  VideoBookmark  getBookmark(userId,  videoId);        def  VideoRating  getRating(userId,  videoId);        def  VideoMetadata  getMetadata(videoId);   } ... create an observable api: class  VideoService  {        def  Observable<VideoList>  getPersonalizedListOfMovies(userId);        def  Observable<VideoBookmark>  getBookmark(userId,  videoId);        def  Observable<VideoRating>  getRating(userId,  videoId);        def  Observable<VideoMetadata>  getMetadata(videoId);   }
  • 122. RxJava http://github.com/Netflix/RxJava “a library for composing asynchronous and event-based programs using observable sequences for the Java VM” A Java port of Rx (Reactive Extensions) https://rx.codeplex.com (.Net and Javascript by Microsoft)
  • 123. client code treats all interactions with the api as asynchronous ! ! the api implementation chooses whether something is blocking or non-blocking and what resources it uses
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130. Netflix API Server Device Optimize for Each Device. Leverage the Server
  • 131. Code
  • 132. SDK for API Web Service Development
  • 133. SDK for API Web Service Development
  • 134. SDK for API Web Service Development
  • 136. api.servletResponse.writer.print("Hello") $runScript.py -e PROD sample.groovy Hello ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################ [0ms] INFO: User => NULL ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################
  • 137. api.servletResponse.writer.print("Hello") $runScript.py -e PROD sample.groovy Hello ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################ [0ms] INFO: User => NULL ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################
  • 138. api.servletResponse.writer.print("Hello") $runScript.py -e PROD sample.groovy Hello ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################ [0ms] INFO: User => NULL ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################
  • 139. api.servletResponse.writer.print("Hello") $runScript.py -e PROD sample.groovy Hello ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################ [0ms] INFO: User => NULL ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################
  • 140. api.servletResponse.writer.print("Hello") $runScript.py -e PROD sample.groovy Hello ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################ [0ms] INFO: User => NULL ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################
  • 141. api.servletResponse.writer.print("Hello") $runScript.py -e PROD sample.groovy Hello ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################ [0ms] INFO: User => NULL ################################################################################################ ####### Script Logger (enabled via debug=true request parameter) ################################################################################################
  • 142. public class HelloEndpoint extends APIEndpoint { @Override public void execute(APIRequest api) throws Throwable { // get a request parameter from servlet request String alias = api.servletRequest.getParameter("name"); ! // set content type and write something to servlet response api.servletResponse.setContentType("application/json"); api.servletResponse.writer.print( JsonUtility.toJson( [ alias : alias, name : api.user.firstName ] ) ) ! } }
  • 143. public class HelloEndpoint extends APIEndpoint { @Override public void execute(APIRequest api) throws Throwable { // get a request parameter from servlet request String alias = api.servletRequest.getParameter("name"); ! // set content type and write something to servlet response api.servletResponse.setContentType("application/json"); api.servletResponse.writer.print( JsonUtility.toJson( [ alias : alias, name : api.user.firstName ] ) ) ! } } runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy
  • 144. public class HelloEndpoint extends APIEndpoint { @Override public void execute(APIRequest api) throws Throwable { // get a request parameter from servlet request String alias = api.servletRequest.getParameter("name"); ! // set content type and write something to servlet response api.servletResponse.setContentType("application/json"); api.servletResponse.writer.print( JsonUtility.toJson( [ alias : alias, name : api.user.firstName ] ) ) ! } } runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy {"alias":"bob","name":"Old"}
  • 145. public class HelloEndpoint extends APIEndpoint { @Override public void execute(APIRequest api) throws Throwable { // get a request parameter from servlet request String alias = api.servletRequest.getParameter("name"); ! // set content type and write something to servlet response api.servletResponse.setContentType("application/json"); api.servletResponse.writer.print( JsonUtility.toJson( [ alias : alias, name : api.user.firstName ] ) ) ! } } runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy {"alias":"bob","name":"Old"}
  • 146. public class HelloEndpoint extends APIEndpoint { @Override public void execute(APIRequest api) throws Throwable { // get a request parameter from servlet request String alias = api.servletRequest.getParameter("name"); ! // set content type and write something to servlet response api.servletResponse.setContentType("application/json"); api.servletResponse.writer.print( JsonUtility.toJson( [ alias : alias, name : api.user.firstName ] ) ) ! } } runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy {"alias":"bob","name":"Old"}
  • 147. public class HelloEndpoint extends APIEndpoint { @Override public void execute(APIRequest api) throws Throwable { // get a request parameter from servlet request String alias = api.servletRequest.getParameter("name"); ! // set content type and write something to servlet response api.servletResponse.setContentType("application/json"); api.servletResponse.writer.print( JsonUtility.toJson( [ alias : alias, name : api.user.firstName ] ) ) ! } } runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy {"alias":"bob","name":"Old"}
  • 148. public class HelloEndpoint extends APIEndpoint { @Override public void execute(APIRequest api) throws Throwable { // get a request parameter from servlet request String alias = api.servletRequest.getParameter("name"); ! // set content type and write something to servlet response api.servletResponse.setContentType("application/json"); api.servletResponse.writer.print( JsonUtility.toJson( [ alias : alias, name : api.user.firstName ] ) ) ! } } runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy {"alias":"bob","name":"Old"}
  • 149. public class HelloEndpoint extends APIEndpoint { @Override public void execute(APIRequest api) throws Throwable { // get a request parameter from servlet request String alias = api.servletRequest.getParameter("name"); ! // set content type and write something to servlet response api.servletResponse.setContentType("application/json"); api.servletResponse.writer.print( JsonUtility.toJson( [ alias : alias, name : api.user.firstName ] ) ) ! } } runScript.py -e TEST --userId 1189658154 --args "name=bob" HelloEndpoint.groovy {"alias":"bob","name":"Old"}
  • 150. public Observable getVideoSummary(APIVideo video) { // get id, title def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)] ! // get bookmark def bookmarkObservable = getBookmark(video) ! // get artwork def artworkObservable = getArtworkImageUrl(video) ! // merge them and accumulate into the seed. return Observable.merge(bookmarkObservable, artworkObservable) .reduce(seed, { aggregate, current -> aggregate << current}) .map({ [ (video.id.toString()) : it]}) }
  • 151. public Observable getVideoSummary(APIVideo video) { // get id, title def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)] ! // get bookmark def bookmarkObservable = getBookmark(video) ! // get artwork def artworkObservable = getArtworkImageUrl(video) ! // merge them and accumulate into the seed. return Observable.merge(bookmarkObservable, artworkObservable) .reduce(seed, { aggregate, current -> aggregate << current}) .map({ [ (video.id.toString()) : it]}) }
  • 152. public Observable getVideoSummary(APIVideo video) { // get id, title def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)] ! // get bookmark def bookmarkObservable = getBookmark(video) ! // get artwork def artworkObservable = getArtworkImageUrl(video) ! // merge them and accumulate into the seed. return Observable.merge(bookmarkObservable, artworkObservable) .reduce(seed, { aggregate, current -> aggregate << current}) .map({ [ (video.id.toString()) : it]}) }
  • 153. public Observable getVideoSummary(APIVideo video) { // get id, title def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)] ! // get bookmark def bookmarkObservable = getBookmark(video) ! // get artwork def artworkObservable = getArtworkImageUrl(video) ! // merge them and accumulate into the seed. return Observable.merge(bookmarkObservable, artworkObservable) .reduce(seed, { aggregate, current -> aggregate << current}) .map({ [ (video.id.toString()) : it]}) }
  • 154. public Observable getVideoSummary(APIVideo video) { // get id, title def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)] ! // get bookmark def bookmarkObservable = getBookmark(video) ! // get artwork def artworkObservable = getArtworkImageUrl(video) ! // merge them and accumulate into the seed. return Observable.merge(bookmarkObservable, artworkObservable) .reduce(seed, { aggregate, current -> aggregate << current}) .map({ [ (video.id.toString()) : it]}) }
  • 155. public Observable getVideoSummary(APIVideo video) { // get id, title def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)] ! // get bookmark def bookmarkObservable = getBookmark(video) ! // get artwork def artworkObservable = getArtworkImageUrl(video) ! // merge them and accumulate into the seed. return Observable.merge(bookmarkObservable, artworkObservable) .reduce(seed, { aggregate, current -> aggregate << current}) .map({ [ (video.id.toString()) : it]}) }
  • 156. public Observable getVideoSummary(APIVideo video) { // get id, title def seed = [id: video.id, title : video.getTitle(APIVideo.TitleType.REGULAR)] ! // get bookmark def bookmarkObservable = getBookmark(video) ! // get artwork def artworkObservable = getArtworkImageUrl(video) ! // merge them and accumulate into the seed. return Observable.merge(bookmarkObservable, artworkObservable) .reduce(seed, { aggregate, current -> aggregate << current}) .map({ [ (video.id.toString()) : it]}) }
  • 157. $ uploadScript.py -e TEST /test/hello sample.groovy { "active": false, "allocationPercentage": 0, "creationDate": "Mon Nov 11 05:38:51 UTC 2013", "revision": 1, "userAuthorizationRequired": true, "userAuthorizationType": "https" }
  • 158. $ uploadScript.py -e TEST /test/hello sample.groovy { "active": false, "allocationPercentage": 0, "creationDate": "Mon Nov 11 05:38:51 UTC 2013", "revision": 1, "userAuthorizationRequired": true, "userAuthorizationType": "https" }
  • 159. $ uploadScript.py -e TEST /test/hello sample.groovy { "active": false, "allocationPercentage": 0, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" }
  • 160. $ uploadScript.py -e TEST /test/hello sample.groovy { "active": false, "allocationPercentage": 0, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" } $ activateScript.py -e TEST --revision 2 /test/hello { "active": true, "allocationPercentage": 100, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "previousRevision": null, "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" }
  • 161. $ uploadScript.py -e TEST /test/hello sample.groovy { "active": false, "allocationPercentage": 0, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" } $ activateScript.py -e TEST --revision 2 /test/hello { "active": true, "allocationPercentage": 100, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "previousRevision": null, "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" }
  • 162. $ uploadScript.py -e TEST /test/hello sample.groovy { "active": false, "allocationPercentage": 0, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" } $ activateScript.py -e TEST --revision 2 /test/hello { "active": true, "allocationPercentage": 100, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "previousRevision": null, "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" }
  • 163. $ uploadScript.py -e TEST /test/hello sample.groovy { "active": false, "allocationPercentage": 0, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" } $ activateScript.py -e TEST --revision 2 /test/hello { "active": true, "allocationPercentage": 100, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "previousRevision": null, "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" }
  • 164. $ uploadScript.py -e TEST /test/hello sample.groovy { "active": false, "allocationPercentage": 0, "creationDate": "Mon Nov 11 05:40:26 UTC 2013", "revision": 2, "userAuthorizationRequired": true, "userAuthorizationType": "https" } $ activateScript.py -e TEST --revision 3 /test/hello { "active": true, "allocationPercentage": 100, "creationDate": "Mon Nov 11 05:42:05 UTC 2013", "previousRevision": 2, "revision": 3, "userAuthorizationRequired": true, "userAuthorizationType": "https" }
  • 165. Future
  • 166. millions of API requests per day 2000 1500 1000 500 0 2008 2009 2010 2011 2012 Today
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174. /tv/home /android/home /ps3/home Functional Reactive Dynamic Endpoints Asynchronous Java API Dependency A 10 Threads Dependency F 10 Threads Dependency K 15 Threads Dependency P 10 Threads Dependency B 8 Threads Dependency G 10 Threads Dependency L 4 Threads Dependency Q 8 Threads Dependency C 10 Threads Dependency H 10 Threads Dependency M 5 Threads Dependency R 10 Threads Dependency D 15 Threads Dependency I 5 Threads Dependency N 10 Threads Dependency S 8 Threads Dependency E 5 Threads Dependency J 8 Threads Dependency O 10 Threads Dependency T 10 Threads
  • 175. /tv/home /android/home /ps3/home Hystrix Functional Reactive Dynamic Endpoints fault-isolation layer Asynchronous Java API Dependency A 10 Threads Dependency F 10 Threads Dependency K 15 Threads Dependency P 10 Threads Dependency B 8 Threads Dependency G 10 Threads Dependency L 4 Threads Dependency Q 8 Threads Dependency C 10 Threads Dependency H 10 Threads Dependency M 5 Threads Dependency R 10 Threads Dependency D 15 Threads Dependency I 5 Threads Dependency N 10 Threads Dependency S 8 Threads Dependency E 5 Threads Dependency J 8 Threads Dependency O 10 Threads Dependency T 10 Threads
  • 176. + Observable<User>  u  =  new  GetUserCommand(id).observe();   Observable<Geo>  g  =  new  GetGeoCommand(request).observe();   ! Observable.zip(u,  g,  {user,  geo  -­‐>                    return  [username:  user.getUsername(),                                    currentLocation:  geo.getCounty()]         }) RxJava in Hystrix 1.3+ https://github.com/Netflix/Hystrix
  • 177.
  • 178.
  • 179. Ben Christensen @benjchristensen http://www.linkedin.com/in/benjchristensen jobs.netflix.com ! Functional Reactive in the Netflix API with RxJava http://techblog.netflix.com/2013/02/rxjava-netflix-api.html ! Optimizing the Netflix API http://techblog.netflix.com/2013/01/optimizing-netflix-api.html ! Application Resilience in a Service-oriented Architecture http://programming.oreilly.com/2013/06/application-resilience-in-a-service-oriented-architecture.html ! Fault Tolerance in a High Volume, Distributed System http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html ! Making the Netflix API More Resilient http://techblog.netflix.com/2011/12/making-netflix-api-more-resilient.html
  • 180. Watch the video with slide synchronization on InfoQ.com! http://www.infoq.com/presentations/netflixapi-evolution