最近在研究spring cloud eureka集群配置的时候碰到问题:多台eureka server如果需要互相注册,需要在配置文件中将其他服务器地址配置写死.同样客户端启用服务发现功能(eureka client)也需要配置服务端地址列表(其实eureka server与其他eureka server通信也是用的是eureka client组件).按照官方案例提供3台server,如果现在需要增加第四台,第五台...那么问题就来了,所有eureka client的serverUrls列表是否都得更新(修改配置文件)?

一句话总结如上问题就是:eureka集群有什么办法能支持动态集群(集群数量可增减客户端不需要改动任何内容)?

经过寻找发现spring cloud eureka client提供一个eureka.client.useDnsForFetchingServiceUrls选项,使用Dns获取服务地址.

经过各种了解,明确了该配置项就是启用dns来存储eureka server列表的,可以实现动态eureka server集群的功能.但是问题又来了,相关属性还有那些?dns又该如何配置呢?

相关属性好找,有网友提供的例子,dns这块没有比较明确的说明,为了弄明白这块自己尝试着看了看源码,结果找到了DNS里面关于具体如何使用DNS结果的相关代码.代码如下:

getDiscoveryServiceUrls的作用是获取所有eureka service urls,该方法首先判断是否需要从DNS获取服务列表,图中红框部分就是从DNS获取服务列表,继续往下分析:

在分析之前,插播一个知识点:eureka集群与region和zone这几个概念的关系.http://www.vccoo.com/v/bqq4vj

继续看代码:

复制代码

1 /**

2 * Get the list of all eureka service urls from DNS for the eureka client to

3 * talk to. The client picks up the service url from its zone and then fails over to

4 * other zones randomly. If there are multiple servers in the same zone, the client once

5 * again picks one randomly. This way the traffic will be distributed in the case of failures.

6 *

7 * @param clientConfig the clientConfig to use

8 * @param instanceZone The zone in which the client resides.

9 * @param preferSameZone true if we have to prefer the same zone as the client, false otherwise.

10 * @param randomizer a randomizer to randomized returned urls

11 *

12 * @return The list of all eureka service urls for the eureka client to talk to.

13 */

14 public static List getServiceUrlsFromDNS(EurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone, ServiceUrlRandomizer randomizer) {

15 String region = getRegion(clientConfig);

16 // Get zone-specific DNS names for the given region so that we can get a

17 // list of available zones

18 Map> zoneDnsNamesMap = getZoneBasedDiscoveryUrlsFromRegion(clientConfig, region);

19 Set availableZones = zoneDnsNamesMap.keySet();

20 List zones = new ArrayList(availableZones);

21 if (zones.isEmpty()) {

22 throw new RuntimeException("No available zones configured for the instanceZone " + instanceZone);

23 }

24 int zoneIndex = 0;

25 boolean zoneFound = false;

26 for (String zone : zones) {

27 logger.debug("Checking if the instance zone {} is the same as the zone from DNS {}", instanceZone, zone);

28 if (preferSameZone) {

29 if (instanceZone.equalsIgnoreCase(zone)) {

30 zoneFound = true;

31 }

32 } else {

33 if (!instanceZone.equalsIgnoreCase(zone)) {

34 zoneFound = true;

35 }

36 }

37 if (zoneFound) {

38 Object[] args = {zones, instanceZone, zoneIndex};

39 logger.debug("The zone index from the list {} that matches the instance zone {} is {}", args);

40 break;

41 }

42 zoneIndex++;

43 }

44 if (zoneIndex >= zones.size()) {

45 logger.warn("No match for the zone {} in the list of available zones {}",

46 instanceZone, Arrays.toString(zones.toArray()));

47 } else {

48 // Rearrange the zones with the instance zone first

49 for (int i = 0; i < zoneIndex; i++) {

50 String zone = zones.remove(0);

51 zones.add(zone);

52 }

53 }

54

55 // Now get the eureka urls for all the zones in the order and return it

56 List serviceUrls = new ArrayList();

57 for (String zone : zones) {

58 for (String zoneCname : zoneDnsNamesMap.get(zone)) {

59 List ec2Urls = new ArrayList(getEC2DiscoveryUrlsFromZone(zoneCname, DiscoveryUrlType.CNAME));

60 // Rearrange the list to distribute the load in case of

61 // multiple servers

62 if (ec2Urls.size() > 1) {

63 randomizer.randomize(ec2Urls);

64 }

65 for (String ec2Url : ec2Urls) {

66 String serviceUrl = "http://" + ec2Url + ":"

67 + clientConfig.getEurekaServerPort()

68 + "/" + clientConfig.getEurekaServerURLContext()

69 + "/";

70 logger.debug("The EC2 url is {}", serviceUrl);

71 serviceUrls.add(serviceUrl);

72 }

73 }

74 }

75 // Rearrange the fail over server list to distribute the load

76 String primaryServiceUrl = serviceUrls.remove(0);

77 randomizer.randomize(serviceUrls);

78 serviceUrls.add(0, primaryServiceUrl);

79

80 logger.debug("This client will talk to the following serviceUrls in order : {} ",

81 Arrays.toString(serviceUrls.toArray()));

82 return serviceUrls;

83 }

