alldata-coordinator v0.1.1
alldata-coordinator
Stability: 1 - Experimental
Request coordinator module for AllData, a distributed master-less write-once immutable event store database implementing "All Data" part of Lambda Architecture.
Usage
var AllDataCoordinator = require('alldata-coordinator');
var AllDataKeygen = require('alldata-keygen');
var AllDataPeerClient = require('alldata-peer-client-http');
var AllDataPeerServer = require('alldata-peer-server-http');
var AllDataServer = require('alldata-server-http');
var AllDataStorage = require('alldata-storage-leveldb');
var allDataStorage = new AllDataStorage('/data');
var allDataCoordinator = new AllDataCoordinator(allDataStorage);
var allDataServer = new AllDataServer({
hostname: 'localhost',
port: 80
});
var allDataPeerServer = new AllDataPeerServer({
port: 8080
});
var allDataPeerClient = new AllDataPeerClient({
method: "POST",
port: 8080
});
allDataServer.on('put', function (event, callback) {
// request from a client external to the cluster
allDataCoordinator.put(AllDataKeygen.generateKey(), event, callback);
});
allDataPeerServer.on('_put', function (key, event, callback) {
// request from a peer within the cluster
// notice that coordinator is not used here as _put is being coordinated
// by some other node
allDataStorage.put(key, event, callback);
});
allDataCoordinator.on('_put', function (peer, key, event, callback) {
// coordinator determined that a _put should happen to given peer
// but because peer clients can have multiple implementations an event
// is emitted that should be listened to and handed to a peer client
// implementation; peer is opaque to the coordinator but has structure
// known to the peer client, hence the peer client knows to use
// peer.hostname for the _put request
allDataPeerClient._put({hostname: peer.hostname}, key, event, callback);
});
// start external server and peer server
allDataServer.listen(function () {
console.log('HTTP Server listening...');
});
allDataPeerServer.listen(function () {
console.log('HTTP Peer Server listening...');
});Test
npm testOverview
AllDataCoordinator coordinates replication between peer nodes as specified by the replication and zone and region placement policies.
It is worth noting that due to the nature of the kind of data stored in AllData, there is no requirement for consistent hashing. Instead, replicas are selected randomly according with placement policies. This is in contrast to data storage systems with more restrictive placement requirements. This has the advantage that if parts of the cluster are down and some zones or regions are unavailable, it still may be possible to succeed in replication by falling back onto writing replicas located in a different region, different zone, or other nodes in the local zone.
Documentation
AllDataCoordinator
Public API
- new AllDataCoordinator(localStorage, options)
- allDataCoordinator.addPeer(peer, [options])
- allDataCoordinator.dropPeer(peer, [options])
- allDataCoordinator.put(key, event, [commitLevel], callback)
- Event '_put'
new AllDataCoordinator(localStorage, options)
localStorage: Object Instance of AllData storage module local to the AllDataCoordinator.options: Object (Default: undefined)commitLevel: String (Default: "QUORUM") One of:ONE,QUORUM,ALL.ONEmeans that once local storage stored the event, the request will be acknowledged.QUORUMmeans that once majority of replicas stored the event, the request will be acknowledged (notice thatQUORUMforreplicationFactorof 1 is 1).ALLmeans that once all replicas stored the event, the request will be acknowledged.replicationFactor: Integer (Default: 1) Number of replicas (including local one) to create for anyputevent.replicationStrategy: ObjectotherZoneReplicas: Integer (Default: 0) Number of replicas to place explicitly in other zones within the local region.otherRegionReplicas: Integer (Default: 0) Number of replicas to place explicitly in other regions.
Creates a new instance of AllDataCoordinator.
Note that the following must hold:
replicationFactor <=
1 + replicationStrategy.otherRegionReplicas
+ replicationStrategy.otherZoneReplicas;If replicationFactor is less than the total above, coordinator will create replicas in the following order:
- local storage
- other zones
- other regions
- same zone
It is worth highlighting that AllDataCoordinator will attempt to fulfill the replicationFactor over the chosen replicationStrategy. This means that if other zone or other region replicas should be created, but no peers in other zones or regions are known, then peers from the same zone may be selected. If there are not enough peers to satisfy replicationFactor and commitLevel criteria, the put will fail.
For example, given:
replicationFactor = 3;
replicationStrategy.otherZoneReplicas = 2;
replicationStrategy.otherRegionReplicas = 1;the following number of replicas would be created:
- local storage - 1 replica
- other zones - 2 replicas
- other regions - 0 replicas
- same zone - 0 replicas
Here is an example of placing replicas in other zones and other regions. Given:
replicationFactor = 3;
replicationStrategy.otherZoneReplicas = 1;
replicationStrategy.otherRegionReplicas = 1;the following number of replicas would be created:
- local storage - 1 replica
- other zones - 1 replica
- other regions - 1 replica
- same zone - 0 replicas
Here is an example of placing replicas in same zone only. Given:
replicationFactor = 3;
replicationStrategy.otherZoneReplicas = 0;
replicationStrategy.otherRegionReplicas = 0;the following number of replicas would be created:
- local storage - 1 replica
- other zones - 0 replica
- other regions - 0 replicas
- same zone - 2 replicas
If any of the replicas fails to succeed in put operation, the AllDataCoordinator will go into "get it done" mode and attempt to spread out the failed replica to any available peer that hasn't been selected already, so that the replicationFactor is honored.
allDataCoordinator.addPeer(peer, options)
peer: Object Peer to add to coordinator's awareness.id: String Uniquepeeridentifier.
options: Object (Default: {})zone: String (Default: undefined)_ If provided, an identifier in the local region for thezonethepeerbelongs to. Ifzoneis specifiedoptions.regionwill be ignored.region: String (Default: undefined) If provided, an identifier for a remote region thepeerbelongs to. This parameter is ignored ifoptions.zoneis specified.
Adds the peer to AllDataCoordinator's awareness for selection when replicas need to be created.
allDataCoordinator.dropPeer(peer, options)
peer: Object Peer to drop from coordinator's awareness.id: String Uniquepeeridentifier.
options: Object (Default: {})zone: String (Default: undefined)_ If provided, an identifier in the local region for thezonethepeerbelongs to. Ifzoneis specifiedoptions.regionwill be ignored.region: String (Default: undefined) If provided, an identifier for a remote region thepeerbelongs to. This parameter is ignored ifoptions.zoneis specified.
Drops the peer from AllDataCoordinator's awareness so that it is no longer considered for replica placement.
allDataCoordinator.put(key, event, commitLevel, callback)
key: String AllData key generated for theevent.event: Object JavaScript object representation of the event toput.commitLevel: String (Default: AllDataCoordinator default) Commit level for thisputif different fromcommitLevelset for AllDataCoordinator.callback: Functionfunction (error) {}Callback to call on success or failure.
Coordinates the replication of the event according to specified commitLevel, replicationFactor and replicationStrategy.
Event _put
function (peer, key, event callback) {}peer: Object Peer to_puttheeventon.key: String AllData generated event key.event: Object Event to_put.callback: Functionfunction (error) {}
Emitted when AllDataCoordinator determines that a remote _put should happen for given peer. Because peer clients can have multiple implementations, this event is emitted instead of directly calling a specific client implementation. The peer is mostly opaque to the AllDataCoordinator but has structure known to the client. See Usage for an example.
