diff --git a/akka-docs/general/actor-systems.rst b/akka-docs/general/actor-systems.rst new file mode 100644 index 0000000000..834eb94d2c --- /dev/null +++ b/akka-docs/general/actor-systems.rst @@ -0,0 +1,114 @@ +.. _actor-systems: + +Actor Systems +============= + +Actors are objects which encapsulate state and behavior, they communicate +exclusively by exchanging messages which are placed into the recipient’s +mailbox. In a sense, actors are the most strigent form of object-oriented +programming, but it serves better to view them as persons: while modeling a +solution with actors, envision a group of people and assign sub-tasks to them, +arrange their functions into an organizational structure and think about how to +escalate failure (all with the benefit of not actually dealing with people, +which means that we need not concern ourselves with their emotional state or +moral issues). The result can then serve as a mental scaffolding for building +the software implementation. + +Hierarchical Structure +---------------------- + +Like in an economic organization, actors naturally form hierarchies. One actor, +which is to oversee a certain function in the program might want to split up +its task into smaller, more manageable pieces. For this purpose it starts child +actors which it supervises. While the details of supervision are explained +:ref:`here `, we shall concentrate on the underlying concepts in +this section. The only prerequisite is to know that each actor has exactly one +supervisor, which is the actor which created it. + +The quintessential feature of actor systems is that tasks are split up and +delegated until they become small enough to be handled in one piece. In doing +so, not only is the task itself clearly structured, but the resulting actors +can be reasoned about in terms of which messages they should process, how they +should react nominally and how failure should be handled. If one actor does not +have the means for dealing with a certain situation, it sends a corresponding +failure message to its supervisor, asking for help. The recursive structure +then allows to handle failure at the right level. + +Compare this to layered software design which easily devolves into defensive +programming with the aim of not leaking any failure out: if the problem is +communicated to the right person, a better solution can be found than if +trying to keep everything “under the carpet”. + +Now, the difficulty in designing such a system is how to decide who should +supervise what. There is of course no single best solution, but there are a few +guide lines which might be helpful: + + - If one actor manages the work another actor is doing, e.g. by passing on + sub-tasks, then the manager should supervise the child. The reason is that + the manager knows which kind of failures are expected and how to handle + them. + + - If one actor carries very important data (i.e. its state shall not be lost + if avoidable), this actor should source out any possibly dangerous sub-tasks + to children it supervises and handle failures of these children as + appropriate. Depending on the nature of the requests, it may be best to + create a new child for each request, which simplifies state management for + collecting the replies. This is known as the “Error Kernel Pattern” from + Erlang. + + - If one actor depends on another actor for carrying out its duty, it should + watch that other actor’s liveness and act upon receiving a termination + notice. This is different from supervision, as the watching party has no + influence on the supervision strategy, and it should be noted that a + functional dependency alone is not a criterion for deciding where to place a + certain child actor in the hierarchy. + +There are of course always exceptions to these rules, but no matter whether you +follow the rules or break them, you should always have a reason. + +Configuration Container +----------------------- + +The actor system as a collaborating ensemble of actors is the natural unit for +managing shared facilities like scheduling services, configuration, logging, +etc. Several actor systems with different configuration may co-exist within the +same JVM without problems, there is no global shared state within Akka itself. +Couple this with the transparent communication between actor systems—within one +node or across a network connection—to see that actor systems themselves can be +used as building blocks in a functional hierarchy. + +Actor Best Practices +-------------------- + +#. Actors should be like nice co-workers: do their job efficiently without + bothering everyone else needlessly and avoid hogging resources. Translated + to programming this means to process events and generate responses (or more + requests) in an event-driven manner. Actors should not block (i.e. passively + wait while occupying a Thread) on some external entity, which might be a + lock, a network socket, etc. The blocking operations should be done in some + special-cased thread which sends messages to the actors which shall act on + them. + +#. Do not pass between actors mutable objects which you actually mutate. In + order to ensure that, prefer immutable messages. If the encapsulation of + actors is broken by exposing their mutable state to the outside, you are + back in normal Java concurrency land with all the drawbacks. + +#. Actors are made to be containers for behavior and state, embracing this + means to not routinely send behavior within messages (which may be tempting + using Scala closures). One of the risks is to accidentally share mutable + state between actors, and this violation of the actor model unfortunately + breaks all the properties which make programming in actors such a nice + experience. + +What you should not concern yourself with +----------------------------------------- + +An actor system manages the resources it is configured to use in order to run +the actors which it contains. There may be millions of actors within one such +system, after all the mantra is to view them as abundant and they weigh in at +an overhead of only roughly 300 bytes per instance. Naturally, the exact order +in which messages are processed in large systems is not controllable by the +application author, but this is also not intended. Take a step back and relax +while Akka does the heavy lifting under the hood. + diff --git a/akka-docs/general/actors.rst b/akka-docs/general/actors.rst new file mode 100644 index 0000000000..5044ecf21a --- /dev/null +++ b/akka-docs/general/actors.rst @@ -0,0 +1,142 @@ +.. _actors-general: + +What is an Actor? +================= + +The previous section about :ref:`actor-systems` explained how actors form +hierarchies and are the smallest unit when building an application. This +section looks at one such actor in isolation, explaining the concepts you +encounter while implementing it. For more an in depth reference with all the +details please refer to :ref:`actors-scala` and :ref:`untyped-actors-java`. + +An actor is a container for `State`_, `Behavior`_, a `Mailbox`_, `Children`_ +and a `Fault Handling Strategy`_. All of this is encapsulated behind an `Actor +Reference`_. Finally, this happens `When and Actor Terminates`_. + +Actor Reference +--------------- + +As detailed below, an actor object needs to be shielded from the outside in +order to benefit from the actor model. Therefore, actors are represented to the +outside using actor references, which are objects that can be passed around +freely and without restriction. This split into inner and outer object enables +transparency for all the desired operations: restarting an actor without +needing to update references elsewhere, placing the actual actor object on +remote hosts, sending messages to actors in completely different applications. +But the most important aspect is that it is not possible to look inside an +actor and get hold of its state from the outside, unless the actor unwisely +publishes this information itself. + +State +----- + +Actor objects will typically contain some variables which reflect possible +states the actor may be in. This can be an explicit state machine (e.g. using +the :ref:`fsm` module), or it could be a counter, set of listeners, pending +requests, etc. These data are what make an actor valuable, and they must be +protected from corruption by other actors. The good news is that Akka actors +conceptually each have their own light-weight thread, which is completely +shielded from the rest of the system. This means that instead of having to +synchronize access using locks you can just write your actor code without +worrying about concurrency at all. + +Behind the scenes Akka will run sets of actors on sets of real threads, where +typically many actors share one thread, and subsequent invocations of one actor +may end up being processed on different threads. Akka ensures that this +implementation detail does not affect the single-threadedness of handling the +actor’s state. + +Because the internal state is vital to an actor’s operations, having +inconsistent state is fatal. Thus, when the actor fails and is restarted by its +supervisor, the state will be created from scratch, like upon first creating +the actor. This is to enable the ability of self-healing of the system. + +Behavior +-------- + +Every time a message is processed, it is matched against the current behavior +of the actor. Behavior means a function which defines the actions to be taken +in reaction to the message at that point in time, say forward a request if the +client is authorized, deny it otherwise. This behavior may change over time, +e.g. because different clients obtain authorization over time, or because the +actor may go into an “out-of-service” mode and later come back. These changes +are achieved by either encoding them in state variables which are read from the +behavior logic, or the function itself may be swapped out at runtime, see the +``become`` and ``unbecome`` operations. However, the initial behavior defined +during construction of the actor object is special in the sense that a restart +of the actor will reset its behavior to this initial one. + +Mailbox +------- + +An actor’s purpose is the processing of messages, and these messages were sent +to the actor from other actors (or from outside the actor system). The piece +which connects sender and receiver is the actor’s mailbox: each actor has +exactly one mailbox to which all senders enqueue their messages. Enqueuing +happens in the time-order of send operations, which means that messages sent +from different actors may not have a defined order at runtime due to the +apparent randomness of distributing actors across threads. Sending multiple +messages to the same target from the same actor, on the other hand, will +enqueue them in the same order. + +There are different mailbox implementations to choose from, the default being a +FIFO: the order of the messages processed by the actor matches the order in +which they were enqueued. This is usually a good default, but applications may +need to prioritize some messages over others. In this case, a priority mailbox +will enqueue not always at the end but at a position as given by the message +priority, which might even be at the front. While using such a queue, the order +of messages processed will naturally be defined by the queue’s algorithm and in +general not be FIFO. + +An important feature in which Akka differs from some other actor model +implementations is that the current behavior must always handle the next +dequeued message, there is no scanning the mailbox for the next matching one. +Failure to handle a message will typically be treated as a failure, unless this +behavior is overridden. + +Children +-------- + +Each actor is potentially a supervisor: if it creates children for delegating +sub-tasks, it will automatically supervise them. The list of children is +maintained within the actor’s context and the actor has access to it. +Modifications to the list are done by creating (``context.actorOf(...)``) or +stopping (``context.stop(child)``) children and these actions are reflected +immediately. The actual creation and termination actions happen behind the +scenes in an asynchronous way, so they do not “block” their supervisor. + +Fault Handling Strategy +----------------------- + +The final piece of an actor is its strategy for handling faults of its +children. To keep it simple and robust, this is declared outside of the actor’s +code and has no access to the actor’s state. Fault handling is then done +transparently by Akka, applying one of the strategies described in +:ref:`supervision` for each incoming failure. As this strategy is fundamental +to how an actor system is structured, it cannot be changed once an actor has +been created. + +Considering that there is only one such strategy for each actor, this means +that if different strategies apply to the various children of an actor, the +children should be grouped beneath intermediate supervisors with matching +strategies, preferring once more the structuring of actor systems according to +the splitting of tasks into sub-tasks. + +When an Actor Terminates +------------------------ + +Once an actor terminates, i.e. fails in a way which is not handled by a +restart, stops itself or is stopped by its supervisor, it will free up its +resources, draining all remaining messages from its mailbox into the system’s +“dead letter mailbox”. The mailbox is then replaced within the actor reference +with a that system mailbox, redirecting all new messages “into the drain”. This +is done on a best effort basis, though, so do not rely on it in order to +construct “guaranteed delivery”. + +The reason for not just silently dumping the messages was inspired by our +tests: we register the TestEventListener on the event bus to which the dead +letters are forwarded, and that will log a warning for every dead letter +received—this has been very helpful for deciphering test failures more quickly. +It is conceivable that this feature may also be of use for other purposes. + + diff --git a/akka-docs/general/addressing.rst b/akka-docs/general/addressing.rst index ce59b02e50..e7a644d915 100644 --- a/akka-docs/general/addressing.rst +++ b/akka-docs/general/addressing.rst @@ -2,9 +2,10 @@ Actor References, Paths and Addresses ===================================== This chapter describes how actors are identified and located within a possibly -distributed actor system. It ties into the central idea that actor systems form -intrinsic supervision hierarchies as well as that communication between actors -is transparent with respect to their placement across multiple network nodes. +distributed actor system. It ties into the central idea that +:ref:`actor-systems` form intrinsic supervision hierarchies as well as that +communication between actors is transparent with respect to their placement +across multiple network nodes. What is an Actor Reference? --------------------------- @@ -84,7 +85,7 @@ actors in the hierarchy from the root up. Examples are:: Here, ``akka`` is the default remote protocol for the 2.0 release, and others are pluggable. The interpretation of the host & port part (i.e. ``serv.example.com:5678`` in the example) depends on the transport mechanism -used, but it should abide by the URI structural rules. +used, but it must abide by the URI structural rules. Logical Actor Paths ^^^^^^^^^^^^^^^^^^^ @@ -144,7 +145,7 @@ Creating Actors An actor system is typically started by creating actors above the guardian actor using the :meth:`ActorSystem.actorOf` method and then using :meth:`ActorContext.actorOf` from within the created actors to spawn the actor -tree. These methods return a reference to the newly created actors. Each actor +tree. These methods return a reference to the newly created actor. Each actor has direct access to references for its parent, itself and its children. These references may be sent within messages to other actors, enabling those to reply directly. @@ -152,17 +153,17 @@ directly. Looking up Actors by Concrete Path ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In addition, actor references may be looked up using the -:meth:`ActorSystem.actorFor` method, which returns an (unverified) local, -remote or clustered actor reference. Sending messages to such a reference or -attempting to observe its livelyhood will traverse the actor hierarchy of the -actor system from top to bottom by passing messages from parent to child until -either the target is reached or failure is certain, i.e. a name in the path -does not exist (in practice this process will be optimized using caches, but it -still has added cost compared to using the physical actor path, can for example -to obtained from the sender reference included in replies from that actor). The -messages passed are handled automatically by Akka, so this process is not -visible to client code. +In addition, actor references may be looked up using the +:meth:`ActorSystem.actorFor` method, which returns an (unverified) local, +remote or clustered actor reference. Sending messages to such a reference or +attempting to observe its livelyhood will traverse the actor hierarchy of the +actor system from top to bottom by passing messages from parent to child until +either the target is reached or failure is certain, i.e. a name in the path +does not exist (in practice this process will be optimized using caches, but it +still has added cost compared to using the physical actor path, which can for +example to obtained from the sender reference included in replies from that +actor). The messages passed are handled automatically by Akka, so this process +is not visible to client code. Absolute vs. Relative Paths ``````````````````````````` @@ -177,12 +178,20 @@ example send a message to a specific sibling:: context.actorFor("../brother") ! msg +Absolute paths may of course also be looked up on `context` in the usual way, i.e. + +.. code-block:: scala + + context.actorFor("/user/serviceA") ! msg + +will work as expected. + Querying the Logical Actor Hierarchy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Since the actor system forms a file-system like hierarchy, matching on paths is possible in the same was as supported by Unix shells: you may replace (parts -of) path element names with wildcards (`"*"` and `"?"`) to formulate a +of) path element names with wildcards (`«*»` and `«?»`) to formulate a selection which may match zero or more actual actors. Because the result is not a single actor reference, it has a different type :class:`ActorSelection` and does not support the full set of operations an :class:`ActorRef` does. @@ -261,8 +270,13 @@ other actors are found. The next level consists of the following: those which are used in the implementation of :meth:`ActorRef.ask`. - ``"/remote"`` is an artificial path below which all actors reside whose supervisors are remote actor references + +Future extensions: + - ``"/service"`` is an artificial path below which actors can be presented by means of configuration, i.e. deployed at system start-up or just-in-time - (triggered by look-up) or “mounting” other actors by path—local or remote—to - give them logical names. + (triggered by look-up) +- ``"/alias"`` is an artificial path below which other actors may be “mounted” + (as in the Unix file-system sense) by path—local or remote—to give them + logical names. diff --git a/akka-docs/general/index.rst b/akka-docs/general/index.rst index 945b52a278..f8fcda9de9 100644 --- a/akka-docs/general/index.rst +++ b/akka-docs/general/index.rst @@ -4,8 +4,11 @@ General .. toctree:: :maxdepth: 2 + actor-systems + actors + supervision + addressing + remoting jmm message-send-semantics configuration - addressing - supervision diff --git a/akka-docs/general/remoting.rst b/akka-docs/general/remoting.rst new file mode 100644 index 0000000000..968486a5ba --- /dev/null +++ b/akka-docs/general/remoting.rst @@ -0,0 +1,64 @@ +.. _remoting: + +Transparent Remoting +==================== + +The previous section describes how actor paths are used to make possible +transparent remoting. This special feature deserves some extra explanation, +because it is a term which was used quite differently in the context of +programming languages, platforms and technologies. + +Distributed by Default +---------------------- + +Everything in Akka is designed to work in a distributed setting: all +interactions of actors use purely message passing and everything is +asynchronous. This effort has been undertaken to ensure that all functions are +available equally when running within a single JVM or on a cluster of hundreds +of machines. The key for enabling this is to go from remote to local by way of +optimization instead of trying to go from local to remote by way of +generalization. See `this classic paper +`_ for a detailed +discussion on why the second approach is bound to fail. + +Ways in which Transparency is Broken +------------------------------------ + +What is true of Akka need not be true of the application which uses it, since +designing for distributed execution poses some restrictions on what is +possible. The most obvious one is that all messages sent over the wire must be +serializable. While being a little less obvious this includes closures which +are used as actor factories (i.e. within :class:`Props`) if the actor is to be +created on a remote node. + +Another consequence is that everything needs to be aware of all interactions +being fully asynchronous, which in a computer network might mean that it may +take several minutes for a message to reach its recipient (depending on +configuration). It also means that the probability for a message to be lost is +much higher than within one JVM, where it is close to zero (still: no hard +guarantee!). + +How is Remoting Used? +--------------------- + +We took the idea of transparency to the limit in that there is no API for the +remoting layer of Akka: it is purely driven by configuration. Just write your +application according to the principles outlined in the previous sections, then +specify remote deployment of actor sub-trees in the configuration file. This +way, your application can be scaled out without having to touch the code. + +Marking Points for Scaling Up with Routers +------------------------------------------ + +In addition to being able to run different parts of an actor system on +different nodes of a cluster, it is also possible to scale up onto more cores +by multiplying actor sub-trees which support parallelization (think for example +a search engine processing different queries in parallel). The clones can then +be routed to in different fashions, e.g. round-robin. The only thing necessary +to achieve this is that the developer needs to declare a certain actor as +“withRouter”, the in its stead a router actor will be created which will spawn +up a configurable number of children of the desired type and route to them in +the configured fashion. Once such a router has been declared, its configuration +can be freely overridden from the configuration file, including mixing it with +the transparent remote deployment of (some of) the children. Read more about +this in :ref:`routing`. diff --git a/akka-docs/general/supervision.rst b/akka-docs/general/supervision.rst index 74c95abfc5..2aa9ceba0a 100644 --- a/akka-docs/general/supervision.rst +++ b/akka-docs/general/supervision.rst @@ -1,5 +1,7 @@ -Supervision -=========== +.. _supervision: + +Supervision and Monitoring +========================== This chapter outlines the concept behind supervision, the primitives offered and their semantics. For details on how that translates into real code, please @@ -8,12 +10,13 @@ refer to the corresponding chapters for Scala and Java APIs. What Supervision Means ---------------------- -Supervision describes a dependency relationship between actors: the supervisor -delegates tasks to subordinates and therefore must respond to their failures. -When a subordinate detects a failure (i.e. throws an exception), it suspends -itself and all its subordinates and sends a message to its supervisor, -signaling failure. Depending on the nature of the work to be supervised and -the nature of the failure, the supervisor has four basic choices: +As described in :ref:`actor-systems` supervision describes a dependency +relationship between actors: the supervisor delegates tasks to subordinates and +therefore must respond to their failures. When a subordinate detects a failure +(i.e. throws an exception), it suspends itself and all its subordinates and +sends a message to its supervisor, signaling failure. Depending on the nature +of the work to be supervised and the nature of the failure, the supervisor has +four basic choices: #. Resume the subordinate, keeping its accumulated internal state #. Restart the subordinate, clearing out its accumulated internal state @@ -27,7 +30,8 @@ three: resuming an actor resumes all its subordinates, restarting an actor entails restarting all its subordinates, similarly stopping an actor will also stop all its subordinates. It should be noted that the default behavior of an actor is to stop all its children before restarting, but this can be overridden -using the :meth:`preRestart` hook. +using the :meth:`preRestart` hook; the recursive restart applies to all +children left after this hook has been executed. Each supervisor is configured with a function translating all possible failure causes (i.e. exceptions) into one of the four choices given above; notably, @@ -46,7 +50,7 @@ makes the formation of actor supervision hierarchies explicit and encourages sound design decisions. It should be noted that this also guarantees that actors cannot be orphaned or attached to supervisors from the outside, which might otherwise catch them unawares. In addition, this yields a natural and -clean shutdown procedure for (parts of) actor applications. +clean shutdown procedure for (sub-trees of) actor applications. What Restarting Means --------------------- @@ -90,12 +94,11 @@ it may react to the other actor’s termination, in contrast to supervision whic reacts to failure. Lifecycle monitoring is implemented using a :class:`Terminated` message to be -received by the behavior of the monitoring actor, where the default behavior is -to throw a special :class:`DeathPactException` if not otherwise handled. One -important property is that the message will be delivered irrespective of the -order in which the monitoring request and target’s termination occur, i.e. you -still get the message even if at the time of registration the target is already -dead. +received by the monitoring actor, where the default behavior is to throw a +special :class:`DeathPactException` if not otherwise handled. One important +property is that the message will be delivered irrespective of the order in +which the monitoring request and target’s termination occur, i.e. you still get +the message even if at the time of registration the target is already dead. Monitoring is particularly useful if a supervisor cannot simply restart its children and has to stop them, e.g. in case of errors during actor @@ -104,6 +107,6 @@ them or schedule itself to retry this at a later time. Another common use case is that an actor needs to fail in the absence of an external resource, which may also be one of its own children. If a third party -terminates a child by way of the ``stop()`` method or sending a +terminates a child by way of the ``system.stop(child)`` method or sending a :class:`PoisonPill`, the supervisor might well be affected. diff --git a/akka-docs/scala/fsm.rst b/akka-docs/scala/fsm.rst index 0f9e8eda15..fe64871a91 100644 --- a/akka-docs/scala/fsm.rst +++ b/akka-docs/scala/fsm.rst @@ -1,3 +1,5 @@ +.. _fsm: + ### FSM ###