Hi, I am trying to build a custom MasterSlave model. It differs from Helix’s out-of-the-box MasterSlave model in the following ways:
In addition to MASTER, there is a SYNCREPLICA state and ASYNCREPLICA state. For each partition, there will be one MASTER, and a small (R) number of sync-replicas. Master will consider a message to be committed only if it is synchronously replicated to all sync-replicas. (push-model) The async-replicas are run on the remaining nodes, and they will be asynchronously replicating from master (pull-model). The upper-bound for MASTER is 1. The dynamic upper-bound for SYNCREPLICA is “R” (replica count) The dynamic upper-bound for ASYNCREPLICA is “N” (replica count) Here is a snippet of my code: (I am using Helix 0.7.1 and following this documentation: http://helix.apache.org/0.7.1-docs/tutorial_state.html <http://helix.apache.org/0.7.1-docs/tutorial_state.html>) // upper bounds builder.upperBound(States.MASTER.name(), 1); builder.dynamicUpperBound(States.SYNCREPLICA.name(), "R"); builder.dynamicUpperBound(States.ASYNCREPLICA.name(), "N"); With the above code, I am getting the following exception, during the initial configuration of the cluster. Exception in thread "main" org.apache.helix.HelixException: Invalid or unsupported state model definition at org.apache.helix.manager.zk.ZKHelixAdmin.rebalance(ZKHelixAdmin.java:895) at org.apache.helix.manager.zk.ZKHelixAdmin.rebalance(ZKHelixAdmin.java:844) at org.apache.helix.manager.zk.ZKHelixAdmin.rebalance(ZKHelixAdmin.java:824) I saw the same exception with following code too: // upper bounds builder.upperBound(States.MASTER.name(), 1); builder.upperBound(States.SYNCREPLICA.name(), 3); builder.dynamicUpperBound(States.ASYNCREPLICA.name(), "N"); Next, I tried something different. Instead of providing upper-bound to two states, I provided upper-bound to only one state. Here is the code snippet: // upper bounds builder.upperBound(States.MASTER.name(), 1); builder.upperBound(States.SYNCREPLICA.name(), 3); builder.dynamicUpperBound(States.ASYNCREPLICA.name(), "R"); With the above code snippet, the initial configuration/rebalance completed successfully. (3 partitions and 2 replicas) However, when I bring up 5 nodes, I see that few nodes are spinning/toggling between two states for a while, and then settle in one state. But the cluster does not seem to be reaching the ideal state. One node toggled between MASTER<->SYNCREPLICA Another node toggled between SYNCREPLICA<->ASYNCREPLICA, and finally went to OFFLINE—>DROPPED Third node toggled between OFFLINE<->ASYNCREPLICA, before finally settled into ASYNCREPLICA—>SYNCREPLICA—>MASTER After all the 5 nodes settled down, I still did not see any of the nodes in ASYNCREPLICA state. Here is the ExternalView: { "id" : "msshard", "mapFields" : { "msshard_0" : { "MS_instance0" : "MASTER", "MS_instance2" : "SYNCREPLICA" }, "msshard_1" : { "MS_instance1" : "MASTER", "MS_instance3" : "SYNCREPLICA" }, "msshard_2" : { "MS_instance0" : "SYNCREPLICA", "MS_instance4" : "MASTER" } }, "listFields" : { }, "simpleFields" : { "BUCKET_SIZE" : "0" } } I would really appreciate help on this. Here is the complete code for building state. I am wondering if there is any issue in the transitions below that is causing the problem: public static enum States { MASTER, SYNCREPLICA, ASYNCREPLICA, OFFLINE } public static StateModelDefinition buildCustomMasterSlaveModel() { StateModelDefinition.Builder builder = new StateModelDefinition.Builder("CustomMasterSlave"); builder.initialState(States.OFFLINE.name()); // add states builder.addState(States.MASTER.name(), 0); builder.addState(States.SYNCREPLICA.name(), 1); builder.addState(States.ASYNCREPLICA.name(), 2); builder.addState(States.OFFLINE.name(), 3); for (HelixDefinedState state : HelixDefinedState.values()) { builder.addState(state.name()); } // add transitions builder.addTransition(States.SYNCREPLICA.name(), States.MASTER.name(), 1); builder.addTransition(States.ASYNCREPLICA.name(), States.SYNCREPLICA.name(), 2); builder.addTransition(States.OFFLINE.name(), States.ASYNCREPLICA.name(), 3); builder.addTransition(States.MASTER.name(), States.SYNCREPLICA.name(), 4); builder.addTransition(States.SYNCREPLICA.name(), States.ASYNCREPLICA.name(), 4); builder.addTransition(States.ASYNCREPLICA.name(), States.OFFLINE.name(), 4); builder.addTransition(States.OFFLINE.name(), HelixDefinedState.DROPPED.name()); // upper bounds builder.upperBound(States.MASTER.name(), 1); builder.upperBound(States.SYNCREPLICA.name(), 3); builder.dynamicUpperBound(States.ASYNCREPLICA.name(), "R"); return builder.build(); } Thanks and regards Tej
