Network Deployment and Clustering

Vertigo provides its own cluster management framework on top of the Vert.x cluster. Each Vertigo network will always be deployed in a Vertigo cluster. Vertigo clusters can be deployed either within a single, non-clustered Vert.x instance or across a Vert.x cluster. Clusters provide a logical separation between different applications within a Vert.x cluster and provide additional features such as failover.

Starting a cluster from the command line

Vertigo provides a special Vert.x module for starting a Vertigo cluster agent. To start a cluster node simply start the net.kuujo~vertigo-cluster~0.7.0-beta2 module.

vertx runmod net.kuujo~vertigo-cluster~0.7.0-beta2

The cluster agent accepts a few important configuration options:

  • cluster - the event bus address of the cluster to which the node belongs. Defaults to vertigo
  • group - the HA group to which the node belongs. For simplicity, the Vertigo HA mechanism is modeled on the core Vert.x HA support.
  • address - the event bus address of the node. Defaults to a UUID based string.
  • quorum - the HA quorum size. See the Vert.x HA documentation on quorums.

Starting a cluster programmatically

Vertigo also provides an API for deploying clusters or individual nodes through the Vert.x Container.

Vertigo vertigo = new Vertigo(this);
vertigo.deployCluster("test-cluster", new Handler<AsyncResult<ClusterManager>>() {
  public void handle(AsyncResult<ClusterManager> result) {
    ClusterManager cluster = result.result();
  }
});
Vertigo vertigo = new Vertigo(this);
vertigo.deployCluster("test-cluster", (result) -> {
    ClusterManager cluster = result.result();
});

TODO

TODO

There are several methods for deploying nodes or clusters within the current Vert.x instance.

deployCluster(String address);
deployCluster(String address, Handler<AsyncResult<ClusterManager>> doneHandler);
deployCluster(String address, int nodes);
deployCluster(String address, int nodes, Handler<AsyncResult<ClusterManager>> doneHandler);

TODO

TODO

Users should use this API rather than deploying the ClusterAgent verticle directly because the cluster agent is pluggable. To override the default cluster agent set the system property net.kuujo.vertigo.cluster.

Referencing a cluster programmatically

Network deployments are performed through the ClusterManager API. To get a ClusterManager instance for a running Vertigo cluster call the getCluster method

ClusterManager cluster = vertigo.getCluster("test-cluster");

TODO

TODO

Accessing a cluster through the event bus

The cluster system is built on worker verticles that are accessed over the event bus. Cluster agents expose an event bus API that can be used as an alternative to the Java API. Since all Java interface methods simply wrap the event bus API, you can perform all the same operations as are available through the API over the event bus.

To send a message to a cluster simply send the message to the cluster address.

JsonObject message = new JsonObject()
    .putString("action", "check")
    .putString("network", "test");
vertx.eventBus().send("test-cluster", message, new Handler<Message<JsonObejct>>() {
  public void handle(Message<JsonObject> reply) {
    if (reply.body().getString("status").equals("ok")) {
      boolean isDeployed = reply.body().getBoolean("result");
    }
  }
});
JsonObject message = new JsonObject()
    .putString("action", "check")
    .putString("network", "test");
vertx.eventBus().send("test-cluster", message, (Message<JsonObject> reply) -> {
  if (reply.body().getString("status").equals("ok")) {
    boolean isDeployed = reply.body().getBoolean("result");
  }
});

TODO

TODO

Each message must contain an action indicating the action to perform. Each API method has an action associated with it, and the actions and their arguments will be outline in the following documentation.

Deploying a network

To deploy a network use the deployNetwork methods on the ClusterManager for the cluster to which the network should be deployed.

NetworkConfig network = vertigo.createNetwork("test");
network.addComponent("foo", "foo.js", 2);
network.addComponent("bar", "bar.py", 4);
network.createConnection("foo", "out", "bar", "in");

cluster.deployNetwork(network);

TODO

TODO

When the network is deployed, the cluster will check to determine whether a network of the same name is already running in the cluster. If a network of the same name is running, the given network configuration will be merged with the running network’s configuration and the missing components will be deployed. This is very important to remember. Deployment will not fail if you deploy a network with the same name of a network that already running in the given cluster.

