Scala na soundcloud [QCon]
-
Upload
herval-freire -
Category
Technology
-
view
255 -
download
0
description
Transcript of 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
@herval
Fundador de Startups
Dois Easter Eggs publicados
Padawan Scala
Tem um cachorro
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
Era uma vez uma startup...
Era uma vez uma startup...
Uma base de código
Era uma vez uma startup...
Uma base de códigoUm punhado de construtores
Move fast and break things
Um milhão de featuresBase de código gigante
Quebrando os muros
Muitos vilarejos, muitos idiomas
Muitos vilarejos, muitos idiomas
Microserviços → "tudo é http"Culturas de códigoInfraestruturaMonitoramento"production ready"
Ninguém entende ninguém
Move fast without breaking everything, bitte.
Java
JavaServiços de baseBibliotecas compartilhadasMonitoriaAutenticação/segurança (cross-cutting concerns)
JavaServiços de baseBibliotecas compartilhadasMonitoriaAutenticação/segurança (cross-cutting concerns)
INFRAESTRUTURA BÁSICA
JVM-Kit + Finagle
Estudo de caso
O novo Stream
Reescrever pra quê?
APIMySQL
Cassandra
Reescrever pra quê?
APIMySQL
Cassandra
Reescrever pra quê?
APIMySQL
Cassandra
Reescrever pra quê?80% request queueing
Reescrever pra quê?
Novas featuresLatênciaVazãoMicroserviços
Timeline
API
Timeline
API
Roshi
Timeline
API
Roshi
Autentic.
Autoriz.
Geo loc.
Timeline
API
Roshi
Autentic.
Autoriz.
Geo loc.
Timeline
API
Roshi
Autentic.
Autoriz.
Geo loc.
Playlists
Tracks
Usuários
Timeline
API
Roshi
Autentic.
Autoriz.
Geo loc.
Playlists
Tracks
Usuários
Likes
Coment.
Promoted
Stats
Timeline
API
Roshi
Autentic.
Autoriz.
Geo loc.
Playlists
Tracks
Usuários
Likes
Coment.
Promoted
Stats
...
Timeline
API
Roshi
Autentic.
Autoriz.
Geo loc.
Playlists
Tracks
Usuários
Likes
Coment.
Promoted
Stats
...
BuscarAgregar
BuscarLatência
Timeline
API
Roshi
Autentic.
Autoriz.
Geo loc.
Playlists
Tracks
Usuários
Likes
Coment.
Promoted
Stats
...
AgregarComplexidade
Timeline
API
Roshi
Autentic.
Autoriz.
Geo loc.
Playlists
Tracks
Usuários
Likes
Coment.
Promoted
Stats
...
Scala yay!
Buscar
Paralelizar
Futuros
Futuros
Referência para um valor que será disponibilizado no futuro.
Futuros val response: Future[Int] = …
// Não compila
response + 1
val response: Future[Int] = …
// Adiciona um callback
response.onSuccess { int =>
println(int)
}
Futuros
val response: Future[Int] = …
// Compõe um novo futuro
val count: Future[Int] =
response.map { int =>
int + 1
}
Futuros
for {
user <- authenticate(request)
} yield {
}
Futuros
for {
user <- authenticate(request)
geo <- geoLocationFor(request, user)
} yield {
}
Futuros
for {
user <- authenticate(request)
geo <- geoLocationFor(request, user)
timeline <- timelineFor(user, geo)
} yield {
}
Futuros
for {
user <- authenticate(request)
geo <- geoLocationFor(request, user)
timeline <- timelineFor(user, geo)
resources <-
fetchTracks(timeline)
.join(fetchPlaylists(timeline))
.join(fetchComments(timeline))
} yield {
}
Futuros
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
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
Futuros
+ NIO
Escalabilidade
Máquinas
MáquinasProcessos
MáquinasProcessosThreads
MáquinasProcessosThreadsFuturos
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
Agregar
Funcional
Collections
val timeline: Timeline = …
val timeline: Timeline = …
val actorsToFetch: List[User] =
timeline.items.map(_.actor)
val timeline: Timeline = …
val actorsToFetch: List[User] =
timeline.items.map(_.actor)
val itemsByActor: Map[User, List[Item]] =
timeline.items.groupBy(_.actor)
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)
def createEnrichedTimeline(
timeline: Timeline,
users: Map[User, EnrichedUser]) = {
timeline.items.map { item =>
new EnrichedItem(
item, users.get(item.actor))
}
}
Options
Some(value)None
Option[T]
def findUser(id: Int): Option[User]
// Não compila
render.json(findUser(666).name)
Options
def findUser(id: Int): Option[User]
// Compila
findUser(666).map {
case Some(user) => render.json(user.name)
case None => render.notFound
}
Options
PatternMatching
case class User(name: String, gender: Gender, email: Email)
case class User(name: String, gender: Gender, email: Email)
timelineActors.foreach {
}
case class User(name: String, gender: Gender, email: Email)
timelineActors.foreach {
case User(name, Female, Email(_, “soundcloud.com”) =>
println(“mulher trabalhando na soundcloud”)
}
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 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 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”)
}
Nem tudo são flores...
Código denso
def flatMap[B, That] (f: (A) ⇒ Traversable[B]) (implicit bf: CanBuildFrom[
List[A], B, That]): That
Código denso
def flatMap[B, That] (f: (A) ⇒ Traversable[B]) (implicit bf: CanBuildFrom[
List[A], B, That]): That
listOfThings.flatMap(_.toUpperCase)
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") }
Mas e o Stream...?
Mas e o Stream...?
APIMySQL
Cassandra
Mas e o Stream...?
API
MySQL
RedisTimeline Service
Tracks ServicePlaylists ServiceMultiple Services
Mas e o Stream...?
API
MySQL
RedisTimeline Service
Tracks ServicePlaylists ServiceMultiple Services
~150 ms~0% request queueing
Mas só o Stream...?
Data teamOutros serviços em ScalaFerramental jvmkit
Stranglers
Stranglers
StranglersNovo
streamCache
O presente
Em resumo...
Produtivo como Ruby, typesafe como Java*
Move faster break fewer things
O futuro
Padrões de códigoBibliotecas mais estáveisFacilidade de inovação"One Scala"
O futuro
Perguntas?