Scala, Akka, Play
The why and how of reactive web-applications on the JVM
Lambda Days 2015
Manuel Bernhardt - @elmanu
Agenda
1. The Why
2. The How
Who is speaking?
• freelance software consultant based
in Vienna
• Vienna Scala User Group
• web, web, web
Who is speaking?
• freelance software consultant based
in Vienna
• Vienna Scala User Group
• web, web, web
• writing a book on reactive web-
applications
http://www.manning.com/
bernhardt
The Why
The Why
The Whys
1st
Why: it's 2015, the
year of...
2015!
Flying cars?
Hoverboards?
Self-lacing shoes?
2015: many-core
CPUs
• End of the single-core multi-core era
• Many players in the space
• Tilera, Cavium
• Adapteva Parallela
• Xeon PHI
• It's happening!
Too many cores?
• 1981 "640 kb ought to be enough
for anybody" ~ Bill Gates
Too many cores?
• 1981 "640 kb ought to be enough
for anybody" ~ Bill Gates
• 2014 "4 cores ought to be enough
for anybody" ~ Linus Torvalds1
1
http://highscalability.com/blog/2014/12/31/linus-the-whole-parallel-
computing-is-the-future-is-a-bunch.html
2nd
Why: distribution
is the norm, not the
exception
It's all in the cloud
• divide & conquer: specialized
services that do one thing well
• storage: S3
• emails: MailChimp
• monitoring: New Relic, Plumbr
• etc. etc. etc.
This is not the
cloud
That's more like the
cloud
• scaling out to handle large loads
• scaling out / replication to handle
node failure
Yes! That's the
cloud!
• networks, networks, networks
• they fail all the time
• Jepsen series3
3
http://aphyr.com
The cloud is hard
• CAP theorem
• 8 fallacies of distributed computing
• hard problem, no easy solution
• PAXOS, CQRS, CRDTs
3rd
Why: Winter is
coming
Side note: Internet of Lost Things
Prediction: "By 2020, everyone will have a bunch of online
things lost in their appartment"
4th
Why: Houston, we
have a problem
Our traditional programming
tools don't work in this setting
We have been
brainwashed to
use:
1. imperative programming with
mutable state
2. locks, locks, locks
The problem with mutable state
car.setPosition(0);
car.setPosition(10);
The problem with mutable state
The problem with
locks
• solution workaround for a broken
conceptual model
• hard to reason about
• performance hit
The problem with
object-orientation
in Java
• there is no notion of time, only an
illusion thereof
• changes to a mutable model only
make sense locally if nobody is
watching
• the larger the scope, the harder it
gets to prevent inconsistencies
The Whys
1. many-core CPUs are here
2. everything is distributed
3. IoT around the corner with 26 billions devices
4. our traditional approach does not work here
The How
The How
The Hows
In theory
• Functional Programming
• The Actor Model
• Evented Server Model
• Stateless architecture
• Event Sourcing
• Reactive Streams
In practice
• Functional Programming Scala
• The Actor Model Akka
• Evented Server Model Play
• Stateless architecture Play
• Event Sourcing Akka Persistence
• Reactive Streams Akka Streams
1st
How: Functional
Programming Scala
Short Scala history
• Martin Odersky, EPFL
• first release in 2003
• Typesafe Inc.
Design goals
• Full interoperability with Java
• Cut down boilerplate
• Pure object orientation & functional programming
• Move away from null
• Many-core programming
Core concepts of Functional
Programming
• immutability
• functions
• transforming data with functions
Immutability
case class Car(brand: String, position: Int)
val car = Car(brand = "DeLorean", position = 0)
val movedCar = car.copy(position = 10)
val movedCarLaterOn = car.copy(position = 30)
Immutability
case class Car(brand: String, position: Int)
val car = Car(brand = "DeLorean", position = 0)
val movedCar = car.copy(position = 10)
val movedCarLaterOn = car.copy(position = 30)
Work with snapshots of
state
Higher-order
functions
val (minors, majors) =
users.partition(_.age < 18)
Higher-order
functions
val isMinor =
(age: Int) => age < 18
val (minors, majors) =
users.partition(isMinor)
Higher-order
functions
val isMinor =
(age: Int) => age < 18
val (minors, majors) =
users.partition(isMinor)
Moving behaviour around instead
of moving data around
Transforming data
val addresses = users.filter(_.age > 18)
.map(_.address)
.sortBy(_.city)
Goal: To build increasingly complex behaviour through
a series of transformations / by composing functions
Composition
def fetchUser(id: Long): Option[User] = ...
def fetchCar(id: Long): Option[Car] = ...
val insuranceCost: Option[BigDecimal] = for {
user <- fetchUser(42)
car <- fetchCar(23)
} yield {
car.price / 10 - user.age
}
Composition
def fetchUser(id: Long): Future[User] = ...
def fetchCar(id: Long): Future[Car] = ...
val insuranceCost: Future[BigDecimal] = for {
user <- fetchUser(42)
car <- fetchCar(23)
} yield {
car.price / 10 - user.age
}
Composition
def fetchUser(id: Long): Try[User] = ...
def fetchCar(id: Long): Try[Car] = ...
val insuranceCost: Try[BigDecimal] = for {
user <- fetchUser(42)
car <- fetchCar(23)
} yield {
car.price / 10 - user.age
}
Composition
def fetchUser(id: Long): [User] = ...
def fetchCar(id: Long): [Car] = ...
val insuranceCost: [BigDecimal] = for {
user <- (42)
car <- (23)
} yield {
car.price / 10 - user.age
}
Composition!
Option
Future
Try
...
Functional
composition
• Option, Future, Try all implement
monadic operations
• set of data structures following the
same laws
• know one, know them all
• keeping things DRY
• also, it's not that scary
2nd
how: Actor model
Akka
History
• 1973 "A Universal Modular Actor
Formalism for Artificial Intelligence",
Carl Hewitt, Peter Bishop and
Richard Steiger
• based on physics (quantum
physics and relativistic physics)
• 1986 First release of Erlang (Joe
Armstrong)
• 1998 Ericsson reports that the
AXD301 switch achieves an
availability of 99.9999999%
History
• 2010 First release of Akka (Jonas
Bonér)
• inspired by Erlang and the Actor
Model
• message-based asynchronous
concurrency toolkit
• object-oriented programming
done right
History
• 2010 First release of Akka (Jonas
Bonér)
• inspired by Erlang and the Actor
Model
• message-based asynchronous
concurrency toolkit
• object-oriented programming
done right
• Akka is also a mountain in Sweden
Actors
• lightweight objects
• send and receive messages (mailbox)
• can have children (supervision)
Sending and receiving messages
case object RevelationOfFathership
class Luke extends Actor {
def receive = {
case RevelationOfFathership =>
System.err.println("Noooooooooo")
}
}
Sending and receiving messages
case object RevelationOfFathership
class Luke extends Actor {
def receive = {
case RevelationOfFathership =>
System.err.println("Noooooooooo")
}
}
val luke = ActorSystem.actorOf(Props[Luke])
luke ! RevelationOfFathership
Supervision
class Vader extends Actor {
val troopers: ActorRef = context
.actorOf[StromTrooper]
.withRouter(
RoundRobinRouter(nrOfInstances = 8)
)
}
Supervision
class Vader extends Actor {
val troopers: ActorRef = context
.actorOf[StromTrooper]
.withRouter(
RoundRobinRouter(nrOfInstances = 8)
)
}
Supervision
class Vader extends Actor {
val troopers: ActorRef = context
.actorOf[StromTrooper]
.withRouter(
RoundRobinRouter(nrOfInstances = 8)
)
override def supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 3) {
case t: Throwable =>
log.error("StormTrooper down!",
t)
Restart
}
}
3rd
How: Evented
servers & statless
architecture Play
Play history
• MVC framework, inspired by RoR,
Django, Symfony
• Zenexity
• first version released in 2009
• version 2.0 released in 2012, core
rewritten in Scala
Design Principles
• everything is compiled
• non-blocking I/O
• controller actions are functions (request => response)
• "share nothing" => horizontal scalability
Threaded servers
• like a train station with multiple
tracks
• station chief decides which trains go
on which platform
• if there are more trains than
platforms, trains queue up
• if too many trains are queuing up,
huge delays occur and passengers
go home
Evented servers
• like a waiter in a restaurant
• runs back and forth between tables
and the kitchen
• does only small tasks that do not
take much time
• one server can each serve many
tables at once
Advantages of the evented
approach
• less threads means less memory
• better CPU utilization (reduced context switching)
• (much) higher throughputs than threaded servers
The Hows
1. functional programming (immutability, functions,
composition)
2. actor model
3. evented servers & stateless architecture
4. event-sourcing & reactive streams
Summary
• many-core & distributed systems
around the corner and there to stay
• get ready and adopt some of the
"new" tools
Thank you
http://www.manning.com/bernhardt
code ctwlambdad 41% discount
@elmanu / manuel@bernhardt.io
Questions?

