11. Futures
a
b
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
12. Futures
a
b
c
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
13. Futures
a
b
c
d
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
14. Futures
a
b
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
15. Futures
16 b
a
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
16. Futures
16 b
a
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
17. Futures
16
a
528
b
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
18. Futures
16
a
528
b
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
19. Futures
16
a
528
b
4
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
20. Futures
16
a
528
b
4
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
21. Futures
16
a
528
b
4
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
22. Futures
16
a
528
b
4
(528,
4)
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
23. Futures
16
a
528
b
4
(528,
4)
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
24. Futures
16
a
528
b 532
4
(528,
4)
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
25. Futures
0 b
a
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
26. Futures
0
a
512
b
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
27. Futures
0
a
512
b
Ex
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
28. Futures
0
a
512
b Ex
Ex
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
29. Futures
0
a
512
b Ex Ex
Ex
c
d e
val a: Future[Int]
val b: Future[Int] = a map { x => x + 512 }
val c = a map { x => 64 / x }
val d = Future.join(b,c)
val e = d map { case (x, y) => x + y }
30. Futures
Lots of combinators:
!
map -> add an edge+node in the graph
flatMap -> combine two graphs together
handle -> deal with exceptions
join -> merge multiple nodes of the graphs
select -> select the first node with a value
!
…more
33. Service
Service is a Function from Request to Response
!
trait Service[Request, Response] {!
def apply(req: Request): Response!
}!
!
Equivalent to Scala’s Function1: Request=>Response
34. Service
But it has to be asynchronous, and treat exception as
value
!
trait Service[Request, Response] {!
def apply(req: Request): Future[Response]!
}!
!
35. Service
It also has to be closable for proper management of
resources.
!
trait Service[Request, Response] {!
def apply(req: Request): Future[Response]!
def close(): Future[Unit]!
}!
41. Connection Pool
class ConnPool[A,B] extends ServiceFactory[…]{
def apply(): Future[Service[A, B]]
}
Connection Dispatcher Transport
Pool
42. Load Balancer
class LoadBalancer[A,B] extends ServiceFactory[…]{
def apply(): Future[Service[A, B]]
}
Connection Dispatcher Transport
Pool
Load
Balancer
43. Finagle in Action
Connection Dispatcher Transport
Pool
Load
Balancer
val req: Request
loadbalancer() // LB select an host
// Pool select a connection
44. Finagle in Action
val req: Request
loadbalancer() flatMap {
service => // LBService(PoolService(disp))
}
Connection Dispatcher Transport
Pool
Load
Balancer
45. Finagle in Action
val req: Request
loadbalancer() flatMap {
service => // LBService(PoolService(disp))
service(req) // disp write req on Transp.
}
Connection Dispatcher Transport
Pool
Load
Balancer
46. Finagle in Action
val req: Request
loadbalancer() flatMap {
service => // LBService(PoolService(disp))
service(req) ensure {
service.close() // close LBService
// close PoolService
}
}
Connection Dispatcher Transport
Pool
Load
Balancer
47. FactoryToService
class FactoryToService[A, B](factory: ServiceFactory[A, B])
extends Service[A, B]
{
def apply(request: A): Future[B] =
factory() flatMap { service =>
service(request) ensure {
service.close()
}
}
}
Connection Dispatcher Transport
Pool
Load
Balancer
FactoryTo
Service
48. Connection Dispatcher Transport
Pool
Load
Balancer
Finagle is “just” a composition of independent
functions on top of a Transport
FactoryTo
Service
49. The “Simplified” Full Picture
Stats
Timeout
Draining
Load Balancer
Monitor
Stats
Failure accrual
Timeout
Conn. Pool
Expiration Dispatcher
ServiceFactory
Service
50. The Stack is configured for you
You rarely have to configured the stack, we have a series
of predefined stack for you.
!
scala> val client: ServiceFactory[Req, Res] = Http.client!
.newClient(“localhost:8080")!
!
51. The Stack is configured for you
You rarely have to configured the stack, we have a series
of predefined stack for you.
!
scala> val client: Service[Req, Res] = Http.client!
.newClient(“localhost:8080")!
.toService!
scala> client(req)!
52. The Stack is configured for you
You rarely have to configured the stack, we have a series
of predefined stack for you.
!
scala> val client: Service[Req, Res] = Http.client!
.configured(DefaultPool.Param(5, 10, 0, 1.minute, 100))!
.newClient(“localhost:8080")!
.toService!
scala> client(req)!
!
You can configure any layer of the Stack
74. Conclusion
• Finagle is a library that lets you treat RPC as functions
• Finagle is itself composed of independent functions
• Very widely used at Twitter, Foursquare, Tumblr,
Pinterest, SoundCloud…
• Protocol agnostic (thrift, http, redis, mysql…)
Github: github.com/twitter/finagle
“Your server as a Function” http://monkey.org/~marius/
funsrv.pdf