public interface RaftServer
To create a new server, use the server RaftServer.Builder
. Servers require
cluster membership information in order to perform communication. Each server must be provided a local MemberId
to which to bind the internal RaftServerProtocol
and a set of addresses
for other members in the cluster.
PrimitiveService
. The state machine is responsible for maintaining the state with
relation to OperationType.COMMAND
s and
OperationType.QUERY
s submitted to the server by a client. State machines
are provided in a factory to allow servers to transition between stateful and stateless states.
Address address = new Address("123.456.789.0", 5000);
Collection<Address> members = Arrays.asList(new Address("123.456.789.1", 5000), new Address("123.456.789.2", 5000));
RaftServer server = RaftServer.builder(address)
.withStateMachine(MyStateMachine::new)
.build();
Server state machines are responsible for registering OperationType.COMMAND
s which can be
submitted to the cluster. Raft relies upon determinism to ensure consistency throughout the cluster, so it is
imperative that each server in a cluster have the same state machine with the same commands. State machines are
provided to the server as a factory
to allow servers to transition
between stateful and stateless states.
OperationType.COMMAND
s are received by the server, they're written to the Raft
RaftLog
and replicated to other members
of the cluster. By default, the log is stored on disk, but users can override the default RaftStorage
configuration
via RaftServer.Builder.withStorage(RaftStorage)
. Most notably, to configure the storage module to store entries in
memory instead of disk, configure the StorageLevel
.
RaftServer server = RaftServer.builder(address)
.withStateMachine(MyStateMachine::new)
.withStorage(Storage.builder()
.withDirectory(new File("logs"))
.withStorageLevel(StorageLevel.DISK)
.build())
.build();
Servers use the Storage
object to manage the storage of cluster configurations, voting information, and
state machine snapshots in addition to logs. See the RaftStorage
documentation for more information.
bootstrapped
to form a new cluster or
joined
to an existing cluster. The simplest way to bootstrap a new cluster is to bootstrap
a single server to which additional servers can be joined.
CompletableFuture<RaftServer> future = server.bootstrap();
future.thenRun(() -> {
System.out.println("Server bootstrapped!");
});
Alternatively, the bootstrapped cluster can include multiple servers by providing an initial configuration to the
bootstrap(MemberId...)
method on each server. When bootstrapping a multi-node cluster, the bootstrap configuration
must be identical on all servers for safety.
List<Address> cluster = Arrays.asList(
new Address("123.456.789.0", 5000),
new Address("123.456.789.1", 5000),
new Address("123.456.789.2", 5000)
);
CompletableFuture<RaftServer> future = server.bootstrap(cluster);
future.thenRun(() -> {
System.out.println("Cluster bootstrapped");
});
bootstrapped
, often times users need to
add additional servers to the cluster. For example, some users prefer to bootstrap a single-node cluster and
add additional nodes to that server. Servers can join existing bootstrapped clusters using the join(MemberId...)
method. When joining an existing cluster, the server simply needs to specify at least one reachable server in the
existing cluster.
RaftServer server = RaftServer.builder(new Address("123.456.789.3", 5000))
.withTransport(NettyTransport.builder().withThreads(4).build())
.build();
List<Address> cluster = Arrays.asList(
new Address("123.456.789.0", 5000),
new Address("123.456.789.1", 5000),
new Address("123.456.789.2", 5000)
);
CompletableFuture<RaftServer> future = server.join(cluster);
future.thenRun(() -> {
System.out.println("Server joined successfully!");
});
PrimitiveService
,
RaftStorage
Modifier and Type | Interface and Description |
---|---|
static class |
RaftServer.Builder
Builds a single-use Raft server.
|
static class |
RaftServer.Role
Raft server state types.
|
Modifier and Type | Method and Description |
---|---|
void |
addRoleChangeListener(java.util.function.Consumer<RaftServer.Role> listener)
Adds a role change listener.
|
default java.util.concurrent.CompletableFuture<RaftServer> |
bootstrap()
Bootstraps a single-node cluster.
|
java.util.concurrent.CompletableFuture<RaftServer> |
bootstrap(java.util.Collection<MemberId> cluster)
Bootstraps the cluster using the provided cluster configuration.
|
default java.util.concurrent.CompletableFuture<RaftServer> |
bootstrap(MemberId... members)
Bootstraps the cluster using the provided cluster configuration.
|
static RaftServer.Builder |
builder()
Returns a new Raft server builder using the default host:port.
|
static RaftServer.Builder |
builder(MemberId localMemberId)
Returns a new Raft server builder.
|
io.atomix.protocols.raft.cluster.RaftCluster |
cluster()
Returns the server's cluster configuration.
|
java.util.concurrent.CompletableFuture<java.lang.Void> |
compact()
Compacts server logs.
|
RaftServer.Role |
getRole()
Returns the server role.
|
default boolean |
isFollower()
Returns whether the server is a follower.
|
default boolean |
isLeader()
Returns whether the server is the leader.
|
boolean |
isRunning()
Returns a boolean indicating whether the server is running.
|
java.util.concurrent.CompletableFuture<RaftServer> |
join(java.util.Collection<MemberId> members)
Joins the cluster.
|
default java.util.concurrent.CompletableFuture<RaftServer> |
join(MemberId... members)
Joins the cluster.
|
java.util.concurrent.CompletableFuture<java.lang.Void> |
leave()
Leaves the Raft cluster.
|
java.util.concurrent.CompletableFuture<RaftServer> |
listen(java.util.Collection<MemberId> cluster)
Joins the cluster as a passive listener.
|
default java.util.concurrent.CompletableFuture<RaftServer> |
listen(MemberId... cluster)
Joins the cluster as a passive listener.
|
java.lang.String |
name()
Returns the server name.
|
java.util.concurrent.CompletableFuture<RaftServer> |
promote()
Promotes the server to leader if possible.
|
void |
removeRoleChangeListener(java.util.function.Consumer<RaftServer.Role> listener)
Removes a role change listener.
|
java.util.concurrent.CompletableFuture<java.lang.Void> |
shutdown()
Shuts down the server without leaving the Raft cluster.
|
static RaftServer.Builder builder()
The server will be constructed at 0.0.0.0:8700.
static RaftServer.Builder builder(MemberId localMemberId)
The provided MemberId
is the address to which to bind the server being constructed.
localMemberId
- The local node identifier.java.lang.String name()
The server name is provided to the server via the builder configuration
.
The name is used internally to manage the server's on-disk state. Log
,
snapshot
,
and configuration
files stored on disk use
the server name as the prefix.
io.atomix.protocols.raft.cluster.RaftCluster cluster()
The RaftCluster
is representative of the server's current view of the cluster configuration. The first time
the server is started
, the cluster configuration will be initialized using the MemberId
list provided to the server builder
. For persistent
servers, subsequent starts will result in the last known cluster configuration being loaded from disk.
The returned RaftCluster
can be used to modify the state of the cluster to which this server belongs. Note,
however, that users need not explicitly join
or leave
the
cluster since starting and stopping the server results in joining and leaving the cluster respectively.
RaftServer.Role getRole()
The initial state of a Raft server is RaftServer.Role.INACTIVE
. Once the server is started
and
until it is explicitly shutdown, the server will be in one of the active states - RaftServer.Role.PASSIVE
,
RaftServer.Role.FOLLOWER
, RaftServer.Role.CANDIDATE
, or RaftServer.Role.LEADER
.
default boolean isLeader()
default boolean isFollower()
void addRoleChangeListener(java.util.function.Consumer<RaftServer.Role> listener)
listener
- The role change listener to add.void removeRoleChangeListener(java.util.function.Consumer<RaftServer.Role> listener)
listener
- The role change listener to remove.default java.util.concurrent.CompletableFuture<RaftServer> bootstrap()
Bootstrapping a single-node cluster results in the server forming a new cluster to which additional servers can be joined.
Only RaftMember.Type#ACTIVE
members can be included in a bootstrap configuration. If the local server is
not initialized as an active member, it cannot be part of the bootstrap configuration for the cluster.
When the cluster is bootstrapped, the local server will be transitioned into the active state and begin
participating in the Raft consensus algorithm. When the cluster is first bootstrapped, no leader will exist.
The bootstrapped members will elect a leader amongst themselves. Once a cluster has been bootstrapped, additional
members may be joined
to the cluster. In the event that the bootstrapped members cannot
reach a quorum to elect a leader, bootstrap will continue until successful.
It is critical that all servers in a bootstrap configuration be started with the same exact set of members. Bootstrapping multiple servers with different configurations may result in split brain.
The CompletableFuture
returned by this method will be completed once the cluster has been bootstrapped,
a leader has been elected, and the leader has been notified of the local server's client configurations.
default java.util.concurrent.CompletableFuture<RaftServer> bootstrap(MemberId... members)
Bootstrapping the cluster results in a new cluster being formed with the provided configuration. The initial nodes in a cluster must always be bootstrapped. This is necessary to prevent split brain. If the provided configuration is empty, the local server will form a single-node cluster.
Only RaftMember.Type#ACTIVE
members can be included in a bootstrap configuration. If the local server is
not initialized as an active member, it cannot be part of the bootstrap configuration for the cluster.
When the cluster is bootstrapped, the local server will be transitioned into the active state and begin
participating in the Raft consensus algorithm. When the cluster is first bootstrapped, no leader will exist.
The bootstrapped members will elect a leader amongst themselves. Once a cluster has been bootstrapped, additional
members may be joined
to the cluster. In the event that the bootstrapped members cannot
reach a quorum to elect a leader, bootstrap will continue until successful.
It is critical that all servers in a bootstrap configuration be started with the same exact set of members. Bootstrapping multiple servers with different configurations may result in split brain.
The CompletableFuture
returned by this method will be completed once the cluster has been bootstrapped,
a leader has been elected, and the leader has been notified of the local server's client configurations.
members
- The bootstrap cluster configuration.java.util.concurrent.CompletableFuture<RaftServer> bootstrap(java.util.Collection<MemberId> cluster)
Bootstrapping the cluster results in a new cluster being formed with the provided configuration. The initial nodes in a cluster must always be bootstrapped. This is necessary to prevent split brain. If the provided configuration is empty, the local server will form a single-node cluster.
Only RaftMember.Type#ACTIVE
members can be included in a bootstrap configuration. If the local server is
not initialized as an active member, it cannot be part of the bootstrap configuration for the cluster.
When the cluster is bootstrapped, the local server will be transitioned into the active state and begin
participating in the Raft consensus algorithm. When the cluster is first bootstrapped, no leader will exist.
The bootstrapped members will elect a leader amongst themselves. Once a cluster has been bootstrapped, additional
members may be joined
to the cluster. In the event that the bootstrapped members cannot
reach a quorum to elect a leader, bootstrap will continue until successful.
It is critical that all servers in a bootstrap configuration be started with the same exact set of members. Bootstrapping multiple servers with different configurations may result in split brain.
The CompletableFuture
returned by this method will be completed once the cluster has been bootstrapped,
a leader has been elected, and the leader has been notified of the local server's client configurations.
cluster
- The bootstrap cluster configuration.default java.util.concurrent.CompletableFuture<RaftServer> join(MemberId... members)
Joining the cluster results in the local server being added to an existing cluster that has already been bootstrapped. The provided configuration will be used to connect to the existing cluster and submit a join request. Once the server has been added to the existing cluster's configuration, the join operation is complete.
Any type
of server may join a cluster. In order to join a cluster, the provided list of
bootstrapped members must be non-empty and must include at least one active member of the cluster. If no member
in the configuration is reachable, the server will continue to attempt to join the cluster until successful. If
the provided cluster configuration is empty, the returned CompletableFuture
will be completed exceptionally.
When the server joins the cluster, the local server will be transitioned into its initial state as defined by
the configured RaftMember.Type
. Once the server has joined, it will immediately begin participating in
Raft and asynchronous replication according to its configuration.
It's important to note that the provided cluster configuration will only be used the first time the server attempts
to join the cluster. Thereafter, in the event that the server crashes and is restarted by join
ing the cluster
again, the last known configuration will be used assuming the server is configured with persistent storage. Only when
the server leaves the cluster will its configuration and log be reset.
In order to preserve safety during configuration changes, Raft leaders do not allow concurrent configuration
changes. In the event that an existing configuration change (a server joining or leaving the cluster or a
member being promoted
or demoted
) is under way, the local
server will retry attempts to join the cluster until successful. If the server fails to reach the leader,
the join will be retried until successful.
members
- A collection of cluster members to join.java.util.concurrent.CompletableFuture<RaftServer> join(java.util.Collection<MemberId> members)
Joining the cluster results in the local server being added to an existing cluster that has already been bootstrapped. The provided configuration will be used to connect to the existing cluster and submit a join request. Once the server has been added to the existing cluster's configuration, the join operation is complete.
Any type
of server may join a cluster. In order to join a cluster, the provided list of
bootstrapped members must be non-empty and must include at least one active member of the cluster. If no member
in the configuration is reachable, the server will continue to attempt to join the cluster until successful. If
the provided cluster configuration is empty, the returned CompletableFuture
will be completed exceptionally.
When the server joins the cluster, the local server will be transitioned into its initial state as defined by
the configured RaftMember.Type
. Once the server has joined, it will immediately begin participating in
Raft and asynchronous replication according to its configuration.
It's important to note that the provided cluster configuration will only be used the first time the server attempts
to join the cluster. Thereafter, in the event that the server crashes and is restarted by join
ing the cluster
again, the last known configuration will be used assuming the server is configured with persistent storage. Only when
the server leaves the cluster will its configuration and log be reset.
In order to preserve safety during configuration changes, Raft leaders do not allow concurrent configuration
changes. In the event that an existing configuration change (a server joining or leaving the cluster or a
member being promoted
or demoted
) is under way, the local
server will retry attempts to join the cluster until successful. If the server fails to reach the leader,
the join will be retried until successful.
members
- A collection of cluster members to join.default java.util.concurrent.CompletableFuture<RaftServer> listen(MemberId... cluster)
cluster
- A collection of cluster members to join.java.util.concurrent.CompletableFuture<RaftServer> listen(java.util.Collection<MemberId> cluster)
cluster
- A collection of cluster members to join.java.util.concurrent.CompletableFuture<RaftServer> promote()
java.util.concurrent.CompletableFuture<java.lang.Void> compact()
boolean isRunning()
java.util.concurrent.CompletableFuture<java.lang.Void> shutdown()
java.util.concurrent.CompletableFuture<java.lang.Void> leave()
Copyright © 2013-2019. All Rights Reserved.