复制代码

从代码中可以看到,首先获取当前eureka-client所在的region,然后根据region获取所有zone以及对应的域名信息,然后循环所有zone域名信息获取eureka-server地址,拼接成完整的serviceUrl并加入serviceUrls列表中.

拼接的serviceUrl格式为:"http://" + ec2Url + ":" + clientConfig.getEurekaServerPort() + "/" + clientConfig.getEurekaServerURLContext() + "/";

另外在代码中有标出两处重点,红色背景的是根据region获取zone的具体方法,蓝色背景的是根据zone具体地址获取eureka地址列表的方法.重点就在这两个方法中.

首先看第一个,获取zone的逻辑:

复制代码

1 /**

2 * Get the zone based CNAMES that are bound to a region.

3 *

4 * @param region

5 * - The region for which the zone names need to be retrieved

6 * @return - The list of CNAMES from which the zone-related information can

7 * be retrieved

8 */

9 public static Map> getZoneBasedDiscoveryUrlsFromRegion(EurekaClientConfig clientConfig, String region) {

10 String discoveryDnsName = null;

11 try {

12 discoveryDnsName = "txt." + region + "." + clientConfig.getEurekaServerDNSName();

13

14 logger.debug("The region url to be looked up is {} :", discoveryDnsName);

15 Set zoneCnamesForRegion = new TreeSet(DnsResolver.getCNamesFromTxtRecord(discoveryDnsName));

16 Map> zoneCnameMapForRegion = new TreeMap>();

17 for (String zoneCname : zoneCnamesForRegion) {

18 String zone = null;

19 if (isEC2Url(zoneCname)) {

20 throw new RuntimeException(

21 "Cannot find the right DNS entry for "

22 + discoveryDnsName

23 + ". "

24 + "Expected mapping of the format .");

25 } else {

26 String[] cnameTokens = zoneCname.split("\.");

27 zone = cnameTokens[0];

28 logger.debug("The zoneName mapped to region {} is {}", region, zone);

29 }

30 List zoneCnamesSet = zoneCnameMapForRegion.get(zone);

31 if (zoneCnamesSet == null) {

32 zoneCnamesSet = new ArrayList();

33 zoneCnameMapForRegion.put(zone, zoneCnamesSet);

34 }

35 zoneCnamesSet.add(zoneCname);

36 }

37 return zoneCnameMapForRegion;

38 } catch (Throwable e) {

39 throw new RuntimeException("Cannot get cnames bound to the region:" + discoveryDnsName, e);

40 }

41 }

复制代码

12行是请求dns中的地址格式:"txt." + region + "." + clientConfig.getEurekaServerDNSName(),例如:txt.region1.baidu.com,txt.region1.163.com,txt.region2.163.com等

