内容简介:Spring Cloud Netflix Eureka集群配置方式主要用两种:Static servers list config和dns,本文主要介绍基于DNS的方式搭建Eureka集群。client启动后从config中获取region和zone以及serviceUrl,进行服务注册、发现,这种静态集群模式无法动态扩容,一旦新增节点,只能挨个修改server和client端的配置文件,大致配置如下:基于DNS的Eureka Cluster架构图如下:
Spring Cloud Netflix Eureka集群配置方式主要用两种:Static servers list config和dns,本文主要介绍基于DNS的方式搭建Eureka集群。
Static servers list config
client启动后从config中获取region和zone以及serviceUrl,进行服务注册、发现,这种静态集群模式无法动态扩容,一旦新增节点,只能挨个修改server和client端的配置文件,大致配置如下:
eureka: server: enable-self-preservation: false instance: prefer-ip-address: true instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://10.25.102.174:8082/eureka/,http://10.25.102.174:8083/eureka/
DNS configuration
基于DNS的Eureka Cluster架构图如下:
简单来说就是使用DNS服务器管理Eureka Server的地址,弹性伸缩对客户端没有影响。
大致流程如下:
use-dns-for-fetching-service-urls: true client.region "http://" + ec2Url + ":" + clientConfig.getEurekaServerPort() + "/" + clientConfig.getEurekaServerURLContext() + "/";
只要解决DNS服务器配置就可以达到动态集群的效果,关于如何搭建DNS服务器集群,请移步另一篇文章: CentOS 搭建DNS主从服务器集群 ,文中详细介绍了如何在区域配置文件中配置TXT记录,本文不在赘述。
1.DNS 区域文件配置TXT记录
zts.local.zone区域配置文件中有关eureka的配置:
; eureka cluster配置 txt.shanghai IN TXT "defaultZone.zts.local" txt.defaultZone IN TXT "10.29.181.56" "10.29.181.57" "10.29.181.58" "10.29.181.60" ;通过查看Eureka的源码,它的实现是通过寻找txt.beijing-a.zts.local(txt.region.eureka-server-d-n-s-name)获取"beijing-a.zts.local" "beijing-b.zts.local"的zone:beijing-a和beijing-b, ;然后再去获取txt.beijing-a.zts.local和txt.beijing-b.zts.local中对应的ServiceUrls的数据,也就是IP地址: "10.29.181.61" "10.29.181.62" ;这样服务间就可以获取到固定端口下的不同IP的机器的注册中心服务地址,并相互注册 txt.beijing IN TXT "beijing-a.zts.local" "beijing-b.zts.local" txt.beijing-a IN TXT "10.29.181.61" "10.29.181.62" txt.beijing-b IN TXT "10.29.181.63" "10.29.181.64"
2.Eureka Server/Client端配置
--- spring: application: name: eureka-server server: port: 8081 eureka: server: enable-self-preservation: false instance: prefer-ip-address: true instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} client: ## 是否将自己注册到eureka register-with-eureka: true ## 是否获取注册信息到本地 fetch-registry: true ## 开启DNS方式获取serviceUrl,默认为false use-dns-for-fetching-service-urls: true ## DNS域名,获取其他信息将以该域名为根域名 eureka-server-d-n-s-name: zts.local ## 当前应用所在区域,默认为us-east-1 region: beijing ## 配置中心的eureka目录 eureka-server-u-r-l-context: eureka ## 映射其他eurekaServer的端口,这里注意采用这种方式 server.port和这个端口最好一致 ## 因为dns是控制地址的变化,端口不变,所以不像前面的哪些配置方式可以自己定义url和port。 ## 所以每个IP都是用的相同的port进行注册中心服务的部署 eureka-server-port: 8081 ## 获取serviceUrl时候是否优先获取相同zone的列表(如果获取为空则获取所在region第一个zone),如果为false则优先获取不在相同zone的列表 prefer-same-zone-eureka: true
3.测试
修改客户端DNS服务器配置为10.29.181.61,DNS服务器的域名为zts.local
依次启动4台Eureka Server服务器,查看启动日志(删减版的日志),:
2018-11-20 16:17:14.962 INFO 49750 --- [ main] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via DNS: txt.beijing.zts.local (<------注意这里) 2018-11-20 16:17:15.012 INFO 49750 --- [ main] com.netflix.discovery.DiscoveryClient : Disable delta property : false 2018-11-20 16:17:15.262 INFO 49750 --- [ main] com.netflix.discovery.DiscoveryClient : Discovery Client initialized at timestamp 1542701835260 with initial instances count: 5 2018-11-20 16:17:15.326 INFO 49750 --- [ main] c.n.eureka.DefaultEurekaServerContext : Initializing ... 2018-11-20 16:17:15.559 INFO 49750 --- [ main] c.n.eureka.cluster.PeerEurekaNodes : Replica node URL: http://10.29.181.62:8081/eureka/ 2018-11-20 16:17:15.560 INFO 49750 --- [ main] c.n.eureka.cluster.PeerEurekaNodes : Replica node URL: http://10.29.181.64:8081/eureka/ 2018-11-20 16:17:15.560 INFO 49750 --- [ main] c.n.eureka.cluster.PeerEurekaNodes : Replica node URL: http://10.29.181.61:8081/eureka/ 2018-11-20 16:17:16.052 INFO 49750 --- [ Thread-14] o.s.c.n.e.server.EurekaServerBootstrap : isAws returned false 2018-11-20 16:17:16.053 INFO 49750 --- [ Thread-14] o.s.c.n.e.server.EurekaServerBootstrap : Initialized server context 2018-11-20 16:17:16.056 INFO 49750 --- [ main] c.z.e.server.EurekaServerApplication : Started EurekaServerApplication in 7.112 seconds (JVM running for 7.625) 2018-11-20 16:17:16.060 INFO 49750 --- [ Thread-14] c.n.e.registry.AbstractInstanceRegistry : Registered instance EUREKA-SERVER/10.29.181.61:eureka-server:8081 with status UP (replication=true) 2018-11-20 16:17:16.061 INFO 49750 --- [ Thread-14] c.n.e.registry.AbstractInstanceRegistry : Registered instance EUREKA-SERVER/10.29.181.62:eureka-server:8081 with status UP (replication=true) 2018-11-20 16:17:16.061 INFO 49750 --- [ Thread-14] c.n.e.registry.AbstractInstanceRegistry : Registered instance EUREKA-SERVER/10.29.181.64:eureka-server:8081 with status UP (replication=true) 2018-11-20 16:17:16.062 INFO 49750 --- [ Thread-14] c.n.e.registry.AbstractInstanceRegistry : Registered instance EUREKA-SERVER/10.29.181.63:eureka-server:8081 with status UP (replication=true) 2018-11-20 16:17:16.062 INFO 49750 --- [ Thread-14] c.n.e.registry.AbstractInstanceRegistry : Registered instance ACCOUNT-CENTER/10.25.102.174:account-center:8891 with status UP (replication=true) 2018-11-20 16:17:16.062 INFO 49750 --- [ Thread-14] c.n.e.r.PeerAwareInstanceRegistryImpl : Got 5 instances from neighboring DS node 2018-11-20 16:17:16.062 INFO 49750 --- [ Thread-14] c.n.e.r.PeerAwareInstanceRegistryImpl : Renew threshold is: 8 2018-11-20 16:17:16.062 INFO 49750 --- [ Thread-14] c.n.e.r.PeerAwareInstanceRegistryImpl : Changing status to UP 2018-11-20 16:17:16.070 INFO 49750 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_EUREKA-SERVER/10.29.181.63:eureka-server:8081 - registration status: 204 2018-11-20 16:17:16.070 INFO 49750 --- [ Thread-14] e.s.EurekaServerInitializerConfiguration : Started Eureka Server 2018-11-20 16:17:16.310 INFO 49750 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet' 2018-11-20 16:17:16.310 INFO 49750 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started 2018-11-20 16:17:16.327 INFO 49750 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 17 ms 2018-11-20 16:17:16.578 INFO 49750 --- [nio-8081-exec-1] c.n.e.registry.AbstractInstanceRegistry : Registered instance EUREKA-SERVER/10.29.181.63:eureka-server:8081 with status UP (replication=true) 2018-11-20 16:17:17.457 INFO 49750 --- [nio-8081-exec-2] c.n.e.registry.AbstractInstanceRegistry : Registered instance EUREKA-SERVER/10.29.181.63:eureka-server:8081 with status UP (replication=true)
Eureka Client端
Account服务配置
logging: level: org.springframework.boot: info org.springframework.cloud: debug spring: application: name: account-center server: port: 8891 eureka: server: enable-self-preservation: false instance: prefer-ip-address: true instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} metadata-map: configPath: ${server.servlet.context-path} home-page-url-path: ${server.servlet.context-path} ## 服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除 lease-expiration-duration-in-seconds: 10 ## 服务刷新时间配置,每隔这个时间会主动心跳一次 lease-renewal-interval-in-seconds: 5 client: ## 是否将自己注册到eureka register-with-eureka: true ## 是否获取注册信息到本地 fetch-registry: true ## 开启DNS方式获取serviceUrl,默认为false use-dns-for-fetching-service-urls: true ## DNS域名,获取其他信息将以该域名为根域名 eureka-server-d-n-s-name: zts.local ## 当前应用所在区域,默认为us-east-1 region: beijing ## 配置中心的eureka目录 eureka-server-u-r-l-context: eureka ## 映射其他eurekaServer的端口,这里注意采用这种方式 server.port和这个端口最好一致 ## 因为dns是控制地址的变化,端口不变,所以不像前面的哪些配置方式可以自己定义url和port。 ## 所以每个IP都是用的相同的port进行注册中心服务的部署 eureka-server-port: 8081 ## 获取serviceUrl时候是否优先获取相同zone的列表(如果获取为空则获取所在region第一个zone),如果为false则优先获取不在相同zone的列表 prefer-same-zone-eureka: true
Account启动日志:
2018-11-20 16:11:05.373 INFO 5824 --- [ restartedMain] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via DNS: txt.beijing.zts.local (<------看这里) 2018-11-20 16:11:05.529 INFO 5824 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Disable delta property : false 2018-11-20 16:11:05.529 INFO 5824 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null 2018-11-20 16:11:05.529 INFO 5824 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Force full registry fetch : false 2018-11-20 16:11:05.529 INFO 5824 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Application is null : false 201
打开Eureka console,查看注册效果:
参考资料
1.com.netflix.discovery.endpoint.EndpointUtils.getServiceUrlsFromDNS
版本:eureka-client:1.9.3
/** * Get the list of all eureka service urls for the eureka client to talk to. * * @param clientConfig the clientConfig to use * @param zone the zone in which the client resides * @param randomizer a randomizer to randomized returned urls, if loading from dns * * @return The list of all eureka service urls for the eureka client to talk to. */ public static List<String> getDiscoveryServiceUrls(EurekaClientConfig clientConfig, String zone, ServiceUrlRandomizer randomizer) { boolean shouldUseDns = clientConfig.shouldUseDnsForFetchingServiceUrls(); if (shouldUseDns) { return getServiceUrlsFromDNS(clientConfig, zone, clientConfig.shouldPreferSameZoneEureka(), randomizer); } return getServiceUrlsFromConfig(clientConfig, zone, clientConfig.shouldPreferSameZoneEureka()); } /** * Get the list of all eureka service urls from DNS for the eureka client to * talk to. The client picks up the service url from its zone and then fails over to * other zones randomly. If there are multiple servers in the same zone, the client once * again picks one randomly. This way the traffic will be distributed in the case of failures. * * @param clientConfig the clientConfig to use * @param instanceZone The zone in which the client resides. * @param preferSameZone true if we have to prefer the same zone as the client, false otherwise. * @param randomizer a randomizer to randomized returned urls * * @return The list of all eureka service urls for the eureka client to talk to. */ public static List<String> getServiceUrlsFromDNS(EurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone, ServiceUrlRandomizer randomizer) { String region = getRegion(clientConfig); // Get zone-specific DNS names for the given region so that we can get a // list of available zones Map<String, List<String>> zoneDnsNamesMap = getZoneBasedDiscoveryUrlsFromRegion(clientConfig, region); Set<String> availableZones = zoneDnsNamesMap.keySet(); List<String> zones = new ArrayList<String>(availableZones); if (zones.isEmpty()) { throw new RuntimeException("No available zones configured for the instanceZone " + instanceZone); } int zoneIndex = 0; boolean zoneFound = false; for (String zone : zones) { logger.debug("Checking if the instance zone {} is the same as the zone from DNS {}", instanceZone, zone); if (preferSameZone) { if (instanceZone.equalsIgnoreCase(zone)) { zoneFound = true; } } else { if (!instanceZone.equalsIgnoreCase(zone)) { zoneFound = true; } } if (zoneFound) { logger.debug("The zone index from the list {} that matches the instance zone {} is {}", zones, instanceZone, zoneIndex); break; } zoneIndex++; } if (zoneIndex >= zones.size()) { if (logger.isWarnEnabled()) { logger.warn("No match for the zone {} in the list of available zones {}", instanceZone, zones.toArray()); } } else { // Rearrange the zones with the instance zone first for (int i = 0; i < zoneIndex; i++) { String zone = zones.remove(0); zones.add(zone); } } // Now get the eureka urls for all the zones in the order and return it List<String> serviceUrls = new ArrayList<String>(); for (String zone : zones) { for (String zoneCname : zoneDnsNamesMap.get(zone)) { List<String> ec2Urls = new ArrayList<String>(getEC2DiscoveryUrlsFromZone(zoneCname, DiscoveryUrlType.CNAME)); // Rearrange the list to distribute the load in case of multiple servers if (ec2Urls.size() > 1) { randomizer.randomize(ec2Urls); } for (String ec2Url : ec2Urls) { StringBuilder sb = new StringBuilder() .append("http://") .append(ec2Url) .append(":") .append(clientConfig.getEurekaServerPort()); if (clientConfig.getEurekaServerURLContext() != null) { if (!clientConfig.getEurekaServerURLContext().startsWith("/")) { sb.append("/"); } sb.append(clientConfig.getEurekaServerURLContext()); if (!clientConfig.getEurekaServerURLContext().endsWith("/")) { sb.append("/"); } } else { sb.append("/"); } String serviceUrl = sb.toString(); logger.debug("The EC2 url is {}", serviceUrl); serviceUrls.add(serviceUrl); } } } // Rearrange the fail over server list to distribute the load String primaryServiceUrl = serviceUrls.remove(0); randomizer.randomize(serviceUrls); serviceUrls.add(0, primaryServiceUrl); if (logger.isDebugEnabled()) { logger.debug("This client will talk to the following serviceUrls in order : {} ", (Object) serviceUrls.toArray()); } return serviceUrls; }
2. dns config配置参考文章
- micro-service-discovery-using-netflix-eureka
- eureka集群基于DNS配置方式 (给予我了不少灵感)
- Spring Cloud Eureka 集群使用DNS方式进行服务分区 (– 简单介绍了windows dns搭建)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。