-
Don’t share mutable state among actors
-
Do not close on the sender
-
Do not close over an actor’s context
-
Do not use the scheduler with the Runnable trait
-
Do not declare one actor within another.
-
Never pass an actor’s this reference into Props
-
Actors do not stop automatically when no longer referenced, every Actor that is created must also explicitly be destroyed. The only simplification is that stopping a parent Actor will also recursively stop all the child Actors that this parent has created.
-
It is always preferable to communicate with other Actors using their ActorRef instead of relying upon ActorSelection. Exceptions are
- sending messages using the At-Least-Once Delivery facility
- initiating first contact with a remote system
- In all other cases ActorRefs can be provided during Actor creation or initialization, passing them from parent to child or introducing Actors by sending their ActorRefs to other Actors within messages.
- sending messages using the At-Least-Once Delivery facility
-
Messages can be any kind of object but have to be immutable. Scala can’t enforce immutability (yet) so this has to be by convention. Primitives like String, Int, Boolean are always immutable. Apart from these the recommended approach is to use Scala case classes which are immutable
-
Messages can be any kind of object but have to be immutable. Scala can’t enforce immutability (yet) so this has to be by convention. Primitives like String, Int, Boolean are always immutable. Apart from these the recommended approach is to use Scala case classes which are immutable
-
Always prefer tell for performance, and only ask if you must.
-
To complete the future with an exception you need send a Failure message to the sender. This is not done automatically when an actor throws an exception while processing a message.
-
When using future callbacks, such as
onComplete
,onSuccess
, andonFailure
, inside actors you need to carefully avoid closing over the containing actor’s reference, i.e. do not call methods or access mutable state on the enclosing actor from within the callback. -
Avoid Context Switching
-
Set the number of thread in the pool to match your cores
I/O
-
Favour non-blocking APIs
-
Be aware of back-pressure
-
Carefully configure timeouts and remember to react to errors
-
If you must use blocking calls, bulkhead them
Memory
- Use bounded mailboxes (
BoundedMailbox
,BoundedPriorityMailbox
,BoundedControlAwareMailbox
)- When mailbox is full, messages go to
DeadLetters
mailbox-push-timeout-time
: how long to wait when mailbox is full- Doesn’t work for distributed Akka systems :(
- When mailbox is full, messages go to
( In distributed systems use real flow control : pull
, push with acks
, etc, works anywhere but more work )
- Use VisualVM to monitor time spent enqueueing messages.
- If your actor behaviour is processing a lot of data, consider using off-heap structures (direct ByteBuffers)
- Memory/GC pressure will make your application die with a whimper, not a bang
Monitor
Record just enough information. Too much slows down the monitored system , too little lets events go unnoticed.
-
Actor creation & destruction
-
Message types , message rates failures and performance at the actor level
-
Queue size at the (local) actor level
-
The number of available and running threads in the ThreadPools
-
Don’t put things that can fail into Actor constructor
- Default supervision that can fail into Actor constructor
- Instead use an Initialize message
Resources
- [Akka in production Evan Chan](https://www.youtube.com/watch?* v=c1heorOM2LE)
- “Tuning and Monitoring Akka” Akka Days Webinar: Day 1
- akka actor’s documentation
- Akka anti-patterns: race conditions