julio capote, twitter

125
Distributing Systems in Scala with Finagle Julio Capote

Upload: ontico

Post on 26-Jun-2015

1.138 views

Category:

Technology


1 download

DESCRIPTION

HighLoad++ 2013

TRANSCRIPT

Page 1: Julio Capote, Twitter

Distributing Systems in Scala

with Finagle Julio Capote

Page 2: Julio Capote, Twitter

About me

• Julio Capote

• API team at Twitter

• @capotej

Page 3: Julio Capote, Twitter

This talk

• Services

• Scala

• Finagle

• Examples

Page 4: Julio Capote, Twitter

Scaling

Page 5: Julio Capote, Twitter
Page 6: Julio Capote, Twitter
Page 7: Julio Capote, Twitter
Page 8: Julio Capote, Twitter
Page 9: Julio Capote, Twitter
Page 10: Julio Capote, Twitter

Monolithic System

• Limited to a single language and runtime

• Can only support few developers

• Deploys get more dangerous

Page 11: Julio Capote, Twitter

Solution?

Page 12: Julio Capote, Twitter
Page 13: Julio Capote, Twitter
Page 14: Julio Capote, Twitter

Distributed System

• Each service written in appropriate language

• Can only support many developers

• Granular deploys

Page 15: Julio Capote, Twitter

But, this is complex...

Page 16: Julio Capote, Twitter
Page 17: Julio Capote, Twitter
Page 18: Julio Capote, Twitter
Page 19: Julio Capote, Twitter

Quick Scala Intro

Page 20: Julio Capote, Twitter

What is Scala?

• JVM language

• Interoperable with Java

• Functional

• But Object Oriented too

Page 21: Julio Capote, Twitter

Values

Page 22: Julio Capote, Twitter

val foo: String = "bar"

Page 23: Julio Capote, Twitter

val age: Int = 27

Page 24: Julio Capote, Twitter

Type inference

Page 25: Julio Capote, Twitter

val foo = "bar"

Page 26: Julio Capote, Twitter

val foo: String = "bar"

Page 27: Julio Capote, Twitter

Collections

Page 28: Julio Capote, Twitter

List(61,31,34)

Page 29: Julio Capote, Twitter

Seq(1,2,3)

Page 30: Julio Capote, Twitter

Dictionaries / Hashes

Page 31: Julio Capote, Twitter

Map("foo" -> "bar")

Page 32: Julio Capote, Twitter

Functional

Page 33: Julio Capote, Twitter

val addOne =

{ x: Int => x + 1 }

Page 34: Julio Capote, Twitter

addOne.apply(2) => 3

Page 35: Julio Capote, Twitter

addOne(2) => 3

Page 36: Julio Capote, Twitter

val list = Seq(1,2,3,4)

Page 37: Julio Capote, Twitter

list.map { x => addOne(x) }

Page 38: Julio Capote, Twitter

list.map(addOne(_))

Page 39: Julio Capote, Twitter

list.map(addOne)

Page 40: Julio Capote, Twitter

list map(addOne)

Page 41: Julio Capote, Twitter

list map addOne

Page 42: Julio Capote, Twitter

list map addOne filter

{ item: Int =>

item % 2 == 0 }

Page 43: Julio Capote, Twitter

Function Composition

Page 44: Julio Capote, Twitter

val addOne =

{ x: Int => x + 1 }

val addTwo =

{ x: Int => x + 2 }

val addThree =

addOne compose addTwo

Page 45: Julio Capote, Twitter

val addOne =

{ x: Int => x + 1 }

val addTwo =

{ x: Int => x + 2 }

val addThree =

addOne compose addTwo

Page 46: Julio Capote, Twitter

addThree(2) => 5

Page 47: Julio Capote, Twitter

Object oriented

Page 48: Julio Capote, Twitter

class Dog extends Animal

def bark = {

println("woof")

}

}

Page 49: Julio Capote, Twitter

Options

Page 50: Julio Capote, Twitter
Page 51: Julio Capote, Twitter

Map("foo" -> "bar").get("foo")

Page 52: Julio Capote, Twitter

Some(bar)

Page 53: Julio Capote, Twitter

Map("foo" -> "bar").get("zzz")

Page 54: Julio Capote, Twitter

None

Page 55: Julio Capote, Twitter

val a = Map("foo" -> "bar")

val opt = a.get("zzz")

val result =

opt.getOrElse("default")

Page 56: Julio Capote, Twitter

val a = Map("foo" -> "bar")

