Successfully reported this slideshow.

Async Microservices with Twitter's Finagle

18

Share

Upcoming SlideShare
Finch + Finagle OAuth2
Finch + Finagle OAuth2
Loading in …3
×
1 of 37
1 of 37

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

Related Audiobooks

Free with a 14 day trial from Scribd

See all

Async Microservices with Twitter's Finagle

  1. 1. Async Microservices with Finagle Vladimir Kostyukov http://vkostyukov.ru
  2. 2. Asynchronous Protocol-Agnostic Full-Stack RPC 2
  3. 3. Adopters 3
  4. 4. Built atop of Netty (#1 Non-Blocking I/O for JVM) 4
  5. 5. Finagle - Netty in a functional setting 5
  6. 6. Building Blocks: Services + Futures + Filters 6
  7. 7. trait Service[-Req, +Rep] extends (Req => Future[Rep]) 7
  8. 8. Service-Oriented rather then Stream-Oriented 8
  9. 9. // TODO: Don't forget to remove it in production. object GetDeveloperPromotionDate extends Service[Developer, Date] { def apply(req: Developer) = Future.never } val date: Future[Date] = GetDeveloperPromotionDate(Developer.Myself) 9
  10. 10. 1 val respond = new Service[HttpRequest, HttpResponse] { 2 def apply(req: HttpRequest) = { 3 val rep = new DefaultHttpResponse(HttpVersion.HTTP_1_1, 4 HttpResponseStatus.OK) 5 rep.setContentString(req.getUri()) 6 Future.value(rep) 7 } 8 } 9 10 Await.ready(Http.serve(":8080", respond) 10
  11. 11. Servers and Clients talk to each other via services 11
  12. 12. 1 val to = Http.newService("google.com") 2 3 val proxy = new Service[HttpRequest, HttpResponse] { 4 def apply(req: HttpRequest) = to(req) 5 } 6 7 Await.ready(Http.serve(":8080", proxy) 12
  13. 13. Are there high-order services? 13
  14. 14. 14 Client Service Server Filter Filter Filter Service
  15. 15. // ReqIn -> Service(ReqOut -> RepIn) -> RepOut trait Filter[-ReqIn, +RepOut, +ReqOut, -RepIn] extends ((ReqIn, Service[ReqOut, RepIn]) => Future[RepOut]) 15
  16. 16. // A filter that does nothing. def identity[Req, Rep] = new Filter[Req, Rep, Req, Rep] { def apply(req: Req, service: Service[Req, Rep]) = service(req) } val auth = identity[HttpRequest, HttpResponse] 16
  17. 17. Filters are type-safe! 17
  18. 18. A Type-Safe Input Filter 1 object TurnAIntoB extends Filter[A, Rep, B, Rep] { 2 def apply(req: A, service: Service[B, Rep]): Future[Rep] = 3 service(req.toB) 4 } 5 6 val serviceOfB: Service[B, Rep] = ... 7 val serviceOfA: Service[A, Rep] = TurnAIntoB andThen serviceOfA 18
  19. 19. A Type-Safe Output Filter 1 object TurnAIntoB extends Filter[Req, B, Req, A] { 2 def apply(req: Req, service: Service[Req, A]): Future[B] = 3 service(req) map { a => a.toB } 4 } 5 6 val serviceOfA: Service[Req, A] = ... 7 val serviceOfB: Service[Req, B] = TurnAIntoB andThen serviceOfA 19
  20. 20. Case Study: TimeOut Filter 1 def timeout[Req, Rep](timeout: Duration)(implicit timer: Timer) = 2 new SimpleFilter[Req, Rep] { 3 def apply(req: Req, service: Service[Req, Rep]) = 4 service(req).within(timer, timeout) 5 } 6 7 val handleExceptions = new SimpleFilter[Req, Rep] { 8 def apply(req: Req, service: Service[Req, Rep]) = 9 service(req) handle { 10 case t: TimeOutException => Future.value(defaultRep) 11 } 12 } 13 14 val respond = new Service[Req, Rep] { ... } 15 // We guarantee 3 seconds response time. 16 val backend = handleExceptions andThen 17 timeout(3.seconds) andThen 18 respond 20
  21. 21. Case Study: OAuth2Filter 1 class OAuth2Filter[U](dataHandler: DataHandler[U]) 2 extends Filter[HttpRequest, HttpResponse, OAuth2Request[U], HttpResponse] 3 with OAuth2 with OAuthErrorHandler { 4 5 def handleError(e: OAuthError) = e.toHttpResponse 6 def apply(req: HttpRequest, service: Service[OAuth2Request[U], HttpResponse]) = 7 authorize(req, dataHandler) flatMap { authInfo => 8 service(OAuth2Request(authInfo, req)) 9 } handle { 10 case e: OAuthError => handleError(e) 11 } 12 } 13 14 val authorize = new OAuth2Filter(...) 15 val respond: Service[OAuth2Request[U], HttpResponse] = ??? 16 val backend: Service[HttpRequest, HttpResponse] = authorize andThen respond 21
  22. 22. Future is a monad! 22
  23. 23. Abstraction: Fibonacci Calculator 1 trait FibonacciCalculator { 2 val Zero = BigInt(0) 3 val One = BigInt(1) 4 val Two = BigInt(2) 5 6 def calculate(n: BigInt): Future[BigInt] 7 } 23
  24. 24. Sequential Composition: map & flatMap 1 trait Future[+A] { 2 def flatMap[B](f: A => Future[B]): Future[B] 3 def map[B](f: A => B): Future[B] 4 } 24
  25. 25. FlatMap Power 1 val ab: Service[A, B] = ??? 2 val bc: Service[B, C] = ??? 3 val cd: Service[C, D] = ??? 4 5 val req: A = ??? 6 val rep: Future[D] = ab(req) flatMap bc flatMap cd 25
  26. 26. Sequential Composition: map & flatMap 1 object FlatMapFibonacciCalculator extends FibonacciCalculator { 2 def calculate(n: BigInt): Future[BigInt] = 3 if (n == Zero || n == One) Future.value(n) 4 else calculate(n - One) flatMap { a => 5 calculate(n - Two) flatMap { b => Future.value(a + b) } 6 } 7 } 8 9 object MapFibonacciCalculator extends FibonacciCalculator { 10 def calculate(n: BigInt): Future[BigInt] = 11 if (n == Zero || n == One) Future.value(n) 12 else calculate(n - One) map { a => 13 calculate(n - Two) map { b => a + b } 14 } 15 } 26
  27. 27. Sequential Composition: for-comprehension 1 object ForFibonacciCalculator extends FibonacciCalculator { 2 def calculate(n: BigInt): Future[BigInt] = 3 if (n == Zero || n == One) Future.value(n) 4 else for { 5 a <- calculate(n - One) 6 b <- calculate(n - Two) 7 } yield a + b 8 } 27
  28. 28. Concurrent Composition: collect & select 1 object Future { 2 def collect[A](fs: Seq[Future[A]]): Future[Seq[A]] 3 def select[A](fs: Seq[Future[A]]): Future[A] 4 } 28
  29. 29. Concurrent Composition: collect 1 class FanoutFibonacciCalculator( 2 left: FibonacciCalculator, 3 right: FibonacciCalculator) extends FibonacciCalculator { 4 5 def calculate(n: BigInt): Future[BigInt] = 6 if (n == Zero) || n == One) Future.value(n) 7 else { 8 val seq = Seq(left.calculate(n - One), right.calculate(n - Two)) 9 Future.collect(seq) map { _.sum } 10 } 11 } 29
  30. 30. Concurrent Composition: select 1 class SelectFibonacciCalculator(seq: Seq[FibonacciCalculator]) 2 extends FibonacciCalculator { 3 4 def calculate(n: BigInt): Future[BigInt] = { 5 val futures: Seq[Future[BigInt]] = seq map { _.calculate(n) } 6 Future.select(futures) 7 } 8 } 30
  31. 31. Futures should be chained asynchronously 31
  32. 32. Do Not Await // Asynchronous operation. val f = service(req) // Blocking operation. Await.result(f) 32
  33. 33. Involving Side-Effects // Asynchronous operation. val f = service(req) ! f onSuccess { rep => println("Got the value: " + rep) } onFailure { t => t.printStackTrace() } 33
  34. 34. Finagle is a non-blocking glue for services that implement different protocols 34
  35. 35. Finagle is extremely good at gluing things that work with different speed 35
  36. 36. References § http://twitter.github.io/finagle/ ! § http://vkostyukov.ru/posts/finagle-your-fibonacci-calculation/ ! § https://github.com/finagle/finch ! § https://github.com/finagle/finagle-oauth2 36
  37. 37. Stay Finagled! ! And drop your feedbacks to @vkostyukov 37

×