To determine when the network has been successfully deployed pass an AsyncResult handler to the deployNetwork method.

clusterManager.deployNetwork(network, new Handler<AsyncResult<ActiveNetwor>>() {
  public void handle(AsyncResult<ActiveNetwork> result) {
    if (result.succeeded()) {
      ActiveNetwork network = result.result();
    }
  }
});
clusterManager.deployNetwork(network, (result) -> {
  if (result.succeeded()) {
    ActiveNetwork network = result.result();
  }
});

TODO

TODO

You can also deploy the network from the Vertigo API by naming the cluster to which to deploy the network.

vertigo.deployNetwork("test-cluster", network, new Handler<AsyncResult<ActiveNetwor>>() {
  public void handle(AsyncResult<ActiveNetwork> result) {
    if (result.succeeded()) {
      ActiveNetwork network = result.result();
    }
  }
});
vertigo.deployNetwork("test-cluster", network, (result) -> {
  if (result.succeeded()) {
    ActiveNetwork network = result.result();
  }
});

TODO

TODO

Deploying a network from JSON

Networks can be deployed programmatically from JSON configurations. To deploy a network from JSON configuration simply pass the JsonObject configuration in place of the NetworkConfig

JsonObject network = new JsonObject()
    .putString("name", "test")
    .putObject("components", new JsonObject()
        .putObject("foo", new JsonObject()
            .putString("type", "verticle").putString("main", "foo.js")));

cluster.deployNetwork(network);

TODO

TODO

JSON configurations can also be used to deploy networks to a cluster over the event bus. To deploy a network over the event bus send a deploy message to the cluster address with a network type, specifying the network configuration as a JsonObject.

{
  "action": "deploy",
  "type": "network",
  "network": {
    "name": "test",
    "components": {
      "foo": {
        "type": "verticle",
        "main": "foo.js"
      }
    }
  }
}

If successful, the cluster will reply with a status of ok.

vertx.eventBus().send("test-cluster", message, new Handler<Message<JsonObject>>() {
  public void handle(Message<JsonObject> reply) {
    if (reply.body().getString("status").equals("ok")) {
      // Network was successfully deployed!
    }
  }
});
vertx.eventBus().send("test-cluster", message, (Message<JsonObject> reply) -> {
  if (reply.body().getString("status").equals("ok")) {
    // Network was successfully deployed!
  }
});

TODO

TODO

For information on the JSON configuration format see creating networks from json

Undeploying a network

To undeploy a complete network from a cluster call the undeployNetwork method, passing the network name as the first argument.

clusterManager.undeployNetwork("test", new Handler<AsyncResult<Void>>() {
  public void handle(AsyncResult<Void> result) {
    if (result.succeeded()) {
      // Network has been undeployed.
    }
  }
});
clusterManager.undeployNetwork("test", (result) -> {
  if (result.succeeded()) {
    // Network has been undeployed.
  }
});

TODO

TODO

The AsyncResult handler will be called once all the components within the network have been undeployed from the cluster.

The undeployNetwork method also supports a NetworkConfig. The configuration based undeploy method behaves similarly to the deployNetwork method in that the given configuration will be unmerged from the configuration that’s running in the cluster. If the configuration lists all the components that are present in the running network then the network will be completely undeployed, otherwise only the listed components will be undeployed and the network will continue to run. For this reason it is strongly recommended that you undeploy a network by name if you intend to undeploy the entire network.

Like the deployNetwork method, undeployNetwork has an equivalent event bus based action. To undeploy a network over the event bus use the undeploy action, specifying network as the type to undeploy along with the network to undeploy.

{
  "action": "undeploy",
  "type": "network",
  "network": "test"
}

The network field can also contain a JSON configuration to undeploy. If the undeployment is successful, the cluster will reply with a status of ok.

JsonObject message = new JsonObject()
  .putString("action", "undeploy")
  .putString("type", "network")
  .putString("network", "test");
vertx.eventBus().send("test-cluster", message, new Handler<Message<JsonObject>>() {
  public void handle(Message<JsonObject> reply) {
    if (reply.body().getString("status").equals("ok")) {
      // Network was successfully undeployed!
    }
  }
});
JsonObject message = new JsonObject()
  .putString("action", "undeploy")
  .putString("type", "network")
  .putString("network", "test");