val opt = a.get("zzz")

val result = opt match {

case Some(x) => x

case None => "default"

}

Page 57: Julio Capote, Twitter

val a = Map("foo" -> "bar")

val opt = a.get("zzz")

opt foreach { result =>

println(result)

}

Page 58: Julio Capote, Twitter

Finagle

Page 59: Julio Capote, Twitter

What is Finagle?

• Client/Server RPC Framework

• Asynchronous

• Functional

• Protocol Agnostic

Page 60: Julio Capote, Twitter

Futures

Page 61: Julio Capote, Twitter
Page 62: Julio Capote, Twitter
Page 63: Julio Capote, Twitter
Page 64: Julio Capote, Twitter
Page 65: Julio Capote, Twitter

def fetchUrl(url: String) = Future[Response]

Page 66: Julio Capote, Twitter

val f: Future[Response] =

fetchUrl("google.ru")

f map { response =>

println(response.content)

}

Page 67: Julio Capote, Twitter

val f: Future[Response] =

fetchUrl("google.ru")

f onSuccess { response =>

println(response.content)

} onFailure {

case e => log.error(e)

}

Page 68: Julio Capote, Twitter

val f: Future[Response] =

fetchUrl("google.ru")

f onSuccess { response =>

println(response.content)

} onFailure {

case e => log.error(e)

}

Page 69: Julio Capote, Twitter

Services

Page 70: Julio Capote, Twitter

“Your Server as a Function”

Page 71: Julio Capote, Twitter

type Service[Req, Rep] = Req => Future[Rep]

Page 72: Julio Capote, Twitter

Request => Future[Response]

Page 73: Julio Capote, Twitter
Page 74: Julio Capote, Twitter

Http Client

Page 75: Julio Capote, Twitter

val client: Service[Request, Response] =

Http.newService("www.google.ru:80")

Page 76: Julio Capote, Twitter

Making a request

Page 77: Julio Capote, Twitter

val req = Request("/")

client(req) onSuccess { resp =>

println(resp.content)

}

Page 78: Julio Capote, Twitter

val req = Request("/")

client.apply(req) onSuccess { resp =>

println(resp.content)

}

Page 79: Julio Capote, Twitter

val req = Request("/")

val resp = client(req)

resp onSuccess { resp =>

println(resp.content)

}

Await.ready(resp)

Page 80: Julio Capote, Twitter

val req = Request("/")

val resp = client(req)

resp onSuccess { resp =>

println(resp.content)

}

Await.ready(resp)

Page 81: Julio Capote, Twitter

Http Server

Page 82: Julio Capote, Twitter

class MyServer

extends Service[Request, Response] {

def apply(request: Request) = {

Future.value(new Response("hi"))

}

}

Page 83: Julio Capote, Twitter

class MyServer

extends Service[Request, Response] {

def apply(request: Request) = {

Future.value(new Response("hi"))

}

}

Page 84: Julio Capote, Twitter

Request => Future[Response]

Page 85: Julio Capote, Twitter

Starting the server

Page 86: Julio Capote, Twitter

val service = new MyServer

val server = Http.serve(":8080", service)

Await.ready(server)

Page 87: Julio Capote, Twitter

Http Proxy

Page 88: Julio Capote, Twitter

object Proxy extends App {

val client: Service[Request, Response] =

Http.newService("www.google.ru:80")

val server = Http.serve(":8080", client)

Await.ready(server)

}

Page 89: Julio Capote, Twitter

object Proxy extends App {

val client: Service[Request, Response] =

Http.newService("www.google.ru:80")

val server = Http.serve(":8080", client)

Await.ready(server)

}

Page 90: Julio Capote, Twitter

object Proxy extends App {

val client: Service[Request, Response] =

Http.newService("www.google.ru:80")

val server = Http.serve(":8080", client)

Await.ready(server)

}

Page 91: Julio Capote, Twitter

Filters

Page 92: Julio Capote, Twitter
Page 93: Julio Capote, Twitter

Filter[InRequest,

InResponse,

OutRequest,

OutResponse]

Page 94: Julio Capote, Twitter

Filter[InRequest,

InResponse,

OutRequest,

OutResponse]

Page 95: Julio Capote, Twitter

Filter[InRequest,

InResponse,

OutRequest,

OutResponse]

Page 96: Julio Capote, Twitter

SimpleFilter[Request, Response]

Page 97: Julio Capote, Twitter

def apply(request: Req,

service: Service[Req, Rep]): Future[Rep]

Page 98: Julio Capote, Twitter

