Reactive REST

  • 1,100 views
Uploaded on

Video and slides synchronized, mp3 and slide download available at URL http://bit.ly/1gtG0yb. …

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.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,100
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
0
Comments
0
Likes
8

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. + JSONG JSONGPath HTTP Path Evaluators Reactive REST RESTful API for Application Data
  • 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.
  • 5. + Netflix
  • 6. + Question What’s the most successful distributed system designed for information browsing?
  • 7. + Answer
  • 8. + WWW Caching index.html Browser Cache index.html index.html cnn.com
  • 9. + REST  Unique ID for every resource  Idempotent VERBS  GET  PUT
  • 10. + REST Benefits  Cache Transparency  Cache Coherence
  • 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!
  • 14. + Challenge Can we build a high-performance REST API for our data?
  • 15. + Introducing Falkor  RESTful Query API for Data  Coherent, Transparent, Managed Cache  Efficient bulk data transfer over HTTP  Query Optimization
  • 16. + Netflix Domain Model
  • 17. + Netflix Domain Model http://netflix.com/user { videoLists: [ [ { name: “Die hard”, rating: 4.0 }, // more titles ], [ { name: “Die hard”, rating: 4.0 }, // more titles ], // more lists… ] }
  • 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”]
  • 27. + Question So how does it work?
  • 28. + Features  Efficient data transfer over HTTP  Cache Coherence  Cache Transparency  Query Optimization
  • 29. + One Resource/One Domain Model http://netflix.com/videos/234234/name http://netflix.com/videos/234234/rating http://netflix.com/videos/54325/name http://netflix.com/user?path=[“videos”,234,”name”]&path=… 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
  • 30. + Features  Efficient data transfer over HTTP  Cache Coherence  Cache Transparency  Query Optimization
  • 31. + Netflix Domain Model http://netflix.com/user { videoLists: { “0”: { “name”: “Thrillers”, “0”: { name: “Die hard”, rating: 4.0 }, // more titles length: 74, }, “1”: { “name”: “Action Movies”, “0”: { name: “Die hard”, rating: 4.0 }, // more titles length: 74 }, // more lists… length: 25 } }
  • 32. + What’s wrong with JSON? “videoLists” “0” “0” “name” “Die Hard” “1” “0” Same movie appears twice in the same message! “name” “Die Hard”
  • 33. + The Problem How to model a graph in JSON?
  • 34. + Introducing JSON Graph (JSONG)
  • 35. + JSONG  Graph representation language in JSON  Two types: 1. Maps 2. Values (includes Arrays)
  • 36. + JSONG Benefits  Serializable  Partitionable
  • 37. + JSON http://netflix.com/user { videoLists: { “0”: { “name”: “Thrillers”, “0”: { id: 2654, name: “Die hard”, rating: 4.0 }, // more titles length: 74, }, “1”: { “name”: “Action Movies”, “0”: { id: 2654, name: “Die hard”, rating: 4.0 }, // more titles length: 74 }, // more lists… length: 25 } }
  • 38. + JSONG http://netflix.com/user { videoLists: { “0”: { “name”: “Thrillers”, “0”: [“videos”, 2654], // more titles length: 74, }, “1”: { “name”: “Action Movies”, “0”: [“videos”, 2654], // more titles length: 74 }, // more lists… length: 25 }, videos: { 2654: { name: “Die hard”, rating: 4.0 } } }
  • 39. + Okay so we’ve got a graph… …now we need a convenient API for querying data.
  • 40. + Hierarchical API var userModel = { videoLists: { “0”: { “name”: “Thrillers”, “0”: { id: 2654, name: “Die hard”, rating: 4.0 }, // more titles length: 74, } } } JSONG Path userModel[‘videoLists’][0][0][‘name’] [‘videoLists’, 0, 0, ‘name’]
  • 41. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } [“videoLists”,0,0,”name”]
  • 42. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } [“videoLists”,0,0,”name”]
  • 43. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } [“videoLists”,0,0,”name”]
  • 44. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } [“videoLists”,0,0,”name”]
  • 45. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } Array found before last key evaluated… [“videoLists”,0,0,”name”]
  • 46. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } Array must be a path! [“videoLists”,0,0,”name”]
  • 47. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } Array must be a path! [“videos”,234,”name”]
  • 48. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } Rewrite path, and start evaluating from top node. [“videos”,234,”name”]
  • 49. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } [“videos”,234,”name”]
  • 50. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } [“videos”,234,”name”]
  • 51. + JSONG Path Evaluation var netflixUser = { videoLists: { “0”: { name: “Thrillers”, “0”: [“videos”,234], // more videos… length: 75 }, “1”: { name: “Action Movies”, “0”: [“videos”,234], // more videos… length: 75 }, // more lists… length: 15 }, videos: { 234: {name: “Die Hard”, rating:5} } } [“videos”,234,”name”]
  • 52. + Okay… …how do we make this process transparent to the developer?
  • 53. + Features  Efficient data transfer over HTTP  Cache Coherence  Cache Transparency  Query Optimization
  • 54. + Path Evaluator Path Evaluator get(Observable<Path>): Observable<PathBoundValue> set(Observable<PathBoundValue>): Observable<PathBoundValue> delete(Observable<Path>): Observable<PathBoundValue>
  • 55. + Observable  Object  Open that represents stream of data Source Reactive Extensions Library  Ported to  Javascript  .NET C  Java (Netflix)
  • 56. + Observable.forEach // “subscribe” var subscription = remoteModel.get([“videoLists”,0,0,”name”]). forEach( event => console.log(event),error error => console.error(error), () => console.log(“done”)); // “unsubscribe” subscription.dispose(); optional
  • 57. + Path Evaluator  Proxy for a JSONG Model  Idempotent Operations:   Set   Get Delete Composable
  • 58. + Path Evaluator Implementations  RemotePathEvaluator  SizedMemoryPathEvaluator  CachedPathEvaluator  LocalStoragePathEvaluator?  etc
  • 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: {…} }
  • 74. + Features  Efficient data transfer over HTTP  Cache Coherence  Cache Transparency  Query Optimization
  • 75. + Query Optimization
  • 76. + Query Optimization Client Memory Server Path Evaluator var netflixMember = { videoLists: { name: “Action Movies”, “0”: [“lists”, 54354334], // more lists… “length: 15 }, “videos”: { “34123432”: { … } } } TV Path Evaluator Falkor Server Sized Memory Path Evaluator Remote Path Evaluator Cached Path Evaluator [videoLists,1,3,’rating’]
  • 77. + Query Optimization Client Memory Server Path Evaluator var netflixMember = { videoLists: { name: “Action Movies”, “0”: [“lists”, 54354334], // more lists… “length: 15 }, “videos”: { “34123432”: { … } } } TV Path Evaluator Falkor Server Sized Memory Path Evaluator Remote Path Evaluator Cached Path Evaluator [videoLists,1,3,’rating’]
  • 78. + Query Optimization Client Memory Server Path Evaluator var netflixMember = { videoLists: { name: “Action Movies”, “0”: [“lists”, 54354334], // more lists… “length: 15 }, “videos”: { “34123432”: { … } } } TV Path Evaluator Falkor Server Sized Memory Path Evaluator Remote Path Evaluator [videoLists,1,3,’rating’] Cached Path Evaluator [videoLists,1,3,’rating’]
  • 79. + Query Optimization Client Memory Server Path Evaluator var netflixMember = { videoLists: { name: “Action Movies”, “0”: [“lists”, 54354334], // more lists… “length: 15 }, “videos”: { “34123432”: { … } } } TV Path Evaluator Falkor Server Sized Memory Path Evaluator Remote Path Evaluator {path: [videoLists,1], value: [lists,23432] } {path: [lists,23432,0], value: [movies,234234] } Cached Path Evaluator [videoLists,1,3,’rating’]
  • 80. + Query Optimization Client Memory Server Path Evaluator var netflixMember = { videoLists: { name: “Action Movies”, “0”: [“lists”, 54354334], // more lists… “length: 15 }, “videos”: { “34123432”: { … } } } TV Path Evaluator Falkor Server Sized Memory Path Evaluator Remote Path Evaluator [movies,234234,rating] Cached Path Evaluator Path optimized!!
  • 81. + Query Optimization  Path partially evaluated in the cache  Path is rewritten and optimized before it is sent to server
  • 82. + Query Optimization Rocks! Same API for local and remote data!
  • 83. + Features  Efficient data transfer over HTTP  Cache Coherence  Cache Transparency  Query Optimization
  • 84. + Roadmap  Currently Internal Software  Defensive Patent Filed  Plan to open-source 2014
  • 85. + Questions?
  • 86. Watch the video with slide synchronization on InfoQ.com! http://www.infoq.com/presentations/netflixreactive-rest