SlideShare a Scribd company logo
MANCHESTER LONDON NEW YORK
Petr Zapletal @petr_zapletal
#ReactiveNYC
@cakesolutions
Top Mistakes When Writing Reactive
Applications
Agenda
● Motivation
● Actors vs Futures
● Serialization
● Flat Actor Hierarchies
● Graceful Shutdown
● Distributed Transactions
● Longtail Latencies
● Quick Tips
Actors vs Futures
Constraints Liberate, Liberties Constrain
Pick the Right Tool for The Job
Scala
Future[T]
Akka
ACTORS
Power
Constraints
Akka
Stream
Pick the Right Tool for The Job
Scala
Future[T]
Akka
ACTORS
Power
Constraints
Akka
TYPED
Pick the Right Tool for The Job
Scala
Future[T] Akka
TYPED
Akka
ACTORS
Power
Constraints
Akka
Stream
Pick the Right Tool for The Job
Scala
Future[T]
Local Abstractions Distribution
Akka
TYPED
Akka
ACTORS
Power
Constraints
Akka
Stream
Actor Use Cases
● State management
● Location transparency
● Resilience mechanisms
● Single writer
● In-memory lock-free cache
● Sharding
Akka
ACTOR
Future Use Cases
● Local Concurrency
● Simplicity
● Composition
● Typesafety
Scala
Future[T]
Avoid Java Serialization
Java Serialization is the default in Akka, since
it is easy to start with it, but is very slow and
footprint heavy
Akka
ACTOR
Sending Data Through Network
Serialization Serialization
Akka
ACTOR
Persisting Data
Akka
ACTOR
Serialization
Java Serialization - Round Trip
Java Serialization - Footprint
Java Serialization - Footprint
case class Order (id: Long, description: String, totalCost: BigDecimal, orderLines: ArrayList[OrderLine], customer: Customer)
Java Serialization:
----sr--model.Order----h#-----J--idL--customert--Lmodel/Customer;L--descriptiont--Ljava/lang/String;L--orderLinest--Ljava/util
/List;L--totalCostt--Ljava/math/BigDecimal;xp--------ppsr--java.util.ArrayListx-----a----I--sizexp----w-----sr--model.OrderLine--
&-1-S----I--lineNumberL--costq-~--L--descriptionq-~--L--ordert--Lmodel/Order;xp----sr--java.math.BigDecimalT--W--(O---I--s
caleL--intValt--Ljava/math/BigInteger;xr--java.lang.Number-----------xp----sr--java.math.BigInteger-----;-----I--bitCountI--bitLe
ngthI--firstNonzeroByteNumI--lowestSetBitI--signum[--magnitudet--[Bxq-~----------------------ur--[B------T----xp----xxpq-~--x
q-~--
XML:
<order id="0" totalCost="0"><orderLines lineNumber="1" cost="0"><order>0</order></orderLines></order>
JSON:
{"order":{"id":0,"totalCost":0,"orderLines":[{"lineNumber":1,"cost":0,"order":0}]}}
Java Serialization Implementation
● Serializes
○ Data
○ Entire class definition
○ Definitions of all referenced classes
● It just “works”
○ Serializes almost everything (what implements Serializable)
○ Works with different JVMs
● Performance was not the main requirement
Points of Interest
● Performance
● Footprint
● Schema evolution
● Implementation effort
● Human readability
● Language bindings
● Backwards & forwards compatibility
● ...
JSON
● Advantages:
○ Human readability
○ Simple & well known
○ Many good libraries
for all platforms
● Disadvantages:
○ Slow
○ Large
○ Object names included
○ No schema (except e.g. json
schema)
○ Format and precision issues
● json4s, circe, µPickle, spray-json, argonaut, rapture-json, play-json, …
Binary formats [Schema-less]
● Metadata send together with data
● Advantages:
○ Implementation effort
○ Performance
○ Footprint *
● Disadvantages:
○ No human readability
● Kryo, Binary JSON (MessagePack, BSON, ... )
Binary formats [Schema]
● Schema defined by some kind of DSL
● Advantages:
○ Performance
○ Footprint
○ Schema evolution
● Disadvantages:
○ Implementation effort
○ No human readability
● Protobuf (+ projects like Flatbuffers, Cap’n Proto, etc.), Thrift, Avro
Summary
● Should be always changed
● Depends on particular use case
● Quick tips:
○ json4s
○ kryo
○ protobuf
Flat Actor Hierarchies
Errors should be handled out of band in a
parallel process - they are not part of the
main app
Top Level Actors
The Actor Hierarchy
/a1 /a2
Top Level Actors
The Actor Hierarchy
/a1 /a2
Root Actor
/user
Top Level Actors
The Actor Hierarchy
/a1 /a2
/b1 /b2
Root Actor
/c4/c3/c2/c1
/user
Top Level Actors
The Actor Hierarchy
/a1 /a2
/b1 /b2
Root Actor
/c4/c3/c2/c1
/user
/
/system
Two Different Battles to Win
● Separate business logic and failure handling
○ Less complexity
○ Better supportability
● Getting our application back to life after something bad happened
○ Failure isolation
○ Recovery
○ No more midnight calls :)
---> no more midnight calls :)
Errors & Failures
Errors
● Common events
● The current request is affected
● Will be communicated with the client/caller
● Incorrect requests, errors during validations, ...
Failures
● Unexpected events
● Service/actor is not able to operate normally
● Reports to supervisor
● Client can’t do anything, might be notified
● Database failures, network partitions, hardware
malfunctions, ...
Error Kernel Pattern
● Actor’s state is lost during restart and may not be recovered
● Delegating dangerous tasks to child actors and supervise them
/user/
a1
/user/
a1
/user/
a1/w1
/user/
a1
/user/
a1/w1
Summary
● Create rich actor hierarchies
● Separate business logic and failure handling
● Properly written, your application will be self-healing and incredibly
resilient
Graceful Shutdown
We have thousands of sharded actors on
multiple nodes and we want to shut one of
them down
Graceful Shutdown
High-level Procedure
High-level Procedure
1. JVM gets the shutdown signal
High-level Procedure
1. JVM gets the shutdown signal
2. Coordinator tells all local ShardRegions to shut down gracefully
High-level Procedure
1. JVM gets the shutdown signal
2. Coordinator tells all local ShardRegions to shut down gracefully
3. Node leaves cluster
High-level Procedure
1. JVM gets the shutdown signal
2. Coordinator tells all local ShardRegions to shut down gracefully
3. Node leaves cluster
4. Coordinator gives singletons a grace period to migrate
High-level Procedure
1. JVM gets the shutdown signal
2. Coordinator tells all local ShardRegions to shut down gracefully
3. Node leaves cluster
4. Coordinator gives singletons a grace period to migrate
5. Actor System & JVM Termination
Adding Shutdown Hook
val nodeShutdownCoordinatorActor = system.actorOf(Props(
new NodeGracefulShutdownCoordinator(...)))
sys.addShutdownHook {
nodeShutdownCoordinatorActor ! StartNodeShutdown(shardRegions)
}
Adding Shutdown Hook
val nodeShutdownCoordinatorActor = system.actorOf(Props(
new NodeGracefulShutdownCoordinator(...)))
sys.addShutdownHook {
nodeShutdownCoordinatorActor ! StartNodeShutdown(shardRegions)
}
Adding Shutdown Hook
val nodeShutdownCoordinatorActor = system.actorOf(Props(
new NodeGracefulShutdownCoordinator(...)))
sys.addShutdownHook {
nodeShutdownCoordinatorActor ! StartNodeShutdown(shardRegions)
}
Tell Local Regions to Shutdown
when(AwaitNodeShutdownInitiation) {
case Event(StartNodeShutdown(shardRegions), _) =>
if (shardRegions.nonEmpty) {
// starts watching of every shard region and sends GracefulShutdown msg to them
stopShardRegions(shardRegions)
goto(AwaitShardRegionsShutdown) using ManagedRegions(shardRegions)
} else {
// registers OnMemberRemoved and leaves the cluster
leaveCluster()
goto(AwaitClusterExit)
}
}
Tell Local Regions to Shutdown
when(AwaitNodeShutdownInitiation) {
case Event(StartNodeShutdown(shardRegions), _) =>
if (shardRegions.nonEmpty) {
// starts watching of every shard region and sends GracefulShutdown msg to them
stopShardRegions(shardRegions)
goto(AwaitShardRegionsShutdown) using ManagedRegions(shardRegions)
} else {
// registers OnMemberRemoved and leaves the cluster
leaveCluster()
goto(AwaitClusterExit)
}
}
Tell Local Regions to Shutdown
when(AwaitNodeShutdownInitiation) {
case Event(StartNodeShutdown(shardRegions), _) =>
if (shardRegions.nonEmpty) {
// starts watching of every shard region and sends GracefulShutdown msg to them
stopShardRegions(shardRegions)
goto(AwaitShardRegionsShutdown) using ManagedRegions(shardRegions)
} else {
// registers OnMemberRemoved and leaves the cluster
leaveCluster()
goto(AwaitClusterExit)
}
}
Tell Local Regions to Shutdown
when(AwaitNodeShutdownInitiation) {
case Event(StartNodeShutdown(shardRegions), _) =>
if (shardRegions.nonEmpty) {
// starts watching of every shard region and sends GracefulShutdown msg to them
stopShardRegions(shardRegions)
goto(AwaitShardRegionsShutdown) using ManagedRegions(shardRegions)
} else {
// registers OnMemberRemoved and leaves the cluster
leaveCluster()
goto(AwaitClusterExit)
}
}
Node Leaves the Cluster
when(AwaitShardRegionsShutdown, stateTimeout = ... ){
case Event(Terminated(actor), ManagedRegions(regions)) =>
if (regions.contains(actor)) {
val remainingRegions = regions - actor
if (remainingRegions.isEmpty) {
leaveCluster()
goto(AwaitClusterExit)
} else {
goto(AwaitShardRegionsShutdown) using ManagedRegions(remainingRegions)
}
} else {
stay()
}
case Event(StateTimeout, _) =>
leaveCluster()
goto(AwaitNodeTerminationSignal)
}
Node Leaves the Cluster
when(AwaitShardRegionsShutdown, stateTimeout = ... ){
case Event(Terminated(actor), ManagedRegions(regions)) =>
if (regions.contains(actor)) {
val remainingRegions = regions - actor
if (remainingRegions.isEmpty) {
leaveCluster()
goto(AwaitClusterExit)
} else {
goto(AwaitShardRegionsShutdown) using ManagedRegions(remainingRegions)
}
} else {
stay()
}
case Event(StateTimeout, _) =>
leaveCluster()
goto(AwaitNodeTerminationSignal)
}
Node Leaves the Cluster
when(AwaitShardRegionsShutdown, stateTimeout = ... ){
case Event(Terminated(actor), ManagedRegions(regions)) =>
if (regions.contains(actor)) {
val remainingRegions = regions - actor
if (remainingRegions.isEmpty) {
leaveCluster()
goto(AwaitClusterExit)
} else {
goto(AwaitShardRegionsShutdown) using ManagedRegions(remainingRegions)
}
} else {
stay()
}
case Event(StateTimeout, _) =>
leaveCluster()
goto(AwaitNodeTerminationSignal)
}
Wait for Singletons to Migrate
when(AwaitClusterExit, stateTimeout = ...) {
case Event(NodeLeftCluster | StateTimeout, _) =>
// Waiting on cluster singleton migration
goto(AwaitClusterSingletonMigration)
}
when(AwaitClusterSingletonMigration, stateTimeout = ... ) {
case Event(StateTimeout, _) =>
goto(AwaitNodeTerminationSignal)
}
onTransition {
case AwaitClusterSingletonMigration -> AwaitNodeTerminationSignal =>
self ! TerminateNode
}
Wait for Singletons to Migrate
when(AwaitClusterExit, stateTimeout = ...) {
case Event(NodeLeftCluster | StateTimeout, _) =>
// Waiting on cluster singleton migration
goto(AwaitClusterSingletonMigration)
}
when(AwaitClusterSingletonMigration, stateTimeout = ... ) {
case Event(StateTimeout, _) =>
goto(AwaitNodeTerminationSignal)
}
onTransition {
case AwaitClusterSingletonMigration -> AwaitNodeTerminationSignal =>
self ! TerminateNode
}
Wait for Singletons to Migrate
when(AwaitClusterExit, stateTimeout = ...) {
case Event(NodeLeftCluster | StateTimeout, _) =>
// Waiting on cluster singleton migration
goto(AwaitClusterSingletonMigration)
}
when(AwaitClusterSingletonMigration, stateTimeout = ... ) {
case Event(StateTimeout, _) =>
goto(AwaitNodeTerminationSignal)
}
onTransition {
case AwaitClusterSingletonMigration -> AwaitNodeTerminationSignal =>
self ! TerminateNode
}
Wait for Singletons to Migrate
when(AwaitClusterExit, stateTimeout = ...) {
case Event(NodeLeftCluster | StateTimeout, _) =>
// Waiting on cluster singleton migration
goto(AwaitClusterSingletonMigration)
}
when(AwaitClusterSingletonMigration, stateTimeout = ... ) {
case Event(StateTimeout, _) =>
goto(AwaitNodeTerminationSignal)
}
onTransition {
case AwaitClusterSingletonMigration -> AwaitNodeTerminationSignal =>
self ! TerminateNode
}
Actor System & JVM Termination
when(AwaitNodeTerminationSignal, stateTimeout = ...) {
case Event(TerminateNode | StateTimeout, _) =>
// This is NOT an Akka thread-pool (since we're shutting those down)
val ec = scala.concurrent.ExecutionContext.global
// Calls context.system.terminate with registered onComplete block
terminateSystem {
case Success(ex) =>
System.exit(...)
case Failure(ex) =>
System.exit(...)
}(ec)
stop(Shutdown)
}
Actor System & JVM Termination
when(AwaitNodeTerminationSignal, stateTimeout = ...) {
case Event(TerminateNode | StateTimeout, _) =>
// This is NOT an Akka thread-pool (since we're shutting those down)
val ec = scala.concurrent.ExecutionContext.global
// Calls context.system.terminate with registered onComplete block
terminateSystem {
case Success(ex) =>
System.exit(...)
case Failure(ex) =>
System.exit(...)
}(ec)
stop(Shutdown)
}
Actor System & JVM Termination
when(AwaitNodeTerminationSignal, stateTimeout = ...) {
case Event(TerminateNode | StateTimeout, _) =>
// This is NOT an Akka thread-pool (since we're shutting those down)
val ec = scala.concurrent.ExecutionContext.global
// Calls context.system.terminate with registered onComplete block
terminateSystem {
case Success(ex) =>
System.exit(...)
case Failure(ex) =>
System.exit(...)
}(ec)
stop(Shutdown)
}
Actor System & JVM Termination
when(AwaitNodeTerminationSignal, stateTimeout = ...) {
case Event(TerminateNode | StateTimeout, _) =>
// This is NOT an Akka thread-pool (since we're shutting those down)
val ec = scala.concurrent.ExecutionContext.global
// Calls context.system.terminate with registered onComplete block
terminateSystem {
case Success(ex) =>
System.exit(...)
case Failure(ex) =>
System.exit(...)
}(ec)
stop(Shutdown)
}
Integration with Sharded Actors
● Handling of added messages
○ Passivate() message for graceful stop
○ Context.stop() for immediate stop
● Priority mailbox
○ Priority message handling
○ Message retrying support
Summary
● We don’t want to lose data (usually)
● Shutdown coordinator on every node
● Integration with sharded actors
Distributed Transactions
Any situation where a single event results in
the mutation of two separate sources of data
which cannot be committed atomically
What’s Wrong With Them
● Simple happy paths
● 7 Fallacies of Distributed Programming
○ The network is reliable.
○ Latency is zero.
○ Bandwidth is infinite.
○ The network is secure.
○ Topology doesn't change.
○ There is one administrator.
○ Transport cost is zero.
○ The network is homogeneous.
Two-phase commit (2PC)
Stage 1 - Prepare Stage 2 - Commit
Prepare
Prepared
Prepare
Prepared
Com
m
it
Com
m
itted
Commit
Committed
Resource
Manager
Resource
Manager
Transaction
Manager
Resource
Manager
Resource
Manager
Transaction
Manager
Saga Pattern
T1 T2 T3 T4
C1 C2 C3 C4
The Big Trade-Off
● Distributed transactions can be usually avoided
○ Hard, expensive, fragile and do not scale
● Every business event needs to result in a single synchronous commit
● Other data sources should be updated asynchronously
● Introducing eventual consistency
Longtail Latencies
Consider a system where each service
typically responds in 10ms but with a 99th
percentile latency of one second
Longtail Latencies
Latency Normal vs. Longtail
Legend:
Normal
Longtail
50
40
30
20
10
0
25 50 75 90 99 99.9
Latency(ms)
Percentile
Longtails really matter
● Latency accumulation
● Not just noise
● Don’t have to be power users
● Real problem
Investigating Longtail Latencies
● Narrow the problem
● Isolate in a test environment
● Measure & monitor everything
● Tackle the problem
● Pretty hard job
Tolerating Longtail Latencies
Tolerating Longtail Latencies
● Hedging your bet
Tolerating Longtail Latencies
● Hedging your bet
● Tied requests
Tolerating Longtail Latencies
● Hedging your bet
● Tied requests
● Selectively increase replication factors
Tolerating Longtail Latencies
● Hedging your bet
● Tied requests
● Selectively increase replication factors
● Put slow machines on probation
Tolerating Longtail Latencies
● Hedging your bet
● Tied requests
● Selectively increase replication factors
● Put slow machines on probation
● Consider ‘good enough’ responses
Tolerating Longtail Latencies
● Hedging your bet
● Tied requests
● Selectively increase replication factors
● Put slow machines on probation
● Consider ‘good enough’ responses
● Hardware update
Quick Tips
Quick Tips
● Monitoring
Quick Tips
● Monitoring
● Network partitions & Split Brain Resolver
Quick Tips
● Monitoring
● Network partitions & Split Brain Resolver
● Blocking
Quick Tips
● Monitoring
● Network partitions & Split Brain Resolver
● Blocking
● Too many actor systems
Questions
MANCHESTER LONDON NEW YORK
MANCHESTER LONDON NEW YORK
@petr_zapletal @cakesolutions
347 708 1518
petrz@cakesolutions.net
We are hiring
http://www.cakesolutions.net/careers
References
● http://www.reactivemanifesto.org/
● http://www.slideshare.net/ktoso/zen-of-akka
● http://eishay.github.io/jvm-serializers/prototype-results-page/
● http://java-persistence-performance.blogspot.com/2013/08/optimizing-java-serialization-java-vs.html
● https://github.com/romix/akka-kryo-serialization
● http://gotocon.com/dl/goto-chicago-2015/slides/CaitieMcCaffrey_ApplyingTheSagaPattern.pdf
● http://www.grahamlea.com/2016/08/distributed-transactions-microservices-icebergs/
● http://www.cs.duke.edu/courses/cps296.4/fall13/838-CloudPapers/dean_longtail.pdf
● https://engineering.linkedin.com/performance/who-moved-my-99th-percentile-latency
● http://doc.akka.io/docs/akka/rp-15v09p01/scala/split-brain-resolver.html
● http://manuel.bernhardt.io/2016/08/09/akka-anti-patterns-flat-actor-hierarchies-or-mixing-business-logic-a
nd-failure-handling/
Backup Slides
MANCHESTER LONDON NEW YORK

More Related Content

PDF
Reactive mistakes - ScalaDays Chicago 2017
PDF
Real World Serverless
PPT
Scalable Realtime Analytics with declarative SQL like Complex Event Processin...
PDF
Distributed systems vs compositionality
PDF
Apache Flink internals
PDF
Virtual Flink Forward 2020: Autoscaling Flink at Netflix - Timothy Farkas
PDF
Spark streaming: Best Practices
PPTX
Cassandra Metrics
Reactive mistakes - ScalaDays Chicago 2017
Real World Serverless
Scalable Realtime Analytics with declarative SQL like Complex Event Processin...
Distributed systems vs compositionality
Apache Flink internals
Virtual Flink Forward 2020: Autoscaling Flink at Netflix - Timothy Farkas
Spark streaming: Best Practices
Cassandra Metrics

What's hot (20)

PDF
PSUG #52 Dataflow and simplified reactive programming with Akka-streams
PDF
Journey into Reactive Streams and Akka Streams
PDF
Flink Forward SF 2017: Joe Olson - Using Flink and Queryable State to Buffer ...
PPTX
Javantura v3 - Going Reactive with RxJava – Hrvoje Crnjak
PDF
Pulsar connector on flink 1.14
PPTX
Monitoring Cassandra with graphite using Yammer Coda-Hale Library
PPT
Spark and spark streaming internals
ODP
Introduction to Structured Streaming
PDF
Unified Stream and Batch Processing with Apache Flink
PPTX
Flink Forward SF 2017: Timo Walther - Table & SQL API – unified APIs for bat...
PDF
Thinking Functionally with Clojure
PPTX
S3 cassandra or outer space? dumping time series data using spark
PPTX
Flink Forward SF 2017: Shaoxuan Wang_Xiaowei Jiang - Blinks Improvements to F...
PDF
Self-managed and automatically reconfigurable stream processing
PDF
Apache Flink Internals: Stream & Batch Processing in One System – Apache Flin...
PPT
Reactive programming with examples
PPTX
Stream processing from single node to a cluster
PDF
Spark Summit EU talk by Qifan Pu
PPTX
Till Rohrmann – Fault Tolerance and Job Recovery in Apache Flink
PDF
Ufuc Celebi – Stream & Batch Processing in one System
PSUG #52 Dataflow and simplified reactive programming with Akka-streams
Journey into Reactive Streams and Akka Streams
Flink Forward SF 2017: Joe Olson - Using Flink and Queryable State to Buffer ...
Javantura v3 - Going Reactive with RxJava – Hrvoje Crnjak
Pulsar connector on flink 1.14
Monitoring Cassandra with graphite using Yammer Coda-Hale Library
Spark and spark streaming internals
Introduction to Structured Streaming
Unified Stream and Batch Processing with Apache Flink
Flink Forward SF 2017: Timo Walther - Table & SQL API – unified APIs for bat...
Thinking Functionally with Clojure
S3 cassandra or outer space? dumping time series data using spark
Flink Forward SF 2017: Shaoxuan Wang_Xiaowei Jiang - Blinks Improvements to F...
Self-managed and automatically reconfigurable stream processing
Apache Flink Internals: Stream & Batch Processing in One System – Apache Flin...
Reactive programming with examples
Stream processing from single node to a cluster
Spark Summit EU talk by Qifan Pu
Till Rohrmann – Fault Tolerance and Job Recovery in Apache Flink
Ufuc Celebi – Stream & Batch Processing in one System
Ad

Viewers also liked (20)

PDF
Distributed Stream Processing - Spark Summit East 2017
PPTX
Akka: Введение
PDF
Top Mistakes When Writing Reactive Applications - Scala by the Bay 2016
PPTX
MessageBus vs MessageBus
PDF
Streaming data to s3 using akka streams
PDF
User Focused Security at Netflix: Stethoscope
PDF
Taking the friction out of microservice frameworks with Lagom
PPTX
Akka Fundamentals
PDF
Stay productive while slicing up the monolith
PDF
Akka Streams in Action @ ScalaDays Berlin 2016
PPTX
Akkaships: "Primeros pasos con Akka: Olvídate de los threads"
PPTX
JavaOne: A tour of (advanced) akka features in 60 minutes [con1706]
PDF
Akka stream
PDF
Modernizing Applications with Microservices
PDF
How Reactive Streams & Akka Streams change the JVM Ecosystem
PPTX
2016 Tableau in the Cloud - A Netflix Original (AWS Re:invent)
PDF
Akka streams
PDF
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
PDF
Hyperscale Computing, Enterprise Agility with Mesosphere
PPTX
Spark Concepts - Spark SQL, Graphx, Streaming
Distributed Stream Processing - Spark Summit East 2017
Akka: Введение
Top Mistakes When Writing Reactive Applications - Scala by the Bay 2016
MessageBus vs MessageBus
Streaming data to s3 using akka streams
User Focused Security at Netflix: Stethoscope
Taking the friction out of microservice frameworks with Lagom
Akka Fundamentals
Stay productive while slicing up the monolith
Akka Streams in Action @ ScalaDays Berlin 2016
Akkaships: "Primeros pasos con Akka: Olvídate de los threads"
JavaOne: A tour of (advanced) akka features in 60 minutes [con1706]
Akka stream
Modernizing Applications with Microservices
How Reactive Streams & Akka Streams change the JVM Ecosystem
2016 Tableau in the Cloud - A Netflix Original (AWS Re:invent)
Akka streams
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
Hyperscale Computing, Enterprise Agility with Mesosphere
Spark Concepts - Spark SQL, Graphx, Streaming
Ad

Similar to Reactive mistakes reactive nyc (20)

PDF
A tour of (advanced) Akka features in 40 minutes
PDF
Akka (1)
PDF
Akka and the Zen of Reactive System Design
PDF
Advanced akka features
PDF
Backday Xebia : Akka, the reactive toolkit
PDF
PDF
Writing Asynchronous Programs with Scala & Akka
PDF
Introducing Akka
PDF
Introducingakkajavazone2012 120914094033-phpapp02
PDF
First glance at Akka 2.0
PPT
Building large scale, job processing systems with Scala Akka Actor framework
PDF
Introducing Akka
PDF
Actor, an elegant model for concurrent and distributed computation
PDF
Scaling Web Apps with Akka
PDF
Akka lsug skills matter
PDF
Reactive applications and Akka intro used in the Madrid Scala Meetup
PPTX
Scale up your thinking
PDF
A gentle introduction into AKKA and the actor model
PDF
Scalaz 8 vs Akka Actors
PDF
Building Stateful Microservices With Akka
A tour of (advanced) Akka features in 40 minutes
Akka (1)
Akka and the Zen of Reactive System Design
Advanced akka features
Backday Xebia : Akka, the reactive toolkit
Writing Asynchronous Programs with Scala & Akka
Introducing Akka
Introducingakkajavazone2012 120914094033-phpapp02
First glance at Akka 2.0
Building large scale, job processing systems with Scala Akka Actor framework
Introducing Akka
Actor, an elegant model for concurrent and distributed computation
Scaling Web Apps with Akka
Akka lsug skills matter
Reactive applications and Akka intro used in the Madrid Scala Meetup
Scale up your thinking
A gentle introduction into AKKA and the actor model
Scalaz 8 vs Akka Actors
Building Stateful Microservices With Akka

More from Petr Zapletal (7)

PDF
Change Data Capture - Scale by the Bay 2019
PDF
Adopting GraalVM - NE Scala 2019
PDF
Adopting GraalVM - Scala eXchange London 2018
PDF
Adopting GraalVM - Scale by the Bay 2018
PDF
Distributed Real-Time Stream Processing: Why and How 2.0
PDF
Distributed real time stream processing- why and how
PPTX
MLlib and Machine Learning on Spark
Change Data Capture - Scale by the Bay 2019
Adopting GraalVM - NE Scala 2019
Adopting GraalVM - Scala eXchange London 2018
Adopting GraalVM - Scale by the Bay 2018
Distributed Real-Time Stream Processing: Why and How 2.0
Distributed real time stream processing- why and how
MLlib and Machine Learning on Spark

Recently uploaded (20)

PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Download FL Studio Crack Latest version 2025 ?
PPTX
Monitoring Stack: Grafana, Loki & Promtail
PPTX
history of c programming in notes for students .pptx
PPTX
Computer Software and OS of computer science of grade 11.pptx
PDF
iTop VPN Free 5.6.0.5262 Crack latest version 2025
PDF
17 Powerful Integrations Your Next-Gen MLM Software Needs
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
CCleaner Pro 6.38.11537 Crack Final Latest Version 2025
PPTX
Patient Appointment Booking in Odoo with online payment
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
CapCut Video Editor 6.8.1 Crack for PC Latest Download (Fully Activated) 2025
DOCX
Greta — No-Code AI for Building Full-Stack Web & Mobile Apps
PPTX
Weekly report ppt - harsh dattuprasad patel.pptx
PDF
iTop VPN 6.5.0 Crack + License Key 2025 (Premium Version)
PDF
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Download FL Studio Crack Latest version 2025 ?
Monitoring Stack: Grafana, Loki & Promtail
history of c programming in notes for students .pptx
Computer Software and OS of computer science of grade 11.pptx
iTop VPN Free 5.6.0.5262 Crack latest version 2025
17 Powerful Integrations Your Next-Gen MLM Software Needs
Digital Systems & Binary Numbers (comprehensive )
CCleaner Pro 6.38.11537 Crack Final Latest Version 2025
Patient Appointment Booking in Odoo with online payment
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
CapCut Video Editor 6.8.1 Crack for PC Latest Download (Fully Activated) 2025
Greta — No-Code AI for Building Full-Stack Web & Mobile Apps
Weekly report ppt - harsh dattuprasad patel.pptx
iTop VPN 6.5.0 Crack + License Key 2025 (Premium Version)
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
Odoo Companies in India – Driving Business Transformation.pdf
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
Operating system designcfffgfgggggggvggggggggg
Adobe Illustrator 28.6 Crack My Vision of Vector Design

Reactive mistakes reactive nyc

  • 2. Petr Zapletal @petr_zapletal #ReactiveNYC @cakesolutions Top Mistakes When Writing Reactive Applications
  • 3. Agenda ● Motivation ● Actors vs Futures ● Serialization ● Flat Actor Hierarchies ● Graceful Shutdown ● Distributed Transactions ● Longtail Latencies ● Quick Tips
  • 4. Actors vs Futures Constraints Liberate, Liberties Constrain
  • 5. Pick the Right Tool for The Job Scala Future[T] Akka ACTORS Power Constraints Akka Stream
  • 6. Pick the Right Tool for The Job Scala Future[T] Akka ACTORS Power Constraints Akka TYPED
  • 7. Pick the Right Tool for The Job Scala Future[T] Akka TYPED Akka ACTORS Power Constraints Akka Stream
  • 8. Pick the Right Tool for The Job Scala Future[T] Local Abstractions Distribution Akka TYPED Akka ACTORS Power Constraints Akka Stream
  • 9. Actor Use Cases ● State management ● Location transparency ● Resilience mechanisms ● Single writer ● In-memory lock-free cache ● Sharding Akka ACTOR
  • 10. Future Use Cases ● Local Concurrency ● Simplicity ● Composition ● Typesafety Scala Future[T]
  • 11. Avoid Java Serialization Java Serialization is the default in Akka, since it is easy to start with it, but is very slow and footprint heavy
  • 12. Akka ACTOR Sending Data Through Network Serialization Serialization Akka ACTOR
  • 14. Java Serialization - Round Trip
  • 15. Java Serialization - Footprint
  • 16. Java Serialization - Footprint case class Order (id: Long, description: String, totalCost: BigDecimal, orderLines: ArrayList[OrderLine], customer: Customer) Java Serialization: ----sr--model.Order----h#-----J--idL--customert--Lmodel/Customer;L--descriptiont--Ljava/lang/String;L--orderLinest--Ljava/util /List;L--totalCostt--Ljava/math/BigDecimal;xp--------ppsr--java.util.ArrayListx-----a----I--sizexp----w-----sr--model.OrderLine-- &-1-S----I--lineNumberL--costq-~--L--descriptionq-~--L--ordert--Lmodel/Order;xp----sr--java.math.BigDecimalT--W--(O---I--s caleL--intValt--Ljava/math/BigInteger;xr--java.lang.Number-----------xp----sr--java.math.BigInteger-----;-----I--bitCountI--bitLe ngthI--firstNonzeroByteNumI--lowestSetBitI--signum[--magnitudet--[Bxq-~----------------------ur--[B------T----xp----xxpq-~--x q-~-- XML: <order id="0" totalCost="0"><orderLines lineNumber="1" cost="0"><order>0</order></orderLines></order> JSON: {"order":{"id":0,"totalCost":0,"orderLines":[{"lineNumber":1,"cost":0,"order":0}]}}
  • 17. Java Serialization Implementation ● Serializes ○ Data ○ Entire class definition ○ Definitions of all referenced classes ● It just “works” ○ Serializes almost everything (what implements Serializable) ○ Works with different JVMs ● Performance was not the main requirement
  • 18. Points of Interest ● Performance ● Footprint ● Schema evolution ● Implementation effort ● Human readability ● Language bindings ● Backwards & forwards compatibility ● ...
  • 19. JSON ● Advantages: ○ Human readability ○ Simple & well known ○ Many good libraries for all platforms ● Disadvantages: ○ Slow ○ Large ○ Object names included ○ No schema (except e.g. json schema) ○ Format and precision issues ● json4s, circe, µPickle, spray-json, argonaut, rapture-json, play-json, …
  • 20. Binary formats [Schema-less] ● Metadata send together with data ● Advantages: ○ Implementation effort ○ Performance ○ Footprint * ● Disadvantages: ○ No human readability ● Kryo, Binary JSON (MessagePack, BSON, ... )
  • 21. Binary formats [Schema] ● Schema defined by some kind of DSL ● Advantages: ○ Performance ○ Footprint ○ Schema evolution ● Disadvantages: ○ Implementation effort ○ No human readability ● Protobuf (+ projects like Flatbuffers, Cap’n Proto, etc.), Thrift, Avro
  • 22. Summary ● Should be always changed ● Depends on particular use case ● Quick tips: ○ json4s ○ kryo ○ protobuf
  • 23. Flat Actor Hierarchies Errors should be handled out of band in a parallel process - they are not part of the main app
  • 24. Top Level Actors The Actor Hierarchy /a1 /a2
  • 25. Top Level Actors The Actor Hierarchy /a1 /a2 Root Actor /user
  • 26. Top Level Actors The Actor Hierarchy /a1 /a2 /b1 /b2 Root Actor /c4/c3/c2/c1 /user
  • 27. Top Level Actors The Actor Hierarchy /a1 /a2 /b1 /b2 Root Actor /c4/c3/c2/c1 /user / /system
  • 28. Two Different Battles to Win ● Separate business logic and failure handling ○ Less complexity ○ Better supportability ● Getting our application back to life after something bad happened ○ Failure isolation ○ Recovery ○ No more midnight calls :) ---> no more midnight calls :)
  • 29. Errors & Failures Errors ● Common events ● The current request is affected ● Will be communicated with the client/caller ● Incorrect requests, errors during validations, ... Failures ● Unexpected events ● Service/actor is not able to operate normally ● Reports to supervisor ● Client can’t do anything, might be notified ● Database failures, network partitions, hardware malfunctions, ...
  • 30. Error Kernel Pattern ● Actor’s state is lost during restart and may not be recovered ● Delegating dangerous tasks to child actors and supervise them /user/ a1 /user/ a1 /user/ a1/w1 /user/ a1 /user/ a1/w1
  • 31. Summary ● Create rich actor hierarchies ● Separate business logic and failure handling ● Properly written, your application will be self-healing and incredibly resilient
  • 32. Graceful Shutdown We have thousands of sharded actors on multiple nodes and we want to shut one of them down
  • 35. High-level Procedure 1. JVM gets the shutdown signal
  • 36. High-level Procedure 1. JVM gets the shutdown signal 2. Coordinator tells all local ShardRegions to shut down gracefully
  • 37. High-level Procedure 1. JVM gets the shutdown signal 2. Coordinator tells all local ShardRegions to shut down gracefully 3. Node leaves cluster
  • 38. High-level Procedure 1. JVM gets the shutdown signal 2. Coordinator tells all local ShardRegions to shut down gracefully 3. Node leaves cluster 4. Coordinator gives singletons a grace period to migrate
  • 39. High-level Procedure 1. JVM gets the shutdown signal 2. Coordinator tells all local ShardRegions to shut down gracefully 3. Node leaves cluster 4. Coordinator gives singletons a grace period to migrate 5. Actor System & JVM Termination
  • 40. Adding Shutdown Hook val nodeShutdownCoordinatorActor = system.actorOf(Props( new NodeGracefulShutdownCoordinator(...))) sys.addShutdownHook { nodeShutdownCoordinatorActor ! StartNodeShutdown(shardRegions) }
  • 41. Adding Shutdown Hook val nodeShutdownCoordinatorActor = system.actorOf(Props( new NodeGracefulShutdownCoordinator(...))) sys.addShutdownHook { nodeShutdownCoordinatorActor ! StartNodeShutdown(shardRegions) }
  • 42. Adding Shutdown Hook val nodeShutdownCoordinatorActor = system.actorOf(Props( new NodeGracefulShutdownCoordinator(...))) sys.addShutdownHook { nodeShutdownCoordinatorActor ! StartNodeShutdown(shardRegions) }
  • 43. Tell Local Regions to Shutdown when(AwaitNodeShutdownInitiation) { case Event(StartNodeShutdown(shardRegions), _) => if (shardRegions.nonEmpty) { // starts watching of every shard region and sends GracefulShutdown msg to them stopShardRegions(shardRegions) goto(AwaitShardRegionsShutdown) using ManagedRegions(shardRegions) } else { // registers OnMemberRemoved and leaves the cluster leaveCluster() goto(AwaitClusterExit) } }
  • 44. Tell Local Regions to Shutdown when(AwaitNodeShutdownInitiation) { case Event(StartNodeShutdown(shardRegions), _) => if (shardRegions.nonEmpty) { // starts watching of every shard region and sends GracefulShutdown msg to them stopShardRegions(shardRegions) goto(AwaitShardRegionsShutdown) using ManagedRegions(shardRegions) } else { // registers OnMemberRemoved and leaves the cluster leaveCluster() goto(AwaitClusterExit) } }
  • 45. Tell Local Regions to Shutdown when(AwaitNodeShutdownInitiation) { case Event(StartNodeShutdown(shardRegions), _) => if (shardRegions.nonEmpty) { // starts watching of every shard region and sends GracefulShutdown msg to them stopShardRegions(shardRegions) goto(AwaitShardRegionsShutdown) using ManagedRegions(shardRegions) } else { // registers OnMemberRemoved and leaves the cluster leaveCluster() goto(AwaitClusterExit) } }
  • 46. Tell Local Regions to Shutdown when(AwaitNodeShutdownInitiation) { case Event(StartNodeShutdown(shardRegions), _) => if (shardRegions.nonEmpty) { // starts watching of every shard region and sends GracefulShutdown msg to them stopShardRegions(shardRegions) goto(AwaitShardRegionsShutdown) using ManagedRegions(shardRegions) } else { // registers OnMemberRemoved and leaves the cluster leaveCluster() goto(AwaitClusterExit) } }
  • 47. Node Leaves the Cluster when(AwaitShardRegionsShutdown, stateTimeout = ... ){ case Event(Terminated(actor), ManagedRegions(regions)) => if (regions.contains(actor)) { val remainingRegions = regions - actor if (remainingRegions.isEmpty) { leaveCluster() goto(AwaitClusterExit) } else { goto(AwaitShardRegionsShutdown) using ManagedRegions(remainingRegions) } } else { stay() } case Event(StateTimeout, _) => leaveCluster() goto(AwaitNodeTerminationSignal) }
  • 48. Node Leaves the Cluster when(AwaitShardRegionsShutdown, stateTimeout = ... ){ case Event(Terminated(actor), ManagedRegions(regions)) => if (regions.contains(actor)) { val remainingRegions = regions - actor if (remainingRegions.isEmpty) { leaveCluster() goto(AwaitClusterExit) } else { goto(AwaitShardRegionsShutdown) using ManagedRegions(remainingRegions) } } else { stay() } case Event(StateTimeout, _) => leaveCluster() goto(AwaitNodeTerminationSignal) }
  • 49. Node Leaves the Cluster when(AwaitShardRegionsShutdown, stateTimeout = ... ){ case Event(Terminated(actor), ManagedRegions(regions)) => if (regions.contains(actor)) { val remainingRegions = regions - actor if (remainingRegions.isEmpty) { leaveCluster() goto(AwaitClusterExit) } else { goto(AwaitShardRegionsShutdown) using ManagedRegions(remainingRegions) } } else { stay() } case Event(StateTimeout, _) => leaveCluster() goto(AwaitNodeTerminationSignal) }
  • 50. Wait for Singletons to Migrate when(AwaitClusterExit, stateTimeout = ...) { case Event(NodeLeftCluster | StateTimeout, _) => // Waiting on cluster singleton migration goto(AwaitClusterSingletonMigration) } when(AwaitClusterSingletonMigration, stateTimeout = ... ) { case Event(StateTimeout, _) => goto(AwaitNodeTerminationSignal) } onTransition { case AwaitClusterSingletonMigration -> AwaitNodeTerminationSignal => self ! TerminateNode }
  • 51. Wait for Singletons to Migrate when(AwaitClusterExit, stateTimeout = ...) { case Event(NodeLeftCluster | StateTimeout, _) => // Waiting on cluster singleton migration goto(AwaitClusterSingletonMigration) } when(AwaitClusterSingletonMigration, stateTimeout = ... ) { case Event(StateTimeout, _) => goto(AwaitNodeTerminationSignal) } onTransition { case AwaitClusterSingletonMigration -> AwaitNodeTerminationSignal => self ! TerminateNode }
  • 52. Wait for Singletons to Migrate when(AwaitClusterExit, stateTimeout = ...) { case Event(NodeLeftCluster | StateTimeout, _) => // Waiting on cluster singleton migration goto(AwaitClusterSingletonMigration) } when(AwaitClusterSingletonMigration, stateTimeout = ... ) { case Event(StateTimeout, _) => goto(AwaitNodeTerminationSignal) } onTransition { case AwaitClusterSingletonMigration -> AwaitNodeTerminationSignal => self ! TerminateNode }
  • 53. Wait for Singletons to Migrate when(AwaitClusterExit, stateTimeout = ...) { case Event(NodeLeftCluster | StateTimeout, _) => // Waiting on cluster singleton migration goto(AwaitClusterSingletonMigration) } when(AwaitClusterSingletonMigration, stateTimeout = ... ) { case Event(StateTimeout, _) => goto(AwaitNodeTerminationSignal) } onTransition { case AwaitClusterSingletonMigration -> AwaitNodeTerminationSignal => self ! TerminateNode }
  • 54. Actor System & JVM Termination when(AwaitNodeTerminationSignal, stateTimeout = ...) { case Event(TerminateNode | StateTimeout, _) => // This is NOT an Akka thread-pool (since we're shutting those down) val ec = scala.concurrent.ExecutionContext.global // Calls context.system.terminate with registered onComplete block terminateSystem { case Success(ex) => System.exit(...) case Failure(ex) => System.exit(...) }(ec) stop(Shutdown) }
  • 55. Actor System & JVM Termination when(AwaitNodeTerminationSignal, stateTimeout = ...) { case Event(TerminateNode | StateTimeout, _) => // This is NOT an Akka thread-pool (since we're shutting those down) val ec = scala.concurrent.ExecutionContext.global // Calls context.system.terminate with registered onComplete block terminateSystem { case Success(ex) => System.exit(...) case Failure(ex) => System.exit(...) }(ec) stop(Shutdown) }
  • 56. Actor System & JVM Termination when(AwaitNodeTerminationSignal, stateTimeout = ...) { case Event(TerminateNode | StateTimeout, _) => // This is NOT an Akka thread-pool (since we're shutting those down) val ec = scala.concurrent.ExecutionContext.global // Calls context.system.terminate with registered onComplete block terminateSystem { case Success(ex) => System.exit(...) case Failure(ex) => System.exit(...) }(ec) stop(Shutdown) }
  • 57. Actor System & JVM Termination when(AwaitNodeTerminationSignal, stateTimeout = ...) { case Event(TerminateNode | StateTimeout, _) => // This is NOT an Akka thread-pool (since we're shutting those down) val ec = scala.concurrent.ExecutionContext.global // Calls context.system.terminate with registered onComplete block terminateSystem { case Success(ex) => System.exit(...) case Failure(ex) => System.exit(...) }(ec) stop(Shutdown) }
  • 58. Integration with Sharded Actors ● Handling of added messages ○ Passivate() message for graceful stop ○ Context.stop() for immediate stop ● Priority mailbox ○ Priority message handling ○ Message retrying support
  • 59. Summary ● We don’t want to lose data (usually) ● Shutdown coordinator on every node ● Integration with sharded actors
  • 60. Distributed Transactions Any situation where a single event results in the mutation of two separate sources of data which cannot be committed atomically
  • 61. What’s Wrong With Them ● Simple happy paths ● 7 Fallacies of Distributed Programming ○ The network is reliable. ○ Latency is zero. ○ Bandwidth is infinite. ○ The network is secure. ○ Topology doesn't change. ○ There is one administrator. ○ Transport cost is zero. ○ The network is homogeneous.
  • 62. Two-phase commit (2PC) Stage 1 - Prepare Stage 2 - Commit Prepare Prepared Prepare Prepared Com m it Com m itted Commit Committed Resource Manager Resource Manager Transaction Manager Resource Manager Resource Manager Transaction Manager
  • 63. Saga Pattern T1 T2 T3 T4 C1 C2 C3 C4
  • 64. The Big Trade-Off ● Distributed transactions can be usually avoided ○ Hard, expensive, fragile and do not scale ● Every business event needs to result in a single synchronous commit ● Other data sources should be updated asynchronously ● Introducing eventual consistency
  • 65. Longtail Latencies Consider a system where each service typically responds in 10ms but with a 99th percentile latency of one second
  • 66. Longtail Latencies Latency Normal vs. Longtail Legend: Normal Longtail 50 40 30 20 10 0 25 50 75 90 99 99.9 Latency(ms) Percentile
  • 67. Longtails really matter ● Latency accumulation ● Not just noise ● Don’t have to be power users ● Real problem
  • 68. Investigating Longtail Latencies ● Narrow the problem ● Isolate in a test environment ● Measure & monitor everything ● Tackle the problem ● Pretty hard job
  • 71. Tolerating Longtail Latencies ● Hedging your bet ● Tied requests
  • 72. Tolerating Longtail Latencies ● Hedging your bet ● Tied requests ● Selectively increase replication factors
  • 73. Tolerating Longtail Latencies ● Hedging your bet ● Tied requests ● Selectively increase replication factors ● Put slow machines on probation
  • 74. Tolerating Longtail Latencies ● Hedging your bet ● Tied requests ● Selectively increase replication factors ● Put slow machines on probation ● Consider ‘good enough’ responses
  • 75. Tolerating Longtail Latencies ● Hedging your bet ● Tied requests ● Selectively increase replication factors ● Put slow machines on probation ● Consider ‘good enough’ responses ● Hardware update
  • 78. Quick Tips ● Monitoring ● Network partitions & Split Brain Resolver
  • 79. Quick Tips ● Monitoring ● Network partitions & Split Brain Resolver ● Blocking
  • 80. Quick Tips ● Monitoring ● Network partitions & Split Brain Resolver ● Blocking ● Too many actor systems
  • 82. MANCHESTER LONDON NEW YORK @petr_zapletal @cakesolutions 347 708 1518 petrz@cakesolutions.net We are hiring http://www.cakesolutions.net/careers
  • 83. References ● http://www.reactivemanifesto.org/ ● http://www.slideshare.net/ktoso/zen-of-akka ● http://eishay.github.io/jvm-serializers/prototype-results-page/ ● http://java-persistence-performance.blogspot.com/2013/08/optimizing-java-serialization-java-vs.html ● https://github.com/romix/akka-kryo-serialization ● http://gotocon.com/dl/goto-chicago-2015/slides/CaitieMcCaffrey_ApplyingTheSagaPattern.pdf ● http://www.grahamlea.com/2016/08/distributed-transactions-microservices-icebergs/ ● http://www.cs.duke.edu/courses/cps296.4/fall13/838-CloudPapers/dean_longtail.pdf ● https://engineering.linkedin.com/performance/who-moved-my-99th-percentile-latency ● http://doc.akka.io/docs/akka/rp-15v09p01/scala/split-brain-resolver.html ● http://manuel.bernhardt.io/2016/08/09/akka-anti-patterns-flat-actor-hierarchies-or-mixing-business-logic-a nd-failure-handling/