Reactive Web-Applications @ LambdaDays

  • 1.
    Scala, Akka, Play Thewhy and how of reactive web-applications on the JVM Lambda Days 2015 Manuel Bernhardt - @elmanu
  • 2.
  • 3.
    Who is speaking? •freelance software consultant based in Vienna • Vienna Scala User Group • web, web, web
  • 4.
    Who is speaking? •freelance software consultant based in Vienna • Vienna Scala User Group • web, web, web • writing a book on reactive web- applications http://www.manning.com/ bernhardt
  • 5.
  • 6.
  • 7.
    1st Why: it's 2015,the year of...
  • 8.
  • 9.
    2015: many-core CPUs • Endof the single-core multi-core era • Many players in the space • Tilera, Cavium • Adapteva Parallela • Xeon PHI • It's happening!
  • 10.
    Too many cores? •1981 "640 kb ought to be enough for anybody" ~ Bill Gates
  • 11.
    Too many cores? •1981 "640 kb ought to be enough for anybody" ~ Bill Gates • 2014 "4 cores ought to be enough for anybody" ~ Linus Torvalds1 1 http://highscalability.com/blog/2014/12/31/linus-the-whole-parallel- computing-is-the-future-is-a-bunch.html
  • 12.
    2nd Why: distribution is thenorm, not the exception
  • 13.
    It's all inthe cloud • divide & conquer: specialized services that do one thing well • storage: S3 • emails: MailChimp • monitoring: New Relic, Plumbr • etc. etc. etc.
  • 15.
    This is notthe cloud
  • 16.
    That's more likethe cloud • scaling out to handle large loads • scaling out / replication to handle node failure
  • 17.
    Yes! That's the cloud! •networks, networks, networks • they fail all the time • Jepsen series3 3 http://aphyr.com
  • 18.
    The cloud ishard • CAP theorem • 8 fallacies of distributed computing • hard problem, no easy solution • PAXOS, CQRS, CRDTs
  • 19.
  • 21.
    Side note: Internetof Lost Things Prediction: "By 2020, everyone will have a bunch of online things lost in their appartment"
  • 22.
  • 23.
    Our traditional programming toolsdon't work in this setting
  • 24.
    We have been brainwashedto use: 1. imperative programming with mutable state 2. locks, locks, locks
  • 25.
    The problem withmutable state car.setPosition(0); car.setPosition(10);
  • 26.
    The problem withmutable state
  • 27.
    The problem with locks •solution workaround for a broken conceptual model • hard to reason about • performance hit
  • 28.
    The problem with object-orientation inJava • there is no notion of time, only an illusion thereof • changes to a mutable model only make sense locally if nobody is watching • the larger the scope, the harder it gets to prevent inconsistencies
  • 29.
    The Whys 1. many-coreCPUs are here 2. everything is distributed 3. IoT around the corner with 26 billions devices 4. our traditional approach does not work here
  • 30.
  • 31.
  • 32.
    In theory • FunctionalProgramming • The Actor Model • Evented Server Model • Stateless architecture • Event Sourcing • Reactive Streams
  • 33.
    In practice • FunctionalProgramming Scala • The Actor Model Akka • Evented Server Model Play • Stateless architecture Play • Event Sourcing Akka Persistence • Reactive Streams Akka Streams
  • 34.
  • 35.
    Short Scala history •Martin Odersky, EPFL • first release in 2003 • Typesafe Inc.
  • 36.
    Design goals • Fullinteroperability with Java • Cut down boilerplate • Pure object orientation & functional programming • Move away from null • Many-core programming
  • 37.
    Core concepts ofFunctional Programming • immutability • functions • transforming data with functions
  • 38.
    Immutability case class Car(brand:String, position: Int) val car = Car(brand = "DeLorean", position = 0) val movedCar = car.copy(position = 10) val movedCarLaterOn = car.copy(position = 30)
  • 39.
    Immutability case class Car(brand:String, position: Int) val car = Car(brand = "DeLorean", position = 0) val movedCar = car.copy(position = 10) val movedCarLaterOn = car.copy(position = 30) Work with snapshots of state
  • 40.
    Higher-order functions val (minors, majors)= users.partition(_.age < 18)
  • 41.
    Higher-order functions val isMinor = (age:Int) => age < 18 val (minors, majors) = users.partition(isMinor)
  • 42.
    Higher-order functions val isMinor = (age:Int) => age < 18 val (minors, majors) = users.partition(isMinor) Moving behaviour around instead of moving data around
  • 43.
    Transforming data val addresses= users.filter(_.age > 18) .map(_.address) .sortBy(_.city) Goal: To build increasingly complex behaviour through a series of transformations / by composing functions
  • 44.
    Composition def fetchUser(id: Long):Option[User] = ... def fetchCar(id: Long): Option[Car] = ... val insuranceCost: Option[BigDecimal] = for { user <- fetchUser(42) car <- fetchCar(23) } yield { car.price / 10 - user.age }
  • 45.
    Composition def fetchUser(id: Long):Future[User] = ... def fetchCar(id: Long): Future[Car] = ... val insuranceCost: Future[BigDecimal] = for { user <- fetchUser(42) car <- fetchCar(23) } yield { car.price / 10 - user.age }
  • 46.
    Composition def fetchUser(id: Long):Try[User] = ... def fetchCar(id: Long): Try[Car] = ... val insuranceCost: Try[BigDecimal] = for { user <- fetchUser(42) car <- fetchCar(23) } yield { car.price / 10 - user.age }
  • 47.
    Composition def fetchUser(id: Long):[User] = ... def fetchCar(id: Long): [Car] = ... val insuranceCost: [BigDecimal] = for { user <- (42) car <- (23) } yield { car.price / 10 - user.age }
  • 48.
  • 49.
    Functional composition • Option, Future,Try all implement monadic operations • set of data structures following the same laws • know one, know them all • keeping things DRY • also, it's not that scary
  • 50.
  • 51.
    History • 1973 "AUniversal Modular Actor Formalism for Artificial Intelligence", Carl Hewitt, Peter Bishop and Richard Steiger • based on physics (quantum physics and relativistic physics) • 1986 First release of Erlang (Joe Armstrong) • 1998 Ericsson reports that the AXD301 switch achieves an availability of 99.9999999%
  • 52.
    History • 2010 Firstrelease of Akka (Jonas Bonér) • inspired by Erlang and the Actor Model • message-based asynchronous concurrency toolkit • object-oriented programming done right
  • 53.
    History • 2010 Firstrelease of Akka (Jonas Bonér) • inspired by Erlang and the Actor Model • message-based asynchronous concurrency toolkit • object-oriented programming done right • Akka is also a mountain in Sweden
  • 54.
    Actors • lightweight objects •send and receive messages (mailbox) • can have children (supervision)
  • 58.
    Sending and receivingmessages case object RevelationOfFathership class Luke extends Actor { def receive = { case RevelationOfFathership => System.err.println("Noooooooooo") } }
  • 59.
    Sending and receivingmessages case object RevelationOfFathership class Luke extends Actor { def receive = { case RevelationOfFathership => System.err.println("Noooooooooo") } } val luke = ActorSystem.actorOf(Props[Luke]) luke ! RevelationOfFathership
  • 60.
    Supervision class Vader extendsActor { val troopers: ActorRef = context .actorOf[StromTrooper] .withRouter( RoundRobinRouter(nrOfInstances = 8) ) }
  • 61.
    Supervision class Vader extendsActor { val troopers: ActorRef = context .actorOf[StromTrooper] .withRouter( RoundRobinRouter(nrOfInstances = 8) ) }
  • 62.
    Supervision class Vader extendsActor { val troopers: ActorRef = context .actorOf[StromTrooper] .withRouter( RoundRobinRouter(nrOfInstances = 8) ) override def supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 3) { case t: Throwable => log.error("StormTrooper down!", t) Restart } }
  • 63.
    3rd How: Evented servers &statless architecture Play
  • 64.
    Play history • MVCframework, inspired by RoR, Django, Symfony • Zenexity • first version released in 2009 • version 2.0 released in 2012, core rewritten in Scala
  • 65.
    Design Principles • everythingis compiled • non-blocking I/O • controller actions are functions (request => response) • "share nothing" => horizontal scalability
  • 66.
    Threaded servers • likea train station with multiple tracks • station chief decides which trains go on which platform • if there are more trains than platforms, trains queue up • if too many trains are queuing up, huge delays occur and passengers go home
  • 67.
    Evented servers • likea waiter in a restaurant • runs back and forth between tables and the kitchen • does only small tasks that do not take much time • one server can each serve many tables at once
  • 68.
    Advantages of theevented approach • less threads means less memory • better CPU utilization (reduced context switching) • (much) higher throughputs than threaded servers
  • 69.
    The Hows 1. functionalprogramming (immutability, functions, composition) 2. actor model 3. evented servers & stateless architecture 4. event-sourcing & reactive streams
  • 70.
    Summary • many-core &distributed systems around the corner and there to stay • get ready and adopt some of the "new" tools
  • 71.
    Thank you http://www.manning.com/bernhardt code ctwlambdad41% discount @elmanu / manuel@bernhardt.io Questions?