ming, robust server deployments include an external “nanny” that will
monitor the running operating system
process and restart it if it fails. The restarted process reinitializes itself by
reading its persistent state from disk
and then resumes running. Any pending operations and volatile state will
be lost, but assuming that the persistent state isn’t irreparably corrupted,
the service can resume.
The Erlang version of a nanny is
the supervisor behaviour. A supervisor process spawns a set of child processes and links to them so it will be
informed if they fail. A supervisor uses
an ini-tialization callback to specify
a strategy and a list of child specifications. A child specification gives
instructions on how to launch a new
child. The strategy tells the supervisor
what to do if one of its children dies:
restart that child, restart all children,
or several other possibilities. If the
child died from a persistent condition
rather than a bad command or a rare
heisenbug, then the restarted child
will just fail again. To avoid looping
forever, the supervisor’s strategy also
gives a maximum rate of restarting. If
restarts exceed this rate, the supervisor
itself will fail.
Children can be normal behaviour-running processes, or they can be supervisors themselves, giving rise to a
tree structure of supervision. If a restart fails to clear an error, then it will
trigger a supervisor subtree failure, resulting in a restart with an even wider
scope. At the root of the supervision
tree, an application can choose the
overall strategy, such as retrying forever, quitting, or possibly restarting the
Erlang virtual machine.
Since linkage is bidirectional, a
failing server will notify or fail the
children under it. Ephemeral worker
processes are usually spawned linked
to their long-lived parent. If the parent
fails, the workers automatically fail,
too. This linking prevents uncollected
workers from accumulating in the system. In a properly written Erlang application, all processes are linked into
the supervision tree so that a top-level
supervision restart can clean up all
running processes.
In this way, a concurrent Erlang
application vulnerable to occasional
deadlocks, starvations, or infinite
With the increasing
importance
of concurrent
programming,
erlang is seeing
growing interest
and adoption.
indeed, erlang
is branded as a
“concurrency-
oriented” language.
loops can still work robustly in the
field unattended.
implementation, Performance,
and scalability
Erlang’s concurrency is built upon the
simple primitives of process spawning and message passing, and its
programming style is built on the assumption that these primitives have
a low overhead. The number of processes must scale as well—imagine
how constrained object-oriented programming would be if there could be
no more than a few hundred objects in
the system.
For Erlang to be portable, it cannot
assume that its host operating system
has fast interprocess communication
and context switching or allows a truly
scalable number of schedulable activities in the kernel. Therefore, the Erlang
emulator (virtual machine) takes care
of scheduling, memory management,
and message passing at the user level.
An Erlang instance is a single operating-system process with multiple
operating-system threads executing in
it, possibly scheduled across multiple
processors or cores. These threads
execute a user-level scheduler to run
Erlang processes. A scheduled process will run until it blocks or until its
time slice runs out. Since the process
is running Erlang code, the emulator
can arrange for the scheduling slice to
end at a time when the process context
is minimal, minimizing the context
switch time.
Each process has a small, dedicated memory area for its heap and
stack. A two-generation copying collector reclaims storage, and the memory area may grow over time. The size
starts small—a few hundred machine
words—but can grow to gigabytes. The
Erlang process stack is separate from
the C runtime stack in the emulator
and has no minimal size or required
granularity. This lets processes be
lightweight.
By default, the Erlang emulator
interprets the intermediate code produced by the compiler. Many substantial Erlang programs can run
sufficiently fast without using the na-tive-code compiler. This is because Erlang is a high-level language and deals
with large, abstract objects. When running, even the interpreter spends most