iRpc选举
iRpc项目地址:
- gitee: https://gitee.com/willbeahero/iRpc
- github: https://github.com/BrianApple/iRpc
iRpc基于raft选举算法实现服务节点自举,由于iRpc需要集群节点扩容,因此没有直接使用dledger项目作为选举实现框架,不过iRpc在实现选举和节点扩容的过程中,复用了dledger项目相关源代码,并按照iRpc所需做出相关调整,在此再次想dledger项目及作者表示感谢,dledger项目地址为: https://github.com/openmessaging/openmessaging-storage-dledger
iRcp选举过程大致如下(如果想要了解raft算法,请自行查询):
iRpc实现基本的raft选举代码如下(所有配置信息均可采用javabean或yml配置文件等形式设置):
/**
* ABC
*/
@Test
public void startCluster1_Node1(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10916");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n0");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n0");
node1.setIp("127.0.0.1");
node1.setPort("10916");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n1");
node2.setIp("127.0.0.1");
node2.setPort("10917");
lits.add(node2);
NodeInfo node3 = new NodeInfo();
node3.setNode("n2");
node3.setIp("127.0.0.1");
node3.setPort("10918");
lits.add(node3);
serverProperty.setClusterNode(lits);;
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* ABC
*/
@Test
public void startCluster1_Node2(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10917");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n1");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n0");
node1.setIp("127.0.0.1");
node1.setPort("10916");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n1");
node2.setIp("127.0.0.1");
node2.setPort("10917");
lits.add(node2);
NodeInfo node3 = new NodeInfo();
node3.setNode("n2");
node3.setIp("127.0.0.1");
node3.setPort("10918");
lits.add(node3);
serverProperty.setClusterNode(lits);;
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* ABC
*/
@Test
public void startCluster1_Node3(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10918");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n2");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n0");
node1.setIp("127.0.0.1");
node1.setPort("10916");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n1");
node2.setIp("127.0.0.1");
node2.setPort("10917");
lits.add(node2);
NodeInfo node3 = new NodeInfo();
node3.setNode("n2");
node3.setIp("127.0.0.1");
node3.setPort("10918");
lits.add(node3);
serverProperty.setClusterNode(lits);
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
iRpc节点扩容
集群扩容过程中,节点的选举依然基于raft算法,扩容节点和原集群节点的groupName必须一致,且iRpc不支持两个存在leader节点的集群合并扩容——会导致出现双leader情况,导致信息不一致
AB + C(AB) -> ABC 扩容模式
AB基于raft算法自举选出leader,C节点携带原集群所有节点信息且groupName一致,参与集群扩容,选举流程如下:
测试代码:
/**
* AB
*/
@Test
public void startNode1(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10916");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n0");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n0");
node1.setIp("127.0.0.1");
node1.setPort("10916");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n1");
node2.setIp("127.0.0.1");
node2.setPort("10917");
lits.add(node2);
serverProperty.setClusterNode(lits);;
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* AB
*/
@Test
public void startNode2(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10917");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n1");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n0");
node1.setIp("127.0.0.1");
node1.setPort("10916");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n1");
node2.setIp("127.0.0.1");
node2.setPort("10917");
lits.add(node2);
serverProperty.setClusterNode(lits);;
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* ABC
*/
@Test
public void startNode3(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10918");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n2");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n0");
node1.setIp("127.0.0.1");
node1.setPort("10916");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n1");
node2.setIp("127.0.0.1");
node2.setPort("10917");
lits.add(node2);
NodeInfo node3 = new NodeInfo();
node3.setNode("n2");
node3.setIp("127.0.0.1");
node3.setPort("10918");
lits.add(node3);
serverProperty.setClusterNode(lits);;
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
AB + C(A) 或 AB + C(B) -> ABC 扩容模式
AB基于raft算法自举选出leader,C节点只携带AB集群中的一部分节点信息参与扩容,最终达成选举一致,如下为AB + C(A)扩容的流程:
相关测试代码如下:
/**
* AB
*/
@Test
public void startCluster1_Node1(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10916");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n0");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n0");
node1.setIp("127.0.0.1");
node1.setPort("10916");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n1");
node2.setIp("127.0.0.1");
node2.setPort("10917");
lits.add(node2);
serverProperty.setClusterNode(lits);;
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* AB
*/
@Test
public void startCluster1_Node2(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10917");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n1");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n0");
node1.setIp("127.0.0.1");
node1.setPort("10916");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n1");
node2.setIp("127.0.0.1");
node2.setPort("10917");
lits.add(node2);
serverProperty.setClusterNode(lits);;
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* AC
*/
@Test
public void startCluster1_Node3(){
IRpcServerProperty serverProperty = new IRpcServerProperty();
serverProperty.setServerPort("10918");
serverProperty.setHeartbeat("60");
serverProperty.setNodeName("n2");
serverProperty.setGroupName("iRpcGroup");
List<NodeInfo> lits = new ArrayList<NodeInfo>();
NodeInfo node1 = new NodeInfo();
node1.setNode("n1");
node1.setIp("127.0.0.1");
node1.setPort("10917");
lits.add(node1);
NodeInfo node2 = new NodeInfo();
node2.setNode("n2");
node2.setIp("127.0.0.1");
node2.setPort("10918");
lits.add(node2);
serverProperty.setClusterNode(lits);;
new ServerStarter(serverProperty);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
总结
综上,iRpc既可以基于raft算法实现iRpc节点的自举,又在raft选举算法框架下实现了iRpc服务节点的动态扩容模式,是的iRpc服务节点部署的灵活性大大加强,能够满足更多的业务场景需求!