这里先说/diamond-utils/src/main/java/com/taobao/diamond/common/Constants.java这个文件必须改动的三个字段
public static final String HTTP_URI_FILE = "/diamond-server/config.co";//这个是为了从服务端提取配置信息
public static final String CONFIG_HTTP_URI_FILE = "/url";//这个是为了获取服务端地址列表的请求地址,后面会说到
public static final int DEFAULT_PORT = 0;//这里面为服务端的端口,默认为0,需要被改成真正的提供服务端口
获取配置信息测试的代码:
1 package com.taobao.diamond.test; 2 import java.util.concurrent.Executor; 3 import com.taobao.diamond.manager.DiamondManager; 4 import com.taobao.diamond.manager.ManagerListener; 5 import com.taobao.diamond.manager.impl.DefaultDiamondManager; 6 public class DiamondClient { 7 public static void main(String[] str) { 8 DiamondManager manager = new DefaultDiamondManager("DEFAULT_GROUP", "topicConfig", 9 new ManagerListener() {//填写你服务端后台保存过的group和dataId 10 public void receiveConfigInfo(String configInfo) { 11 System.out.println("changed config: " + configInfo); 12 } 13 public Executor getExecutor() { 14 return null; 15 } 16 }, "127.0.0.1,10.126.53.16,10.126.53.17"); 17 //设置diamond-server服务的端口 18 manager.getDiamondConfigure().setPort(8080); 19 20 String availableConfigureInfomation = manager.getAvailableConfigureInfomation(5000); 21 System.out.println("start config: " + availableConfigureInfomation); 22 } 23 }
对DefaultDiamondManager的扩展,支持手动指定服务端地址
添加了它的一个构造函数
1 public DefaultDiamondManager(String group, String dataId, ManagerListener managerListener,String diamondServer) { 2 this.dataId = dataId; 3 this.group = group; 4 5 diamondSubscriber = DiamondClientFactory.getSingletonDiamondSubscriber(); 6 7 this.managerListeners.add(managerListener); 8 ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).addManagerListeners(this.dataId, 9 this.group, this.managerListeners); 10 String s[] = diamondServer.split(","); 11 if (s != null && s.length > 0) { 12 for (String o : s) { 13 if (o != null && !o.trim().equals("")) 14 diamondSubscriber.getDiamondConfigure().getDomainNameList().add(o.trim()); 15 } 16 } 17 diamondSubscriber.addDataId(this.dataId, this.group); 18 diamondSubscriber.start(); 19 }
这样的话,就能获取到配置信息了。
上面这个例子通过手动指定diamondServer可以跳过服务端寻址的这个过程。
在配置diamond-server集群的时候,各个server之间的端口并没有要求相同,
但是在这的时候,发现它的端口,只能是相同的,无法每个IP对应自己的端口。
所以这里的diamondServer地址应该是nginx地址,端口的话,也应该是nginx提供diamond-server服务的端口。
nginx提供负载均衡的策略,同一的访问域名,对应了多台diamond-server后台机器,这里面的端口可以是不同的,解决diamond-server的单点问题。
虽然上面的那个例子手动指定了diamondServer地址,但是我们还是要去大体了解获取服务端地址的逻辑。
new DefaultDiamondManager的构造函数,最后一句是diamondSubscriber.start();
点击进去
1 serverAddressProcessor = new ServerAddressProcessor(this.diamondConfigure, this.scheduledExecutor); 2 3 serverAddressProcessor.start(); 4 5 然后在查看serverAddressProcessor.start()的具体逻辑 6 7 public synchronized void start() { 8 if (isRun) { 9 return; 10 } 11 isRun = true; 12 initHttpClient(); 13 if (this.diamondConfigure.isLocalFirst()) { 14 acquireServerAddressFromLocal(); 15 } 16 else { 17 synAcquireServerAddress();//首先执行的是这个 18 asynAcquireServerAddress(); 19 } 20 } 21 protected void synAcquireServerAddress() { 22 if (!isRun) { 23 throw new RuntimeException("ServerAddressProcessor不在运行状态,无法同步获取服务器地址列表"); 24 } 25 if (MockServer.isTestMode()) { 26 diamondConfigure.addDomainName("测试模式,没有使用的真实服务器"); 27 return; 28 } 29 int acquireCount = 0; 30 if (diamondConfigure.getDomainNameList().size() == 0) { 31 if (!acquireServerAddressOnce(acquireCount)) { 32 acquireCount++; 33 if (acquireServerAddressOnce(acquireCount)) { 34 // 存入本地文件 35 storeServerAddressesToLocal(); 36 log.info("在同步获取服务器列表时,向日常ConfigServer服务器获取到了服务器列表"); 37 } 38 else { 39 log.info("从本地获取Diamond地址列表"); 40 reloadServerAddresses(); 41 if (diamondConfigure.getDomainNameList().size() == 0) 42 throw new RuntimeException("当前没有可用的服务器列表"); 43 } 44 } 45 else { 46 log.info("在同步获取服务器列表时,向线上ConfigServer服务器获取到了服务器列表"); 47 // 存入本地文件 48 storeServerAddressesToLocal(); 49 } 50 } 51 } 52 53 private boolean acquireServerAddressOnce(int acquireCount) { 54 HostConfiguration hostConfiguration = configHttpClient.getHostConfiguration(); 55 String configServerAddress; 56 int port; 57 if (null != diamondConfigure.getConfigServerAddress()) { 58 configServerAddress = diamondConfigure.getConfigServerAddress(); 59 port = diamondConfigure.getConfigServerPort(); 60 } 61 else { 62 if (acquireCount == 0) { 63 configServerAddress = Constants.DEFAULT_DOMAINNAME;//a.b.c 64 port = Constants.DEFAULT_PORT;//端口 65 } 66 else { 67 configServerAddress = Constants.DAILY_DOMAINNAME;//d.e.f 68 port = Constants.DEFAULT_PORT;//端口 69 } 70 } 71 hostConfiguration.setHost(configServerAddress, port); 72 73 String serverAddressUrl = Constants.CONFIG_HTTP_URI_FILE; 74 //默认为/url,并且配置域名a.b.c或者d.e.f 访问url==>http://a.b.c:port/url返回以换行分隔的diamond ip列表行. 75 //所以这个/url很有可能需要被改掉 76 HttpMethod httpMethod = new GetMethod(serverAddressUrl); 77 // 设置HttpMethod的参数 78 HttpMethodParams params = new HttpMethodParams(); 79 params.setSoTimeout(diamondConfigure.getOnceTimeout()); 80 // /////////////////////// 81 httpMethod.setParams(params); 82 83 try { 84 if (SC_OK == configHttpClient.executeMethod(httpMethod)) { 85 InputStreamReader reader = new InputStreamReader(httpMethod.getResponseBodyAsStream()); 86 BufferedReader bufferedReader = new BufferedReader(reader); 87 String address = null; 88 List<String> newDomainNameList = new LinkedList<String>(); 89 while ((address = bufferedReader.readLine()) != null) {//以换行分割 90 address = address.trim(); 91 if (StringUtils.isNotBlank(address)) { 92 newDomainNameList.add(address); 93 } 94 } 95 if (newDomainNameList.size() > 0) { 96 log.debug("更新使用的服务器列表"); 97 this.diamondConfigure.setDomainNameList(newDomainNameList); 98 return true; 99 } 100 } 101 else { 102 log.warn("没有可用的新服务器列表"); 103 } 104 } 105 catch (HttpException e) { 106 log.error(getErrorMessage(configServerAddress) + ", " + e); 107 } 108 catch (IOException e) { 109 log.error(getErrorMessage(configServerAddress) + ", " + e); 110 } 111 catch (Exception e) { 112 log.error(getErrorMessage(configServerAddress) + ", " + e); 113 } 114 finally { 115 httpMethod.releaseConnection(); 116 } 117 return false; 118 }
函数reloadServerAddresses,本地获取服务地址列表
File serverAddressFile = new File(generateLocalFilePath(this.diamondConfigure.getFilePath(), "ServerAddress"));
//这里的地址,在我的机器,默认为C:\Users\linchengjun\diamond\ServerAddress
============================分割线==========================================
到这为止,diamond-client获取server列表的顺序出来了
1.如果像我那样对DefaultDiamondManager进行了扩展,手动指定了地址列表,就不会进行其他的寻址逻辑了。
2.如果没有的话,先进行http://a.b.c:port/url请求sever地址列表行,获取不到,再进行http://d.e.f:port/url请求获取;
如果这两个都不行,就会调用reloadServerAddresses,进行本地文件的获取,比如C:\Users\linchengjun\diamond\ServerAddress
--------------------------------------------------读取服务端配置信息的顺序------------------------------------
分析测试代码
1 String availableConfigureInfomation = manager.getAvailableConfigureInfomation(5000); 2 public String getAvailableConfigureInfomation(String dataId, String group, long timeout) { 3 // 尝试先从本地和网络获取配置信息 4 try { 5 String result = getConfigureInfomation(dataId, group, timeout); 6 if (result != null && result.length() > 0) { 7 return result; 8 } 9 } 10 catch (Throwable t) { 11 log.error(t.getMessage(), t); 12 } 13 14 // 测试模式不使用本地dump 15 if (MockServer.isTestMode()) { 16 return null; 17 } 18 return getSnapshotConfiginfomation(dataId, group);//从快照文件获取 19 }
具体断点进行调试,就能总结出来,读取的顺序
要不然老是获取不正确,即Constants.java中HTTP_URI_FILE改成public static final String HTTP_URI_FILE = "/diamond-server/config.co";
从网络获取到数据之后,会先保存到快照里面,然后是保存到本地缓存。