reactive web-applications @ lambdadays
TRANSCRIPT
Scala, Akka, PlayThe why and how of reactive web-applications on the JVM
Lambda Days 2015Manuel Bernhardt - @elmanu
Agenda1. 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 WhyThe 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 Whys1. 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 HowThe 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 dataval addresses = users.filter(_.age > 18) .map(_.address) .sortBy(_.city)
Goal: To build increasingly complex behaviour through a series of transformations / by composing functions
Compositiondef 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}
Compositiondef 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}
Compositiondef 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}
Compositiondef fetchUser(id: Long): [User] = ...def fetchCar(id: Long): [Car] = ...
val insuranceCost: [BigDecimal] = for { user <- (42) car <- (23)} yield { car.price / 10 - user.age}
Composition!OptionFutureTry...
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 messagescase object RevelationOfFathership
class Luke extends Actor { def receive = { case RevelationOfFathership => System.err.println("Noooooooooo") }}
Sending and receiving messagescase 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 Hows1. 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 youhttp://www.manning.com/bernhardt
code ctwlambdad � 41% discount
@elmanu / [email protected]
Questions?