Video and slides synchronized, mp3 and slide download available at URL http://bit.ly/1gtG0yb.
Jafar Husain explains how Netflix uses reactive programming to build and consume REST endpoints, and how they work around the limitations of the HTTP protocol to create high-performance REST APIs. Filmed at qconsf.com.
Jafar Husain has been working as a software developer for 16 years. He's developed software for companies like GE, Microsoft, and Netflix. He specializes in building web servers and clients using functional reactive programming, and was the first user of the Reactive Extensions Framework. He's also responsible for "Falkor", a RESTful data access framework that powers most Netflix clients.
2. Watch the video with slide
synchronization on InfoQ.com!
http://www.infoq.com/presentations
/netflix-reactive-rest
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. +
The is the story…
…of how we freed REST from HTTP...
…and discovered it was even more
Powerful than we thought it was.
11. +
REST + HTTP: Two great tastes
Unique ID for every resource (URL)
Idempotent VERBS
GET
PUT
Cache Control Headers for Invalidation
12. +
Netflix is a web application…
Why not use the browser cache for our data?
13. +
Why not the Browser Cache?
http://netflix.com/videos/234234
http://netflix.com/videos/234234/rating
http://netflix.com/videos/54325
http://netflix.com/videos/54325/rating
http://netflix.com/videos/12356/name
http://netflix.com/videos/12356/rating
http://netflix.com/videos/876456/name
http://netflix.com/videos/876456/rating
Too many HTTP requests!
15. +
Introducing Falkor
RESTful Query API for Data
Coherent, Transparent, Managed Cache
Efficient bulk data transfer over HTTP
Query Optimization
18. +
RESTful Data Access API
var userModel = {
videoLists: {
“0”: {
“name”: “Thrillers”,
“0”: {
id: 2654,
name: “Die hard”,
rating: 4.0
},
// more titles
length: 74,
}
}
}
userModel[‘videoLists’][0][0][‘name’]
[‘videoLists’, 0, 0, ‘name’]
19. +
Building a Proxy for a Remote Model
// Create a proxy or the current user’s domain model
var remoteModel =
new RemotePathEvaluator(“http://netflix.com/user”);
Server Path Evaluator
Falkor Server
Remote Path Evaluator
20. +
Retrieving Data from the Server
// Retrieve the name of the first title in the first genre list.
var remoteModel.
get([“videoLists”,0,0,”name”]).
forEach(function(pathBoundValue) {
console.log(pathBoundValue);
});
[“videoLists”,0,0,”name”]
{
path: [“videoLists”,0,0,”name”],
value: “Die Hard”
}
netflix.com/user
21. +
Retrieving Sub Graph
// Retrieve the names of the first 10 title in the first
// 10 genre lists.
var remoteModel.
get([“videoLists”,{from:0,to:9},{from:0,to:9},”name”]).
forEach(function(pathBoundValue) {
console.log(pathBoundValue);
});
>
>
>
>
>
{path: [“videoLists”,0,0,”name”],
{path: [“videoLists”,0,1,”name”],
// snip
{path: [“videoLists”,9,8,”name”],
{path: [“videoLists”,9,9,”name”],
value: “Die Hard”}
value: “Amelie”}
value: “The New Guys”}
value: “Animal House”}
22. +
Caching Data
// Create a proxy or the current user’s domain model
var remoteModel =
new RemotePathEvaluator(“http://netflix.com/user”);
// Create a path evaluator for a local, in-memory cache.
// Cache uses LRU to ensure size stays < 10000.
var localModel = new SizedMemoryPathEvaluator(10000, {});
// Create a cached path evaluator, using the remoteModel as the
// source and the in-memory model as the cache.
var cachedModel = remoteModel.cache(localModel);
23. +
Caching Data on the Client
Client Memory
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
Cached Path Evaluator
24. +
Retrieving Cached Data
var cachedModel.
get([“videoLists”,0,0,”name”]).
forEach(function(pathBoundValue) {
console.log(pathBoundValue.value);
});
[“videoLists”,0,0,”name”]
{
path: [“videoLists”,0,0,”name”],
value: “Die Hard”
}
Local
Cache
Cache
[“videoLists”,0,0,”name”]
25. +
Retrieving Cached Data
var cachedModel.
get([“videoLists”,0,0,”name”]).
forEach(function(pathBoundValue) {
console.log(pathBoundValue.value);
});
[“videoLists”,0,0,”name”]
{
path: [“videoLists”,0,0,”name”],
value: “Die Hard”
}
Local
Cache
Cache
26. +
Query Optimization
// Query for another video property can be optimized!
var cachedModel.
get([“videoLists”,0,0,”rating”]).
forEach(function(pathBoundValue) {
console.log(pathBoundValue.value);
});
Query is transparently optimized!
[“videoLists”,0,0,”rating”]
{
path: [“videoLists”,0,0,”rating”],
value: “Die Hard”
}
Local
Cache
Cache
[“videos”,234234,”rating”]
59. +
Accessing Data on the Client
// Create a Proxy path evaluator for the server JSONG domain model
var remoteModel =
new RemotePathEvaluator(“http://netflix.com/tvui/user”);`
60. +
Accessing Data on the Client
// Create a Proxy path evaluator for the server JSONG domain model
var remoteModel =
new RemotePathEvaluator(“http://netflix.com/tvui/user”);`
Server Path Evaluator
Remote Path Evaluator
61. +
Accessing Data on the Client
// Create a Proxy path evaluator for the server JSONG domain model
var remoteModel =
new RemotePathEvaluator(“http://netflix.com/tvui/user”);
remoteModel.get([“videoLists”,{to:5},{to:10},”name”]).
forEach(function(pathBoundValue) { /* do something */ });
Server Path Evaluator
[videoLists,{to:5},{to:10},’name’]
Remote Path Evaluator
62. +
Accessing Data on the Client
// Create a Proxy path evaluator for the server JSONG domain model
var remoteModel =
new RemotePathEvaluator(“http://netflix.com/tvui/user”);
remoteModel.get([“videoLists”,{to:5},{to:10},”name”]).
forEach(function(pathBoundValue) { /* do something */ });
Server Path Evaluator
{ path: [“videoLists”,0,0,”name”], value: {…} }
{ path: [“videoLists”,0,1,”name”], value: {…} }
…
{ path: [“videoLists”,5,10,”name”], value: {…} }
Remote Path Evaluator
63. +
Caching Data on the Client
// Create a Proxy path evaluator for the server JSONG domain model
var remoteModel =
new RemotePathEvaluator(“http://netflix.com/tvui/user”);
// Create a path evaluator for a local, in-memory cache.
// Cache stores the fragments of the remote model and stays within
// size of 10000.
var localModelCache = new SizedMemoryPathEvaluator(10000, {});
Client Memory
Server Path Evaluator
Sized Memory Path Evaluator
Remote Path Evaluator
64. +
Sized Memory Path Evaluator
Works like a web browser cache!
Caches resources by path
Removes least-recently used resources
65. +
Caching Data on the Client
// Create a Proxy path evaluator for the server JSONG domain model
var remoteModel =
new RemotePathEvaluator(“http://netflix.com/tvui/user”);
// Create a path evaluator for a local, in-memory cache.
// Cache stores the fragments of the remote model and stays within
// size of 10000.
var localModel = new SizedMemoryPathEvaluator(10000, {});
// Create a cached path evaluator, using the remoteModel as the
// source and the in-memory model as the cache.
var cachedModel = remoteModel.cache(localModel);
66. +
Caching Data on the Client
Client Memory
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
Cached Path Evaluator
[videoLists,{to:5},{to:10},’name’]
67. +
Caching Data on the Client
Client Memory
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
Cached Path Evaluator
68. +
Caching Data on the Client
Client Memory
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
[videoLists,{to:5},{to:10},’name’]`
Cached Path Evaluator
69. +
Caching Data on the Client
Client Memory
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
Nothing
Cached Path Evaluator
70. +
Caching Data on the Client
Client Memory
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
[videoLists,{to:5},{to:10},’name’]
Cached Path Evaluator
71. +
Caching Data on the Client
Client Memory
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
{ path: [“videoLists”,0,0,”name”], value: {…} }
{ path: [“videoLists”,0,1,”name”], value: {…} }
…
{ path: [“videoLists”,5,10,”name”], value: {…} }
Cached Path Evaluator
72. +
Caching Data on the Client
Client Memory
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
{ path: [“videoLists”,0,0,”name”], value: {…} }
{ path: [“videoLists”,0,1,”name”], value: {…} }
…
{ path: [“videoLists”,5,10,”name”], value: {…} }
Cached Path Evaluator
73. +
Caching Data on the Client
Client Memory
var netflixMember = {
videoLists: {
name: “Action Movies”,
“0”: [“lists”, 54354334],
// more lists…
“length: 15
},
“videos”: {
“34123432”:
{ … }
}
}
Server Path Evaluator
Falkor Server
Sized Memory Path Evaluator
Remote Path Evaluator
Cached Path Evaluator
{ path: [“videoLists”,0,0,”name”], value: {…} }
{ path: [“videoLists”,0,1,”name”], value: {…} }
…
{ path: [“videoLists”,5,10,”name”], value: {…} }