Internals View Source
Node Authority
In Syn, every node is the authority in terms of the processes that run on it. This means that all register / unregister / join / leave operations for a specific process are routed to the syn process (registry, pg) that runs on the specific process' node.
It is then the responsibility of this node to communicate the operation results and propagate them to the other nodes.
This serializes per node operations and allows keeping per node consistency.
Scope Subclusters
Syn implement Scopes, which are a way to create namespaced, logical overlay networks running on top of the Erlang distribution cluster. Nodes that belong to the same Scope will form a "subcluster": they will synchronize data between themselves, and themselves only.
Note that all of the data related to a Scope will be replicated to every node of a subcluster, so that every node has a quick read access to it.
Scope processes
When you add a node to a scope (see add_node_to_scopes/1
) i.e. users
,
the following happens:
2 new
gen_server
processes get created (aka "scope processes"), in the given example namedsyn_registry_users
(for registry) andsyn_pg_users
(for process groups).4 new ETS tables get created:
syn_registry_by_name_users
(of typeset
).syn_registry_by_pid_users
(of typebag
).syn_pg_by_name_users
(of typeordered_set
).syn_pg_by_pid_users
(of typeordered_set
).
These tables are owned by the
syn_backbone
process, so that if the related scope processes were to crash the data is not lost. In such case, upon respawn the scope process purges the data of all remote nodes, rebuilds the monitors for the local processes that are still alive and removes from the tables the ones that died meanwhile. The remote data will then get synchronized again.
The 2 newly created scope processes each join a subcluster (one for registry, one for process groups) with the other processes in the Erlang distributed cluster that handle the same Scope (which have the same name).
Subcluster protocol
Joining
- Just after initialization, every scope process tries to send a discovery message in format
{'3.0', discover, self()}
to every process with the same name running on all the nodes in the Erlang cluster. - Scope processes monitor node events, so when a new node joins the cluster the same discovery message is sent to the new node.
- When a scope process receives the discovery message, it:
- Replies with its local data with an ack message in format
{'3.0', ack_sync, self(), LocalData}
. - Starts monitoring the remote scope node process.
- Adds the remote node to the list of the subcluster nodes.
- Replies with its local data with an ack message in format
- The scope process that receives the
ack_sync
message:- Stores the received data of the remote node.
- If it's an unknown node, it:
- Starts monitoring the remote scope node process.
- Sends it its local data with another ack message.
- Adds the remote node to the list of the subcluster nodes.
Leaving
- When a scope process of a remote node dies, all the other scope processes are notified because they were monitoring it.
- The data related to the remote node that left the subcluster is removed locally on every node.