17,27,35行是对返回结果的解析逻辑,可以看出返回值应当是多条记录并且以空格分开(在15行方法内),每条记录都应当是一个域名并且第一个.之前的部分作为zone名称,最终按照zone组织成zone:List的结果返回.

再看第二个,获取eureka server地址逻辑:

复制代码

1 /**

2 * Get the list of EC2 URLs given the zone name.

3 *

4 * @param dnsName The dns name of the zone-specific CNAME

5 * @param type CNAME or EIP that needs to be retrieved

6 * @return The list of EC2 URLs associated with the dns name

7 */

8 public static Set getEC2DiscoveryUrlsFromZone(String dnsName, DiscoveryUrlType type) {

9 Set eipsForZone = null;

10 try {

11 dnsName = "txt." + dnsName;

12 logger.debug("The zone url to be looked up is {} :", dnsName);

13 Set ec2UrlsForZone = DnsResolver.getCNamesFromTxtRecord(dnsName);

14 for (String ec2Url : ec2UrlsForZone) {

15 logger.debug("The eureka url for the dns name {} is {}", dnsName, ec2Url);

16 ec2UrlsForZone.add(ec2Url);

17 }

18 if (DiscoveryUrlType.CNAME.equals(type)) {

19 return ec2UrlsForZone;

20 }

21 eipsForZone = new TreeSet();

22 for (String cname : ec2UrlsForZone) {

23 String[] tokens = cname.split("\.");

24 String ec2HostName = tokens[0];

25 String[] ips = ec2HostName.split("-");

26 StringBuilder eipBuffer = new StringBuilder();

27 for (int ipCtr = 1; ipCtr < 5; ipCtr++) {

28 eipBuffer.append(ips[ipCtr]);

29 if (ipCtr < 4) {

30 eipBuffer.append(".");

31 }

32 }

33 eipsForZone.add(eipBuffer.toString());

34 }

35 logger.debug("The EIPS for {} is {} :", dnsName, eipsForZone);

36 } catch (Throwable e) {

37 throw new RuntimeException("Cannot get cnames bound to the region:" + dnsName, e);

38 }

39 return eipsForZone;

40 }

复制代码

11行代码明确了请求格式为:"txt." + dnsName,例如:txt.zone1.163.com,txt.zone2.baidu.com等

而返回结果则比较复杂,我们只关心cnametype的,从getServiceUrlsFromDNS方法中可以得知,只需要返回服务器地址或域名就可以了(返回多组同样用空格隔开).

看到这里对dns获取eureka地址的过程已经明白了.然后就是配置了

复制代码

eureka:

client:

eureka-server-d-n-s-name: relinson.com

use-dns-for-fetching-service-urls: true

region: region1

eureka-server-u-r-l-context: eureka

eureka-server-port: 9999

prefer-same-zone-eureka: true

复制代码

启动后可以看到这种方式配置还算是成功的

