基于SpringBoot1.5.4 Cloud(Dalston.SR2) 的高可用 Eureka Cluster
,以及注意事项
本教程用1个项目(battcn-cloud-discovery),多环境方式演示
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.battcn</groupId> <artifactId>battcn-cloud-discovery</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <name>battcn-cloud-discovery</name> <description>Eureka服务发现与注册</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR2</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
package com.battcn.discovery; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class BattcnCloudDiscoveryApplication { public static void main(String[] args) { SpringApplication.run(BattcnCloudDiscoveryApplication.class, args); } }
server: port: 8761 spring: profiles: active: peer2 #官方写的就是 8761 --- spring: profiles: peer1 application: name: Eureka-Server-1 eureka: instance: hostname: peer1 #配置主机名 client: register-with-eureka: false #配置服务注册中心是否以自己为客户端进行注册(配置false) fetch-registry: false #是否取得注册信息(配置false) service-url: defaultZone: http://peer2:7002/eureka/ #defaultZone 一定要按照标准写法,因为service-url的数据类型是Map 这算是个小坑需要注意 server: port: 7001 --- spring: profiles: peer2 application: name: Eureka-Server-1 eureka: instance: hostname: peer2 #配置主机名 client: register-with-eureka: false #配置服务注册中心是否以自己为客户端进行注册(配置false) fetch-registry: false #是否取得注册信息(配置false) service-url: defaultZone: http://peer1:7001/eureka/ server: port: 7002 #defaultZone 一定要按照标准写法,因为service-url的数据类型是Map 这算是个小坑需要注意
命令:mvn clean package (先打成jar包)
peer1:java -jar battcn-cloud-discovery.jar --spring.profiles.active=peer1 peer2:java -jar battcn-cloud-discovery.jar --spring.profiles.active=peer2
1.点击蓝色加号
2.点击Spring Boot
3.填写 Name:peer1 Program arguments:–spring.profiles.active=peer1(启动2个操作2次,记得改名字和激活环境,Eclipse太简单了application.yml 直接修改内容启动就行了)
启动成功分别访问
http://peer1:7001
http://peer2:7002
如出现上图所示,代表我们集群启动成功
1.创建 battcn-cloud-h1
和 battcn-cloud-h2
2个项目,基本大同小异
就这2个包够了,跟 h1 代码唯一的区别就是 h2 做调用 h1写好接口就行了
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
server: port: 7012 spring: application: name: battcn-cloud-h2 eureka: instance: hostname: localhost #配置主机名 client: service-url: defaultZone: http://peer1:7001/eureka/,http://peer2:7002/eureka/ #配置Eureka Server
package com.battcn; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient @RestController public class H2Application { static Logger LOGGER = LoggerFactory.getLogger(H2Application.class); @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } @RequestMapping("/h2") public String home(@RequestParam String email) { // 改写法之前有说过是VIP模式 return restTemplate().getForObject("http://battcn-cloud-h1/h1?email=" + email, String.class); } public static void main(String[] args) { SpringApplication.run(H2Application.class, args); } }
分别启动 battcn-cloud-h1
和 battcn-cloud-h2
访问: http://localhost:7012/h2?email=1837307557@qq.com
浏览器: My Name's :battcn-cloud-h1 Email:1837307557@qq.com
代表请求成功,然后我们断掉 peer1
或者 peer2
继续请求依旧可用,只是日志会抛异常,通过日志我们可以发现 peer2
time out 因为它被杀掉了,但是这并不影响我们服务调用(高可用),只要在启动 peer2
错误就不会在出现,在生产中如果集群都挂了 直接 运维下岗就是了(如果 peer1
peer2
同时挂掉,在启动服务会自动注册上去.)
2017-07-31 23:01:03.314 ERROR 14792 --- [-target_peer2-8] c.n.e.cluster.ReplicationTaskProcessor : Network level connection to peer peer2; retrying after delay com.sun.jersey.api.client.ClientHandlerException: org.apache.http.conn.ConnectTimeoutException: Connect to peer2:7002 timed out at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar:1.19.1] at com.netflix.eureka.cluster.DynamicGZIPContentEncodingFilter.handle(DynamicGZIPContentEncodingFilter.java:48) ~[eureka-core-1.6.2.jar:1.6.2] at com.netflix.discovery.EurekaIdentityHeaderFilter.handle(EurekaIdentityHeaderFilter.java:27) ~[eureka-client-1.6.2.jar:1.6.2] at com.sun.jersey.api.client.Client.handle(Client.java:652) ~[jersey-client-1.19.1.jar:1.19.1] at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) ~[jersey-client-1.19.1.jar:1.19.1] at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) ~[jersey-client-1.19.1.jar:1.19.1] at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:570) ~[jersey-client-1.19.1.jar:1.19.1] at com.netflix.eureka.transport.JerseyReplicationClient.submitBatchUpdates(JerseyReplicationClient.java:116) ~[eureka-core-1.6.2.jar:1.6.2] at com.netflix.eureka.cluster.ReplicationTaskProcessor.process(ReplicationTaskProcessor.java:71) ~[eureka-core-1.6.2.jar:1.6.2] at com.netflix.eureka.util.batcher.TaskExecutors$BatchWorkerRunnable.run(TaskExecutors.java:187) [eureka-core-1.6.2.jar:1.6.2] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60] Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to peer2:7002 timed out at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:123) ~[httpclient-4.5.3.jar:4.5.3] at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) ~[httpclient-4.5.3.jar:4.5.3] at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144) ~[httpclient-4.5.3.jar:4.5.3] at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134) ~[httpclient-4.5.3.jar:4.5.3] at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:610) ~[httpclient-4.5.3.jar:4.5.3] at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:445) ~[httpclient-4.5.3.jar:4.5.3] at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835) ~[httpclient-4.5.3.jar:4.5.3] at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:118) ~[httpclient-4.5.3.jar:4.5.3] at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) ~[httpclient-4.5.3.jar:4.5.3] at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:173) ~[jersey-apache-client4-1.19.1.jar:1.19.1] ... 10 common frames omitted
EurekaClientConfigBean.java 默认构造方法,如果serviceUrl.defaultZone = null 那么 就注册到 http://localhost:8761/eureka/
中去(日志会输出改地址,起初我是看的一脸懵逼),所以其他的Key都可以以 杠(-) 或者全大写方式,该处不行,因为人家源码是Map不是对象
public EurekaClientConfigBean() { this.serviceUrl.put("defaultZone", "http://localhost:8761/eureka/"); this.gZipContent = true; this.useDnsForFetchingServiceUrls = false; this.registerWithEureka = true; this.preferSameZoneEureka = true; this.availabilityZones = new HashMap(); this.filterOnlyUpInstances = true; this.fetchRegistry = true; this.dollarReplacement = "_-"; this.escapeCharReplacement = "__"; this.allowRedirects = false; this.onDemandUpdateStatusChange = true; this.clientDataAccept = EurekaAccept.full.name(); } public String[] getAvailabilityZones(String region) { String value = (String)this.availabilityZones.get(region); if(value == null) { value = "defaultZone"; } return value.split(","); } public List<String> getEurekaServerServiceUrls(String myZone) { String serviceUrls = (String)this.serviceUrl.get(myZone); if(serviceUrls == null || serviceUrls.isEmpty()) { serviceUrls = (String)this.serviceUrl.get("defaultZone"); } if(!StringUtils.isEmpty(serviceUrls)) { String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls); List<String> eurekaServiceUrls = new ArrayList(serviceUrlsSplit.length); String[] var5 = serviceUrlsSplit; int var6 = serviceUrlsSplit.length; for(int var7 = 0; var7 < var6; ++var7) { String eurekaServiceUrl = var5[var7]; if(!this.endsWithSlash(eurekaServiceUrl)) { eurekaServiceUrl = eurekaServiceUrl + "/"; } eurekaServiceUrls.add(eurekaServiceUrl); } return eurekaServiceUrls; } else { return new ArrayList(); } }
其实我是比较倾向于 consul
这种零侵入式的,但是 consul
在做高可用比较操蛋,它对外暴露的是 agent
如果你这个 agent
挂了,那么后面服务就GG思密达了,cloud service 不允许配置多个 agent
,个人没找到好的解决方案,有好方案的可以交流…..
全文代码: http://git.oschina.net/battcn/battcn-cloud/tree/master/battcn-cloud-feign
本章代码(Eureka-Cluster): https://git.oschina.net/battcn/battcn-cloud/tree/master/battcn-cloud-discovery
本章代码(Client-H1/H2): https://git.oschina.net/battcn/battcn-cloud/tree/master/battcn-cloud-discovery-cluster-test
如有问题请及时与我联系
个人QQ:1837307557
Spring Cloud中国社区①:415028731
Spring For All 社区⑤:157525002
欢迎一起讨论与交流
转载标明出处,thanks
谢谢你请我吃糖果
支付宝
微信