Scala na soundcloud [QCon]

95

description

A linguagem Scala tem ganho adoção nos últimos anos como alternativa de alto desempenho para sistemas com milhões de usuários, com casos de sucesso incluindo Twitter, Linkedin e Nokia. Nesta palestra, apresentaremos o caso da SoundCloud, a rede social líder na área de música e áudio. Construída inicialmente como aplicação monolítica Ruby on Rails, a arquitetura do SoundCloud evoluiu organicamente para um modelo de microservices implementados em diversas linguagens de programação, com parte importante desses serviços criada na linguagem Scala. Veremos aqui um pouco dessa jornada, focando nas vantagens e desafios encontrados ao desenvolver microservices, e na nossa experiência ao usar Scala em um ambiente de alta demanda e complexidade.

Transcript of Scala na soundcloud [QCon]

Page 1: Scala na soundcloud [QCon]
Page 2: Scala na soundcloud [QCon]

@flaviowbrasil

Aficionado por open source

Expert em escalabilidade

Mestre Jedi Scala

Prefere uma sessão de profiling a uma tarde na praia

Page 3: Scala na soundcloud [QCon]

@herval

Fundador de Startups

Dois Easter Eggs publicados

Padawan Scala

Tem um cachorro

Page 4: Scala na soundcloud [QCon]

A Nuvem de Som

12 horas de novo conteúdo/ minuto350 milhões de usuários/mês12 milhões de horas ouvidas/mês1 usuário no espaço

Page 5: Scala na soundcloud [QCon]

Era uma vez uma startup...

Page 6: Scala na soundcloud [QCon]

Era uma vez uma startup...

Uma base de código

Page 7: Scala na soundcloud [QCon]

Era uma vez uma startup...

Uma base de códigoUm punhado de construtores

Page 8: Scala na soundcloud [QCon]

Move fast and break things

Page 9: Scala na soundcloud [QCon]

Um milhão de featuresBase de código gigante

Page 10: Scala na soundcloud [QCon]

Quebrando os muros

Page 11: Scala na soundcloud [QCon]

Muitos vilarejos, muitos idiomas

Page 12: Scala na soundcloud [QCon]

Muitos vilarejos, muitos idiomas

Microserviços → "tudo é http"Culturas de códigoInfraestruturaMonitoramento"production ready"

Page 13: Scala na soundcloud [QCon]

Ninguém entende ninguém

Page 14: Scala na soundcloud [QCon]

Move fast without breaking everything, bitte.

Page 15: Scala na soundcloud [QCon]

Java

Page 16: Scala na soundcloud [QCon]

JavaServiços de baseBibliotecas compartilhadasMonitoriaAutenticação/segurança (cross-cutting concerns)

Page 17: Scala na soundcloud [QCon]

JavaServiços de baseBibliotecas compartilhadasMonitoriaAutenticação/segurança (cross-cutting concerns)

INFRAESTRUTURA BÁSICA

Page 18: Scala na soundcloud [QCon]
Page 19: Scala na soundcloud [QCon]

JVM-Kit + Finagle

Page 20: Scala na soundcloud [QCon]

Estudo de caso

O novo Stream

Page 21: Scala na soundcloud [QCon]
Page 22: Scala na soundcloud [QCon]

Reescrever pra quê?

Page 23: Scala na soundcloud [QCon]

APIMySQL

Cassandra

Reescrever pra quê?

Page 24: Scala na soundcloud [QCon]

APIMySQL

Cassandra

Reescrever pra quê?

Page 25: Scala na soundcloud [QCon]

APIMySQL

Cassandra

Reescrever pra quê?80% request queueing

Page 26: Scala na soundcloud [QCon]

Reescrever pra quê?

Novas featuresLatênciaVazãoMicroserviços

Page 27: Scala na soundcloud [QCon]

Timeline

API

Page 28: Scala na soundcloud [QCon]

Timeline

API

Roshi

Page 29: Scala na soundcloud [QCon]

Timeline

API

Roshi

Autentic.

Autoriz.

Geo loc.

Page 30: Scala na soundcloud [QCon]

Timeline

API

Roshi

Autentic.

Autoriz.

Geo loc.

Page 31: Scala na soundcloud [QCon]

Timeline

API

Roshi

Autentic.

Autoriz.

Geo loc.

Playlists

Tracks

Usuários

Page 32: Scala na soundcloud [QCon]

Timeline

API

Roshi

Autentic.

Autoriz.

Geo loc.

Playlists

Tracks

Usuários

Likes

Coment.

Promoted

Stats

Page 33: Scala na soundcloud [QCon]

Timeline

API

Roshi

Autentic.

Autoriz.

Geo loc.

Playlists

Tracks

Usuários

Likes

Coment.

Promoted

Stats

...

Page 34: Scala na soundcloud [QCon]

Timeline

API

Roshi

Autentic.

Autoriz.

Geo loc.

Playlists

Tracks

Usuários

Likes

Coment.

Promoted

Stats