eureka多台注册中心_spring cloud eureka集群,注册中心再添加一台服务器相关推荐

  1. apollo 配置中心_Spring Cloud 系列之 Apollo 配置中心(三)

    本篇文章为系列文章,未读前几集的同学请猛戳这里: 哈喽沃德先生:Spring Cloud 系列之 Apollo 配置中心(一)​zhuanlan.zhihu.com 哈喽沃德先生:Spring Clo ...

  2. SpringCloud eureka 高集群注册中心

    高集群注册中心 你中有我,我中有你.相互注册,相互访问. 建立两个项目: 两个里面的依赖一样,启动类一样,yml文件里面几乎一样,知识端口换了一下.我们看图: 如果报错,可能就是两个启动类里面少了注解 ...

  3. 人大金仓集群停止服务时,一台停止失败,一台停止成功

    人大金仓集群停止服务时,一台停止失败,一台停止成功 telnet ip 8890 如果提示 connect to address ip connection refused 删除Server/bin下 ...

  4. eureka多台注册中心_spring cloud注册中心之Eureka

    什么是注册中心? 随着微服务的盛行,越来越多的应用,开始拆成一个一个的服务,服务之间相互依赖,那么内部的服务是怎么相互调用的.例如:服务A部署在3个服务器上,3个实例有不同的ip地址.然后服务B依赖服 ...

  5. spring cloud搭建_Spring Cloud Eureka 注册中心集群搭建,Greenwich 最新版!

    Spring Cloud 的注册中心可以由 Eureka.Consul.Zookeeper.ETCD 等来实现,这里推荐使用 Spring Cloud Eureka 来实现注册中心,它基于 Netfl ...

  6. eureka集群只注册一个_Spring cloud系列教程第十篇- Spring cloud整合Eureka总结篇

    Spring cloud系列教程第十篇- Spring cloud整合Eureka总结篇 本文主要内容: 1:spring cloud整合Eureka总结 本文是由凯哥(凯哥Java:kagejava ...

  7. 注册中心 Spring Cloud Eureka

    一.搭建eureka-server工程 目录结构 二.导入依赖 <?xml version="1.0" encoding="UTF-8"?> < ...

  8. eureka 之前的服务如何关闭_干货分享 | 服务注册中心Spring Cloud Eureka部分源码分析...

    友情提示:全文13000多文字,预计阅读时间10-15分钟 Spring Cloud Eureka作为常用的服务注册中心,我们有必要去了解其内在实现机制,这样出现问题的时候我们可以快速去定位问题.当我 ...

  9. eureka 客户端服务启动了又失败了_Spring cloud Eureka服务注册与发现详解

    一.Eureka概述 (1)Eureka是什么 Eureka是一个用于服务注册与发现的框架,本身是一个基于Rest的服务. (2)Eureka的组件有哪些? Eureka的组件可分为Eureka Se ...

  10. 06 为注册中心Spring Cloud Eureka增加安全认证

    1.为何要加安全认证 在开发Spring Cloud微服务项目时,Eureka默认是可以直接访问的,当项目上线部署时会暴露出很多安全问题,比如只要获取到Eureka注册中心的访问地址,就可以知悉该项目 ...

最新文章

  1. 巧用宏定义进行调试 (转)
  2. 28 模态框拖动案例
  3. python工作-Python自动化运维|Python语言工作岗位待遇如何?
  4. 网络编程--Address already in use 问题
  5. ubuntu 16.0.4如何配合网卡,
  6. 【opencv学习】【形态学】【腐蚀与膨胀】【开运算与闭运算】【礼帽和黑帽】
  7. 影响科学圈的“十大名码”!
  8. HALCON:如何结合面向对象和面向过程的代码
  9. 设计模式网站 http://www.cnblogs.com/justinw/archive/2007/02/06/641414.html
  10. 【MAVEN】搜索错误“Index downloads are disabled,search results may be incomplete”
  11. html网页url伪静态,动态url 静态url 伪静态url页面的区别
  12. 服务器修改字体,云服务器怎么修改字体
  13. mini2440的串口在Qt上实现
  14. 利用鱼塘理论告诉你2020年怎么做IP运营推广
  15. 我喜欢两个男人。。。
  16. 西门子S7200plc通信不上实际问题和解决方法
  17. Java json字符串转json对象
  18. FFmpeg入门详解之124:Qt5 FFmpeg单路网络摄像头采集预览
  19. 怎么在sp3上安装iis6.0
  20. GLES2.0中文API-glFramebufferRenderbuffer

热门文章

  1. matlab 文本框方向,ppt文本框文字方向为所有文字旋转的设置方法
  2. SQLiteDatabaseLockedException: database is locked
  3. 网易云课堂整站源码 THINKPHP二开仿网易云课堂
  4. 联通路由器设置FTP服务器,做家庭储存云盘
  5. 静态NAT64实验配置
  6. 大数据分析应用的机遇与挑战
  7. 文本匹配、文本相似度模型之DSSM
  8. java一元二次方程用if_用javascript写一个求一元二次方程的页面 用JAVA写一个求解一元二次方程的类...
  9. 毕业论文word格式
  10. SQL中order by的高级用法