3.6 实践与应用
3.6.1 如何实现公共配置管理
在分布式多台机器环境下,维持统一的配置信息是最常见的需求,当配置信息改变时,所有的机器能实时获取并更新。
Fourinone通过Park进行配置信息管理,Park提供创建和修改信息的方法,并支持轮循和事件响应两种方式获取变化的对象,两种方式的效果一样。
下面是主要API的设计:
SetConfig:在ParKServer上建立一个“domain=浙江、node=杭州、value=西湖”的配置信息,并且在8秒后把“西湖”改为“余杭”。
GetConfigA:演示了以轮循方式监控配置信息的变化,它调用一个getLastest的方法,该方法可以传入一个旧版本的对象,并对比获取最新版本的对象,如果有就打印,如果没有最新版本,就返回null。
GetConfigB:演示了事件响应方式监控配置信息变化,它实现一个LastestListener的事件接口并进行注册,当信息变化时,会产生事件并获取到变化后的对象进行处理,LastestListener的happenLastest方法有个Boolean返回值,如果返回false,它会一直监控配置信息变化,继续有新的变化时还会进行事件调用;如果返回true,它完成本次事件调用后就终止。
运行步骤:
1)启动ParkServerDemo(它的IP端口已经在配置文件中指定),结果如图3-3所示:
- Java –classpath fourinone.jar; ParkServerDemo
图3-3 ParkServerDemo
2)运行GetConfigA,结果如图3-4所示。
- java -cp fourinone.jar; GetConfigA
图3-4 GetConfigA
3)运行GetConfigB,结果如图3-5所示。
- java -cp fourinone.jar; GetConfigB
图3-5 GetConfigB
4)运行SetConfig,结果如图3-6所示:
- java -cp fourinone.jar; SetConfig
图3-6 SetConfig
可以看到SetConfig对节点“domain=浙江、node=杭州”做了更改后,GetConfigA和GetConfigB都同时获取到了更新。
如果是线上环境,为避免ParkServer宕机,ParkServer可以配置Master和任意数量的Slave,请使用ParkMasterSlave替换上面的ParkServerDemo即可,每次输入M或者S启动Master或者Slave,运行过程关掉Master,GetConfig仍然可以从Slave获取配置信息。
我们打开ParkMasterSlave程序可以看到如下代码:
- String[][] master = new String[][]{{"localhost","1888"},{"localhost","1889"}};
- String[][] slave = new String[][]{{"localhost","1889"},{"localhost","1888"}};
注意
配置Master/Slave时请注意一下顺序,需要将自己的地址放在最前面,备用的地址放后面,比如:
对Master来说:{"localhost","1888"},{"localhost","1889"};
对Slave来说:{"localhost","1889"},{"localhost","1888"}
下面我们演示一下ParkServer如果出现故障,通过配置Master/Slave来维持正常的服务,还是以刚才的demo为例。
1)启动ParkMasterSlave Master(它的IP端口已经在程序内指定),结果如图3-7所示:
- java -cp fourinone.jar; ParkMasterSlave M
图3-7 ParkMasterSlave M
2)启动ParkMasterSlave Slave(它的IP端口已经在程序内指定),结果如图3-8所示:
- java -cp fourinone.jar; ParkMasterSlave S
图3-8 ParkMasterSlave S
可以看到,Salve窗口输出:INFO:wantBeMaster,master is(localhost:1888),表示集群中之前启动的1888是领导者。
3)运行GetConfigA和GetConfigB
- java -cp fourinone.jar; GetConfigA
- java -cp fourinone.jar; GetConfigB
4)这个时候假设ParkServer的Master挂掉了,我们把启动的Master关闭(Ctrl+C),可以看到如图3-9所示的结果。
图3-9 Master挂掉
ParkServer Slave和GetConfigA跟GetConfigB窗口都出现了提示,领导者切换到Slave上继续提供服务。
5)运行SetConfig,结果如图3-10所示:
- java -cp fourinone.jar; SetConfig
图3-10 SetConfig
可以看到SetConfig会切换到Slave的localhost:1889上设置配置信息,并且GetConfigA跟GetConfigB也都会从localhost:1889上获取信息和响应更新,而不会因为master(localhost:1888)故障受影响。
完整demo源码如下:
- // ParkServerDemo
- import com.fourinone.BeanContext;
- public class ParkServerDemo
- {
- public static void main(String[] args)
- {
- BeanContext.startPark();
- }
- }
- // ParkMasterSlave
- import com.fourinone.BeanContext;
- public class ParkMasterSlave
- {
- 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);
- }
- }
- // GetConfigA
- import com.fourinone.BeanContext;
- import com.fourinone.ParkLocal;
- import com.fourinone.ObjectBean;
- public class GetConfigA
- {
- public static void main(String[] args)
- {
- ParkLocal pl = BeanContext.getPark();
- ObjectBean oldob = null;
- while(true){
- ObjectBean newob = pl.getLastest("zhejiang", "hangzhou", oldob);
- if(newob!=null){
- System.out.println(newob);
- oldob = newob;
- }
- }
- }
- }
- // GetConfigB
- import com.fourinone.BeanContext;
- import com.fourinone.ParkLocal;
- import com.fourinone.LastestListener;
- import com.fourinone.LastestEvent;
- import com.fourinone.ObjectBean;
- public class GetConfigB implements LastestListener
- {
- public boolean happenLastest(LastestEvent le)
- {
- ObjectBean ob = (ObjectBean)le.getSource();
- System.out.println(ob);
- return false;
- }
- public static void main(String[] args)
- {
- ParkLocal pl = BeanContext.getPark();
- pl.addLastestListener("zhejiang", "hangzhou", null, new GetConfigB());
- }
- }
- // SetConfig
- import com.fourinone.BeanContext;
- import com.fourinone.ParkLocal;
- import com.fourinone.ObjectBean;
- public class SetConfig
- {
- public static void main(String[] args)
- {
- ParkLocal pl = BeanContext.getPark();
- ObjectBean xihu = pl.create("zhejiang", "hangzhou", "xihu");
- System.out.println("Waiting...");
- try{Thread.sleep(8000);}catch(Exception e){}
- ObjectBean yuhang = pl.update("zhejiang", "hangzhou", "yuhang");
- }
- }