...

BuscarAgregar

Page 35: Scala na soundcloud [QCon]

BuscarLatência

Page 36: Scala na soundcloud [QCon]

Timeline

API

Roshi

Autentic.

Autoriz.

Geo loc.

Playlists

Tracks

Usuários

Likes

Coment.

Promoted

Stats

...

Page 37: Scala na soundcloud [QCon]

AgregarComplexidade

Page 38: Scala na soundcloud [QCon]

Timeline

API

Roshi

Autentic.

Autoriz.

Geo loc.

Playlists

Tracks

Usuários

Likes

Coment.

Promoted

Stats

...

Page 39: Scala na soundcloud [QCon]

Scala yay!

Page 40: Scala na soundcloud [QCon]

Buscar

Paralelizar

Page 41: Scala na soundcloud [QCon]
Page 42: Scala na soundcloud [QCon]

Futuros

Page 43: Scala na soundcloud [QCon]

Futuros

Referência para um valor que será disponibilizado no futuro.

Page 44: Scala na soundcloud [QCon]

Futuros val response: Future[Int] = …

// Não compila

response + 1

Page 45: Scala na soundcloud [QCon]

val response: Future[Int] = …

// Adiciona um callback

response.onSuccess { int =>

println(int)

}

Futuros

Page 46: Scala na soundcloud [QCon]

val response: Future[Int] = …

// Compõe um novo futuro

val count: Future[Int] =

response.map { int =>

int + 1

}

Futuros

Page 47: Scala na soundcloud [QCon]

for {

user <- authenticate(request)

} yield {

}

Futuros

Page 48: Scala na soundcloud [QCon]

for {

user <- authenticate(request)

geo <- geoLocationFor(request, user)

} yield {

}

Futuros

Page 49: Scala na soundcloud [QCon]

for {

user <- authenticate(request)

geo <- geoLocationFor(request, user)

timeline <- timelineFor(user, geo)

} yield {

}

Futuros

Page 50: Scala na soundcloud [QCon]

for {

user <- authenticate(request)

geo <- geoLocationFor(request, user)

timeline <- timelineFor(user, geo)

resources <-

fetchTracks(timeline)

.join(fetchPlaylists(timeline))

.join(fetchComments(timeline))

} yield {

}

Futuros

Page 51: Scala na soundcloud [QCon]

for {

user <- authenticate(request)

geo <- geoLocationFor(request, user)

timeline <- timelineFor(user, geo)

resources <-

fetchTracks(timeline)

.join(fetchPlaylists(timeline))

.join(fetchComments(timeline))

} yield {

new EnrichedTimeline(timeline, resources)

}

Futuros

Page 52: Scala na soundcloud [QCon]

def handle(request: Request): Future[EnrichedTimeline] =

for {

user <- authenticate(request)

geo <- geoLocationFor(request, user)

timeline <- timelineFor(user, geo)

resources <-

fetchTracks(timeline)

.join(fetchPlaylists(timeline))

.join(fetchComments(timeline))

} yield {

new EnrichedTimeline(timeline, resources)

}

Futuros

Page 53: Scala na soundcloud [QCon]

Futuros

+ NIO

Escalabilidade

Page 54: Scala na soundcloud [QCon]

Máquinas

Page 55: Scala na soundcloud [QCon]

MáquinasProcessos

Page 56: Scala na soundcloud [QCon]

MáquinasProcessosThreads

Page 57: Scala na soundcloud [QCon]

MáquinasProcessosThreadsFuturos

Page 58: Scala na soundcloud [QCon]

def handle(request: Request): Future[EnrichedTimeline] =

for {

user <- authenticate(request)

geo <- geoLocationFor(request, user)

timeline <- timelineFor(user, geo)

resources <-

fetchTracks(timeline)

.join(fetchPlaylists(timeline))

.join(fetchComments(timeline))

} yield {

new EnrichedTimeline(timeline, resources)

}

Futuros

Page 59: Scala na soundcloud [QCon]

Agregar

Funcional

Page 60: Scala na soundcloud [QCon]

Collections

Page 61: Scala na soundcloud [QCon]

val timeline: Timeline = …

Page 62: Scala na soundcloud [QCon]

val timeline: Timeline = …

val actorsToFetch: List[User] =

timeline.items.map(_.actor)

Page 63: Scala na soundcloud [QCon]

val timeline: Timeline = …

val actorsToFetch: List[User] =

timeline.items.map(_.actor)

val itemsByActor: Map[User, List[Item]] =

timeline.items.groupBy(_.actor)

Page 64: Scala na soundcloud [QCon]

val timeline: Timeline = …

val actorsToFetch: List[User] =

timeline.items.map(_.actor)

val itemsByActor: Map[User, List[Item]] =

timeline.items.groupBy(_.actor)

val numberOfItemsByActor: Map[User, Int] =

itemsByActor.mapValues(_.size)

Page 65: Scala na soundcloud [QCon]

