3.6.3 如何实现集群管理
对于像淘宝这样上万台服务器集群环境的大型互联网应用,通常我们面临这样一种需求:我们需要一个集群管理者管理集群里的服务器,同一个集群中任何一台服务器宕机,其他服务器都能感知。如果是集群管理者宕机,集群中所有的服务器不能受任何影响,能实时切换到备份管理者上提供服务。
这个demo演示了如何利用Fourinone用简单几行代码实现上述功能:
❏ GroupManager:是一个集群管理者,它有master和slave两个实例,实际上你可以建立任意多的slave。
❏ GroupServer:代表一个集群中的server,它启动后会注册自己的信息到集群管理者,然后监控集群中其他机器的状况并实时反馈。它使用一个getLastest的API,这个API可以返回最新的集群状况,如果不是最新的就返回null。
- pl.create("group", args[0], args[0], AuthPolicy.OP_ALL, true);
❏ 上面的方法进行节点的注册,其中前3个参数分别是domain、node、value,AuthPolicy.OP_ALL表示该节点的权限为公共,也就是可以被其他进程修改删除,true代表它是个保持连接节点,如果失去连接,该节点会被删除。
运行步骤:
1)启动GroupManager进程,输入参数分别为M,代表master,结果如图3-13所示:
- java -cp fourinone.jar; GroupManager M
图3-13 GroupManager M
2)启动GroupManager进程,输入参数分别为S,代表slave,结果如图3-14所示:
- java -cp fourinone.jar; GroupManager S
图3-14 GroupManager S
3)启动3个GroupServer进程,每次输入参数分别为"one,two,three"代表3台集群server(它访问master的IP端口已经在配置文件指定),结果如图3-15所示。
- java -cp fourinone.jar; GroupServer one
- java -cp fourinone.jar; GroupServer two
- java -cp fourinone.jar; GroupServer three
图3-15 GroupServer
观察每个GroupServer进程里的输出,每个进程窗口都会有集群里所有服务器的信息输出,可以关掉其中一个进程模拟一个GroupServer宕机,此时其他两个GroupServer进程会实时输出集群更新信息,请再关掉master进程模拟GroupManager宕机,会发现两个GroupServer进程会即时选取slave为新的领导者,请把刚才关掉的一个GroupServer进程恢复,会发现所有GroupServer在master宕机情况下,也能实时得到集群的最新信息。
下面我们演示这一系列操作:
1)关掉GroupServer three,如图3-16所示。
图3-16 关闭GroupServer
可以看到,GroupServer three关闭后,GroupServer one和GroupServer two都输出了集群更新信息。
2)再关掉GroupManager master,如图3-17所示。
图3-17 关闭GroupManager
可以看到,当GroupManager master关闭时,GroupManager slave成为集群管理的领导者,并且GroupServer one和GroupServer two都切换到GroupManager slave上。
3)恢复GroupServer three,如图3-18所示。
图3-18 恢复GroupServer
从上面可以发现,虽然GroupManager master挂了,但是GroupServer three重新加入集群,GroupServer one和GroupServer two仍然可以通过GroupManager slave感知到集群的状况。
注意
在集群管理或者集群配置信息等应用中,对及时性要求较高,可以将心跳时间调整得快些,避免延迟。比如将默认的3000毫秒改为1000毫秒或者其他值,根据自己的服务器性能和网络质量等因素去定:
- <HEARTBEAT>1000</HEARTBEAT>(配置文件中Park部分)
下面是demo源码:
- // GroupManager
- import com.fourinone.BeanContext;
- public class GroupManager
- {
- public static void main(String[] args)
- {
- String[][] master = new String[][]{{"localhost","1888"},{"localhost", "1889"}};
- String[][] slave = new String[][]{{"localhost","1889"},{"localhost", "1888"}};
- String[][] server = null;
- if(args[0].equals("M"))
- server = master;
- else if(args[0].equals("S"))
- server = slave;
- BeanContext.startPark(server[0][0],Integer.parseInt(server[0][1]), server);
- }
- }
- // GroupServer
- import com.fourinone.BeanContext;
- import com.fourinone.ParkLocal;
- import com.fourinone.ObjectBean;
- import com.fourinone.AuthPolicy;
- import java.util.List;
- public class GroupServer
- {
- public static void main(String[] args)
- {
- ParkLocal pl = BeanContext.getPark();
- pl.create("group", args[0], args[0], AuthPolicy.OP_ALL, true);
- List<ObjectBean> oldls = null;
- while(true){
- List<ObjectBean> newls = pl.getLastest("group", oldls);
- if(newls!=null){
- System.out.println("Group:"+newls);
- oldls = newls;
- }
- }
- }
- }