Skip to content

Instantly share code, notes, and snippets.

@arosien
Created January 20, 2010 02:35
Show Gist options
  • Save arosien/281536 to your computer and use it in GitHub Desktop.
Save arosien/281536 to your computer and use it in GitHub Desktop.
h1. Using Norbert for cluster management
h2. What is a cluster?
In Norbert parlance, a cluster is a set of Nodes with a given name. A Node is a host, port and list of partitions for which the node can handle requests. The set of member Nodes in a given cluster is centrally stored in ZooKeeper. Additionally, a Node can advertise that it is available to process requests. In general, a Node can be in one of three states:
[arosien: Most people don't know the word 'parlance'. I'd say 'In Norbert, a cluster...'.]
[arosien: So Nodes have a name, and Nodes with the same name are a Cluster? It may be easier to understand if a Node has a clusterName and all nodes with the same clusterName are the de-facto Cluster.]
[arosien: What are partitions? How are they represented? What's an example of a partition?]
[arosien: I'd use bullet points for the properties of a Node.]
1. A member of the cluster, but not advertised as available. In this state the other nodes in the cluster know the node exists, but should not attempt to send it traffic.
2. Not a member of the cluster, but available. In this state, the node can handle requests, but it is unknown to the other nodes in the cluster.
3. A member of the cluster and available. In this state the node is known in the cluster and it should be sent traffic.
Number 1 is most commonly the case that an administrator has specified the node in the cluster metadata, but the node is currently offline. Number 2 is useful when the node is online, but for whatever reason, an administrator does not want it to receive traffic.
h2. Defining the cluster
The easiest way to define a cluster is to use the NorbertNetworkClientMain command line program. At the prompt you can type
* nodes - lists all the nodes in the cluster
* join - adds a new node to the cluster
* leave - removes a node from the cluster
[arosien: Why do I have to use this program? Is it because it is defining state in zk? I'd like to know. I also would want to know the relevant classes to do this in my own code.]
h2. Interacting with the cluster
Norbert provides two ways to interact with the cluster.
1. The Cluster trait provides methods for retrieving the current data about the cluster.
2. The ClusterListener notification system allows you to register a ClusterListener with the cluster. The cluster will then send notifications to your ClusterListeners whenever the state of the cluster changes.
h2. Mapping an id to a Node
If your cluster nodes are partitioned you need a way to map the id of an entity in your application to the Node that can handle requests for that id. Norbert provides a RouterFactory trait which your application can extend to provide that mapping. Whenever the cluster topology changes, the cluster will call newRouter on your RouterFactory with the list of currently available nodes. The returned Router can then be retrieved from the Cluster instance or, if you are using the ClusterListener notification system, the Router is sent in the notifications. If using the Scala API, the id mapped to a node can be of any type, the RouterFactoryComponent uses an abstract type to define Router. The Java API is limited to using an int as an id. Norbert comes with a ConsistentHashRouterFactory out of the box.
h2. Writing the code - the Scala version
Whether you are a consumer or a member of the cluster, you connect to the cluster in the same way.
object NorbertClient {
def main(args: Array[String]) {
object ComponentRegistry extends {
val zooKeeperSessionTimeout = ClusterDefaults.ZOOKEEPER_SESSION_TIMEOUT
val clusterDisconnectTimeout = ClusterDefaults.CLUSTER_DISCONNECT_TIMEOUT
val clusterName = args[0]
val zooKeeperUrls = args[1]
} with DefaultClusterComponent { (1)
type Id = Int (2)
val routerFactory = new MyRouterFactoryImplementation
}
import ComponentRegistry.cluster
cluster.start (3)
cluster.awaitConnectionUninterruptibly (4)
cluster.nodes (5)
cluster.router
cluster.addListener(new MyClusterListener) (6)
cluster.markNodeAvailable(argv[2].toInt) (7)
} }
1. Norbert uses the Cake Pattern for dependency injection and this block passes in the initialization parameters and wires up Norbert.
2. (Optional) If you are using Norbert's routing facility you define your RouterFactory here. If you are using the Cake Pattern for your own application, you could wire up your components here as well.
3. Before using it, you must call start on the cluster instance.
4. Finally, you wait for the cluster connection to be established.
5. At this point, the cluster is usable and you can retrieve the list of cluster nodes, the current router instance, etc.
6. Alternatively, instead of steps 4 and 5 above, you can register ClusterListeners with the cluster and they will be sent notifications when the state of the cluster changes.
7. (Optional) If you are a member of the cluster, you want to advertise that you are available to receive traffic.
h2. Writing the code - the Java version
public class NorbertClient {
public static void main(String[] args) {
ClusterConfig config = new ClusterConfig();
config.setClusterName(args[0]);
config.setZooKeeperUrls(args[1]); (1)
config.setRouterFactory(new MyRouterFactoryImplementation()); (2)
ClusterBootstrap bootstrap = new ClusterBootstrap(config); (3)
Cluster cluster = bootstrap.getCluster(); (4)
cluster.awaitConnectionUninterruptibly(); (5)
cluster.getNodes(); (6)
cluster.getRouter();
cluster.addListener(new MyClusterListener()); (7)
cluster.markNodeAvailable(1); (8)
} }
1. The ClusterConfig is a JavaBean which stores the configuration data for a cluster instance.
2. (Optional) If you are using Norbert's routing facility you define your RouterFactory here.
3. The ClusterBootstrap handles initializing and configuring the cluster.
4. A new cluster instance is retrieved from the ClusterBootstrap.
5. Finally, you wait for the cluster connection to be established.
6. At this point, the cluster is usable and you can retrieve the list of cluster nodes, the current router instance, etc.
7. Alternatively, instead of steps 4 and 5 above, you can register ClusterListeners with the cluster and they will be sent notifications when the state of the cluster changes.
8. (Optional) If you are a member of the cluster, you want to advertise that you are available to receive traffic.
[arosien: I like the numbers and the corresponding explanations.]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment