MaxiTaxi is a very simple application:
- Taxis send their location information to MaxiTaxi.
- Customers can order a taxi and use it to get from A to B.
The system will track:
- The last known position of each taxi.
- Whether a taxi is occupied or not.
The following operations will be supported:
- Update the location of a taxi.
- Search for a nearby taxi that is unoccupied.
- Enter a taxi.
- Leave a taxi.
The tutorial is split into 4 branches:
exercise_1exercise_2exercise_3exercise_4
You can start with exercise_1. If you have completed the exercises, then you can continue in that branch with your own solutions, or you can choose to switch to the exercise_2 branch to continue.
The topics covered are:
- libcluster & :rpc
- Distributed location database
- Horde
- Horde partition tolerance
Install libcluster in the application.
Configure libcluster using the guide in the README (Cluster.Strategy.Epmd) to connect nodes maxi1@127.0.0.1 and maxi2@127.0.0.1.
Start the nodes:
iex --name maxi1@127.0.0.1 -S mix
iex --name maxi2@127.0.0.1 -S mix
Confirm that the nodes are connected:
iex(maxi1@127.0.0.1)1> Node.list()
[:"maxi2@127.0.0.1"]
We will distribute the location database to all nodes in the cluster. We will use :rpc.call/4 for this.
- Send updates to all nodes in the cluster using
:rpc.call/4. - Implement a TTL of 2s on updates to prevent stale information from being served (in case of a netsplit for example).
Use send/2 instead of :rpc.call/4. This will help us avoid bottlenecks in :rpc.
Reminder: {name, node}.
Now we have a "distributed location database", but there is no way for nodes to recover if there is a conflict.
- Use
delta_crdtto make the database eventually consistent.
Note: information on nodes can still be out of date, but after a netsplit the database will globally converge.
A taxi can be entered and exited, but we can't allow more than one customer to enter a taxi.
We will use Horde (docs) to distribute taxi processes among the nodes in the cluster. We will register and access the taxi processes using Horde.Registry. Horde.Registry will also keep them unique.
Horde.DynamicSupervisor will ensure that if a node goes down, that the taxi processes are restarted on another node.
- start taxi state processes using Horde.DynamicSupervisor
- register processes with Horde.Registry