vertx.eventBus().send("test-cluster", message, (Message<JsonObject> reply) -> {
  if (reply.body().getString("status").equals("ok")) {
    // Network was successfully undeployed!
  }
});

TODO

TODO

Checking if a network is deployed

To check if a network is deployed in the cluster use the isDeployed method.

cluster.isDeployed("test", new Handler<AsyncResult<Boolean>>() {
  public void handle(AsyncResult<Boolean> result) {
    if (result.succeeded()) {
      boolean deployed = result.result(); // Whether the network is deployed.
    }
  }
});
cluster.isDeployed("test", (result) -> {
  if (result.succeeded()) {
    boolean deployed = result.result(); // Whether the network is deployed.
  }
});

TODO

TODO

When checking if a network is deployed, a check message will be sent to the cluster along with the name of the network to check. If the network’s configuration is available in the cluster then the network will be considered deployed. This is the same check that the cluster uses to determine whether a network is already deployed when deploying a new network configuration.

To check whether a network is deployed directly over the event bus, send a check message to the cluster specifying a network type along with the network name.

{
  "action": "check",
  "type": "network",
  "network": "test"
}

Send the check message to the cluster event bus address. If successful, the cluster will reply with a boolean result indicating whether the network is deployed in the cluster.

JsonObject message = new JsonObject()
  .putString("action", "check")
  .putString("type", "network")
  .putString("network", "test");
vertx.eventBus().send("test-cluster", message, new Handler<Message<JsonObject>>() {
  public void handle(Message<JsonObject> reply) {
    if (reply.body().getString("status").equals("ok")) {
      boolean deployed = reply.body().getBoolean("result");
    }
  }
});
JsonObject message = new JsonObject()
  .putString("action", "check")
  .putString("type", "network")
  .putString("network", "test");
vertx.eventBus().send("test-cluster", message, (Message<JsonObject> reply) -> {
  if (reply.body().getString("status").equals("ok")) {
    boolean deployed = reply.body().getBoolean("result");
  }
});

TODO

TODO

Listing networks running in a cluster

To list the networks running in a cluster call the getNetworks method.

clusterManager.getNetworks(new Handler<AsyncResult<Collection<ActiveNetwork>>>() {
  public void handle(AsyncResult<ActiveNetwork> result) {
    ActiveNetwork network = result.result();
  }
});
clusterManager.getNetworks((result) -> {
  ActiveNetwork network = result.result();
});

TODO

TODO

Note that the method returns an ActiveNetwork. The active network can be used to reconfigure the running network, but more on that later. The current network configuration can be retrieved from the ActiveNetwork by calling the getConfig method.

NetworkConfig config = network.getConfig();

TODO

TODO

To list the networks running in the cluster over the event bus, use the list action.

{ “action”: “list” }

If successful, the cluster will reply with a result containing an array of configuration objects for each network running in the cluster.

JsonObject message = new JsonObject()
  .putStrign("action", "list");
vertx.eventBus().send("test-cluster", message, new Handler<Message<JsonObject>>() {
  public void handle(Message<JsonObject> reply) {
    if (reply.body().getString("status").equals("ok")) {
      JsonArray networks = reply.body().getArray("result");
    }
  }
});
JsonObject message = new JsonObject()
  .putStrign("action", "list");
vertx.eventBus().send("test-cluster", message, (Message<JsonObject> reply) -> {
  if (reply.body().getString("status").equals("ok")) {
    JsonArray networks = reply.body().getArray("result");
  }
});

TODO

TODO

Deploying a bare network

Vertigo networks can be reconfigured after deployment, so sometimes it’s useful to deploy an empty network with no components or connections.

clusterManager.deployNetwork("test", new Handler<AsyncResult<ActiveNetwork>>() {
  public void handle(AsyncResult<ActiveNetwork> result) {
    ActiveNetwork network = result.result();
  }
});
clusterManager.deployNetwork("test", (result) -> {
  ActiveNetwork network = result.result();
});

TODO

TODO

When a bare network is deployed, Vertigo simply deploys a network manager verticle with no components. Once the network is reconfigured, the manager will automatically update the network with any new components.

To deploy a bare network over the event bus, pass a String network name in the network field rather than a JSON network configuration.