def apply(request: Req,

service: Service[Req, Rep]): Future[Rep]

Page 99: Julio Capote, Twitter

def apply(request: Req,

service: Service[Req, Rep]): Future[Rep]

Page 100: Julio Capote, Twitter

def apply(request: Req,

service: Service[Req, Rep]): Future[Rep]

Page 101: Julio Capote, Twitter

class ScreamFilter[Req, Rep]

extends SimpleFilter[Req, Rep]

def apply(request: Req,

service: Service[Req, Rep]) = {

service(request) onSuccess { response =>

response.setContent(response.content + "!")

response

}

}

}

Page 102: Julio Capote, Twitter

class ScreamFilter[Req, Rep]

extends SimpleFilter[Req, Rep]

def apply(request: Req,

service: Service[Req, Rep]) = {

service(request) onSuccess { response =>

response.setContent(response.content + "!")

response

}

}

}

Page 103: Julio Capote, Twitter

class ScreamFilter[Req, Rep]

extends SimpleFilter[Req, Rep]

def apply(request: Req,

service: Service[Req, Rep]) = {

service(request) onSuccess { response =>

response.setContent(response.content + "!")

response

}

}

}

Page 104: Julio Capote, Twitter

class ScreamFilter[Req, Rep]

extends SimpleFilter[Req, Rep]

def apply(request: Req,

service: Service[Req, Rep]) = {

service(request) onSuccess { response =>

response.setContent(response.content + "!")

response

}

}

}

Page 105: Julio Capote, Twitter

class ScreamFilter[Req, Rep]

extends SimpleFilter[Req, Rep]

def apply(request: Req,

service: Service[Req, Rep]) = {

service(request) onSuccess { response =>

response.setContent(response.content + "!")

response

}

}

}

Page 106: Julio Capote, Twitter

class ScreamFilter[Req, Rep]

extends SimpleFilter[Req, Rep]

def apply(request: Req,

service: Service[Req, Rep]) = {

service(request) onSuccess { response =>

response.setContent(response.content + "!")

response }

}

}

Page 107: Julio Capote, Twitter

val service = new MyServer

val server = Http.serve(":8080", service)

Await.ready(server)

Page 108: Julio Capote, Twitter

val service = new MyServer

val myFilter = new MyFilter

val newService = myFilter andThen service

val server = Http.serve(":8080", newService)

Await.ready(server)

Page 109: Julio Capote, Twitter

val service = new MyServer

val myFilter = new MyFilter

val newService = myFilter andThen service

val server = Http.serve(":8080", newService)

Await.ready(server)

Page 110: Julio Capote, Twitter

val service = new MyServer

val myFilter = new MyFilter

val newService = myFilter andThen service

val server = Http.serve(":8080", newService)

Await.ready(server)

Page 111: Julio Capote, Twitter

Metrics

Page 112: Julio Capote, Twitter
Page 113: Julio Capote, Twitter

curl http://localhost:9990/admin/metrics.json

Page 114: Julio Capote, Twitter
Page 115: Julio Capote, Twitter

Add your own

Page 116: Julio Capote, Twitter

class MyServer(stats: StatsReceiver)

extends Service[Request, Response] {

def apply(request: Request) = {

stats.counter("my counter").incr()

stats.time("fetch") {

expensiveOperation()

}

Future.value(new Response("hi"))

}

}

Page 117: Julio Capote, Twitter

class MyServer(stats: StatsReceiver)

extends Service[Request, Response] {

def apply(request: Request) = {

stats.counter("my counter").incr()

stats.time("fetch") {

expensiveOperation()

}

Future.value(new Response("hi"))

}

}

Page 118: Julio Capote, Twitter

class MyServer(stats: StatsReceiver)

extends Service[Request, Response] {

def apply(request: Request) = {

stats.counter("my counter").incr()

stats.time("fetch") {

expensiveOperation()

}

Future.value(new Response("hi"))

}

}

Page 119: Julio Capote, Twitter

Finatra

Page 120: Julio Capote, Twitter

Finagle with Sinatra

Page 121: Julio Capote, Twitter

class Example extends Controller {

get("/") { request =>

render.plain("hi").toFuture

}

}

Page 122: Julio Capote, Twitter

class Example extends Controller {

get("/") { request =>

render.plain("hi").toFuture

}

}

Page 123: Julio Capote, Twitter

class MyServer extends FinatraServer {

val controller = new Example()

register(controller)

}

Page 124: Julio Capote, Twitter

http://finatra.info