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所示:

  1. Java classpath fourinone.jar; ParkServerDemo

3.6 实践与应用 - 图1

图3-3 ParkServerDemo

2)运行GetConfigA,结果如图3-4所示。

  1. java -cp fourinone.jar; GetConfigA

3.6 实践与应用 - 图2

图3-4 GetConfigA

3)运行GetConfigB,结果如图3-5所示。

  1. java -cp fourinone.jar; GetConfigB

3.6 实践与应用 - 图3

图3-5 GetConfigB

4)运行SetConfig,结果如图3-6所示:

  1. java -cp fourinone.jar; SetConfig

3.6 实践与应用 - 图4

图3-6 SetConfig

可以看到SetConfig对节点“domain=浙江、node=杭州”做了更改后,GetConfigA和GetConfigB都同时获取到了更新。

如果是线上环境,为避免ParkServer宕机,ParkServer可以配置Master和任意数量的Slave,请使用ParkMasterSlave替换上面的ParkServerDemo即可,每次输入M或者S启动Master或者Slave,运行过程关掉Master,GetConfig仍然可以从Slave获取配置信息。

我们打开ParkMasterSlave程序可以看到如下代码:

  1. String[][] master = new String[][]{{"localhost","1888"},{"localhost","1889"}};
  2. String[][] slave = new String[][]{{"localhost","1889"},{"localhost","1888"}};

3.6 实践与应用 - 图5注意

配置Master/Slave时请注意一下顺序,需要将自己的地址放在最前面,备用的地址放后面,比如:

对Master来说:{"localhost","1888"},{"localhost","1889"};

对Slave来说:{"localhost","1889"},{"localhost","1888"}

下面我们演示一下ParkServer如果出现故障,通过配置Master/Slave来维持正常的服务,还是以刚才的demo为例。

1)启动ParkMasterSlave Master(它的IP端口已经在程序内指定),结果如图3-7所示:

  1. java -cp fourinone.jar; ParkMasterSlave M

3.6 实践与应用 - 图6

图3-7 ParkMasterSlave M

2)启动ParkMasterSlave Slave(它的IP端口已经在程序内指定),结果如图3-8所示:

  1. java -cp fourinone.jar; ParkMasterSlave S

3.6 实践与应用 - 图7

图3-8 ParkMasterSlave S

可以看到,Salve窗口输出:INFO:wantBeMaster,master is(localhost:1888),表示集群中之前启动的1888是领导者。

3)运行GetConfigA和GetConfigB

  1. java -cp fourinone.jar; GetConfigA
  2. java -cp fourinone.jar; GetConfigB

4)这个时候假设ParkServer的Master挂掉了,我们把启动的Master关闭(Ctrl+C),可以看到如图3-9所示的结果。

3.6 实践与应用 - 图8

图3-9 Master挂掉

ParkServer Slave和GetConfigA跟GetConfigB窗口都出现了提示,领导者切换到Slave上继续提供服务。

5)运行SetConfig,结果如图3-10所示:

  1. java -cp fourinone.jar; SetConfig

3.6 实践与应用 - 图9

图3-10 SetConfig

可以看到SetConfig会切换到Slave的localhost:1889上设置配置信息,并且GetConfigA跟GetConfigB也都会从localhost:1889上获取信息和响应更新,而不会因为master(localhost:1888)故障受影响。

完整demo源码如下:

  1. // ParkServerDemo
  2. import com.fourinone.BeanContext;
  3. public class ParkServerDemo
  4. {
  5. public static void main(String[] args)
  6. {
  7. BeanContext.startPark();
  8. }
  9. }
  10.  
  11. // ParkMasterSlave
  12. import com.fourinone.BeanContext;
  13.  
  14. public class ParkMasterSlave
  15. {
  16. public static void main(String[] args)
  17. {
  18. String[][] master = new String[][]{{"localhost","1888"},{"localhost",
  19. "1889"}};
  20. String[][] slave = new String[][]{{"localhost","1889"},{"localhost",
  21. "1888"}};
  22.  
  23. String[][] server = null;
  24. if(args[0].equals("M"))
  25. server = master;
  26. else if(args[0].equals("S"))
  27. server = slave;
  28.  
  29. BeanContext.startPark(server[0][0],Integer.parseInt(server[0][1]),
  30. server);
  31. }
  32. }
  33.  
  34. // GetConfigA
  35. import com.fourinone.BeanContext;
  36. import com.fourinone.ParkLocal;
  37. import com.fourinone.ObjectBean;
  38.  
  39. public class GetConfigA
  40. {
  41. public static void main(String[] args)
  42. {
  43. ParkLocal pl = BeanContext.getPark();
  44. ObjectBean oldob = null;
  45. while(true){
  46. ObjectBean newob = pl.getLastest("zhejiang", "hangzhou", oldob);
  47. if(newob!=null){
  48. System.out.println(newob);
  49. oldob = newob;
  50. }
  51. }
  52. }
  53. }
  54.  
  55. // GetConfigB
  56. import com.fourinone.BeanContext;
  57. import com.fourinone.ParkLocal;
  58. import com.fourinone.LastestListener;
  59. import com.fourinone.LastestEvent;
  60. import com.fourinone.ObjectBean;
  61.  
  62. public class GetConfigB implements LastestListener
  63. {
  64. public boolean happenLastest(LastestEvent le)
  65. {
  66. ObjectBean ob = (ObjectBean)le.getSource();
  67. System.out.println(ob);
  68. return false;
  69. }
  70.  
  71. public static void main(String[] args)
  72. {
  73. ParkLocal pl = BeanContext.getPark();
  74. pl.addLastestListener("zhejiang", "hangzhou", null, new GetConfigB());
  75. }
  76. }
  77.  
  78. // SetConfig
  79. import com.fourinone.BeanContext;
  80. import com.fourinone.ParkLocal;
  81. import com.fourinone.ObjectBean;
  82.  
  83. public class SetConfig
  84. {
  85. public static void main(String[] args)
  86. {
  87. ParkLocal pl = BeanContext.getPark();
  88. ObjectBean xihu = pl.create("zhejiang", "hangzhou", "xihu");
  89. System.out.println("Waiting...");
  90. try{Thread.sleep(8000);}catch(Exception e){}
  91. ObjectBean yuhang = pl.update("zhejiang", "hangzhou", "yuhang");
  92. }
  93. }