def createEnrichedTimeline(

timeline: Timeline,

users: Map[User, EnrichedUser]) = {

timeline.items.map { item =>

new EnrichedItem(

item, users.get(item.actor))

}

}

Page 66: Scala na soundcloud [QCon]

Options

Page 67: Scala na soundcloud [QCon]

Some(value)None

Option[T]

Page 68: Scala na soundcloud [QCon]

def findUser(id: Int): Option[User]

// Não compila

render.json(findUser(666).name)

Options

Page 69: Scala na soundcloud [QCon]

def findUser(id: Int): Option[User]

// Compila

findUser(666).map {

case Some(user) => render.json(user.name)

case None => render.notFound

}

Options

Page 70: Scala na soundcloud [QCon]

PatternMatching

Page 71: Scala na soundcloud [QCon]

case class User(name: String, gender: Gender, email: Email)

Page 72: Scala na soundcloud [QCon]

case class User(name: String, gender: Gender, email: Email)

timelineActors.foreach {

}

Page 73: Scala na soundcloud [QCon]

case class User(name: String, gender: Gender, email: Email)

timelineActors.foreach {

case User(name, Female, Email(_, “soundcloud.com”) =>

println(“mulher trabalhando na soundcloud”)

}

Page 74: Scala na soundcloud [QCon]

case class User(name: String, gender: Gender, email: Email)

timelineActors.foreach {

case User(name, Female, Email(_, “soundcloud.com”) =>

println(“mulher trabalhando na soundcloud”)

case User(name, Male, Email(_, “soundcloud.com”) =>

println(“homem trabalhando na soundcloud”)

}

Page 75: Scala na soundcloud [QCon]

case class User(name: String, gender: Gender, email: Email)

timelineActors.foreach {

case User(name, Female, Email(_, “soundcloud.com”) =>

println(“mulher trabalhando na soundcloud”)

case User(name, Male, Email(_, “soundcloud.com”) =>

println(“homem trabalhando na soundcloud”)

case User(name, gender, Email(_, “qconrio.com.br”) =>

println(“organizador da qconrio”)

}

Page 76: Scala na soundcloud [QCon]

case class User(name: String, gender: Gender, email: Email)

timelineActors.foreach {

case User(name, Female, Email(_, “soundcloud.com”) =>

println(“mulher trabalhando na soundcloud”)

case User(name, Male, Email(_, “soundcloud.com”) =>

println(“homem trabalhando na soundcloud”)

case User(name, gender, Email(_, “qconrio.com.br”) =>

println(“organizador da qconrio”)

case _ =>

println(“pessoa desconhecida”)

}

Page 77: Scala na soundcloud [QCon]

Nem tudo são flores...

Page 78: Scala na soundcloud [QCon]
Page 79: Scala na soundcloud [QCon]

Código denso

def flatMap[B, That] (f: (A) ⇒ Traversable[B]) (implicit bf: CanBuildFrom[

List[A], B, That]): That

Page 80: Scala na soundcloud [QCon]

Código denso

def flatMap[B, That] (f: (A) ⇒ Traversable[B]) (implicit bf: CanBuildFrom[

List[A], B, That]): That

listOfThings.flatMap(_.toUpperCase)

Page 81: Scala na soundcloud [QCon]

XML também é código?

<fruits> <fruit type="banana" origin="brazil"/> <fruit type="apple"/> <fruit type="orange" origin="usa"/> <fruit type="orange" origin="brazil"/></fruits> \\ "fruit"

filter { _ \\ "@origin" exists (_.text == "brazil") }

Page 82: Scala na soundcloud [QCon]
Page 83: Scala na soundcloud [QCon]

Mas e o Stream...?

Page 84: Scala na soundcloud [QCon]

Mas e o Stream...?

APIMySQL

Cassandra

Page 85: Scala na soundcloud [QCon]

Mas e o Stream...?

API

MySQL

RedisTimeline Service

Tracks ServicePlaylists ServiceMultiple Services

Page 86: Scala na soundcloud [QCon]

Mas e o Stream...?

API

MySQL

RedisTimeline Service

Tracks ServicePlaylists ServiceMultiple Services

~150 ms~0% request queueing

Page 87: Scala na soundcloud [QCon]

Mas só o Stream...?

Data teamOutros serviços em ScalaFerramental jvmkit

Page 88: Scala na soundcloud [QCon]

Stranglers

Page 89: Scala na soundcloud [QCon]

Stranglers

Page 90: Scala na soundcloud [QCon]

StranglersNovo

streamCache

Page 91: Scala na soundcloud [QCon]

O presente

Page 92: Scala na soundcloud [QCon]

Em resumo...

Produtivo como Ruby, typesafe como Java*

Move faster break fewer things

Page 93: Scala na soundcloud [QCon]

O futuro

Page 94: Scala na soundcloud [QCon]

Padrões de códigoBibliotecas mais estáveisFacilidade de inovação"One Scala"

O futuro

Page 95: Scala na soundcloud [QCon]

Perguntas?