JsonObject message = new JsonObject()
  .putString("action", "deploy")
  .putString("type", "network")
  .putString("network", "test");
vertx.eventBus().send("test-cluster", message, new Handler<Message<JsonObject>>() {
  public void handle(Message<JsonObject> reply) {
    if (reply.body().getString("status").equals("ok")) {
      // Network was successfully deployed!
    }
  }
});
JsonObject message = new JsonObject()
  .putString("action", "deploy")
  .putString("type", "network")
  .putString("network", "test");
vertx.eventBus().send("test-cluster", message, (Message<JsonObject> reply) -> {
  if (reply.body().getString("status").equals("ok")) {
    // Network was successfully deployed!
  }
});

TODO

TODO

Reconfiguring a network

Vertigo provides several methods to reconfigure a network after it has been deployed. After a network is deployed users can add or remove components or connections from the network. To reconfigure a running network simply deploy or undeploy a network configuration of the same name.

// Create and deploy a two component network.
NetworkConfig network = vertigo.createNetwork("test");
network.addComponent("foo", "foo.js", 2);
network.addComponent("bar", "bar.py", 4);

vertigo.deployNetwork("test-cluster", network, new Handler<AsyncResult<ActiveNetwork>>() {
  public void handle(AsyncResult<ActiveNetwork> result) {
    // Create and deploy a connection between the two components.
    NetworkConfig network = vertigo.createNetwork("test");
    network.createConnection("foo", "out", "bar", "in");
    vertigo.deployNetwork("test-cluster", network);
  }
});

TODO

TODO

When a network is deployed, the cluster will check to see if any other networks of the same name are already deployed. If a network of the same name is deployed then the new configuration will be merged with the running configuration. Similarly, when undeploying a network from configuration, the cluster will undeploy only the components and connections listed in a connection. The network will only be completely undeployed if the configuration lists all the components deployed in the network.

Vertigo queues configuration changes internally to ensure that only one configuration change can occur at any given time. So if you separately deploy two connections, the second connection will not be added to the network until the first has been added and connected on all relevant components. To deploy more than one component or connection to a running network simultaneously just list them in the same configuration.

Just as networks can be deployed and undeployed over the event bus, they can also be reconfigured by sending deploy and undeploy messages to the cluster.

Working with active networks

Vertigo provides a special API for reconfiguring running networks known as the active network. The ActiveNetwork API mimics the network configuration API, except changes to an ActiveNetwork instance will be immediately deployed to the running network in the appropriate cluster.

To load an active network you can call getNetwork on a cluster.

clusterManager.getNetwork("test", new Handler<AsyncResult<ActiveNetwork>>() {
  public void handle(AsyncResult<ActiveNetwork> result) {
    ActiveNetwork network = result.result();
    network.createConnection("foo", "out", "bar", "in");
  }
});
clusterManager.getNetwork("test", (result) -> {
  ActiveNetwork network = result.result();
  network.createConnection("foo", "out", "bar", "in");
});

TODO

TODO

The active network API also supports AsyncResult handlers so you can determine when the network has been updated with the new configuration.

network.createConnection("foo", "out", "bar", "in", new Handler<AsyncResult<ActiveNetwork>>() {
  public void handle(AsyncResult<ActiveNetwork> result) {
    // Connection has been added and connected.
  }
});
network.createConnection("foo", "out", "bar", "in", (result) -> {
  // Connection has been added and connected.
});

TODO

TODO

Each ActiveNetwork also contains an internal NetworkConfig which can be retrieved by the getConfig method.

NetworkConfig config = network.getConfig();

TODO

TODO

The active network’s internal NetworkConfig will be automatically updated when the running network configuration is updated.

Deploying a network from the command line

Vertigo provides a special facility for deploying networks from json configuration files. This feature is implemented as a Vert.x language module, so the network deployer must be first added to your langs.properties file.

network=net.kuujo~vertigo-deployer~0.7.0-beta2:net.kuujo.vertigo.NetworkFactory
.network=network

You can replace the given extension with anything that works for you. Once the language module has been configured, simply run a network configuration file like any other Vert.x verticle.

vertx run my_network.network

The NetworkFactory will construct the network from the json configuration file and deploy the network to the available cluster.