2018年7月,官方宣布Eureka 2.x停止开源计划了。
详细请看:http://github.com/Netflix/eureka/wiki
尴尬了。
介绍 Eureka是Spring Cloud中的一个负责服务注册与发现的组件。遵循着CAP理论中的A(可用性)、P(分区容错性)。
一个Eureka中分为eureka server和eureka client。其中eureka server是作为服务的注册与发现中心。eureka client既可以作为服务的生产者,又可以作为服务的消费者。
如图:
简单例子 服务注册中心 创建一个基础工程Spring Boot,命名:eureka-server,pom.xml内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <!-- springboot版本与springcloud须匹配 --> <version>2.1.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>eureka-server</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <!-- springboot版本与springcloud须匹配 --> <spring.boot.version>2.1.4.RELEASE</spring.boot.version> <spring.cloud.version>Greenwich.SR1</spring.cloud.version> <spring.maven.version>2.4.1</spring.maven.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</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> <version>${spring.maven.version}</version> </plugin> </plugins> </build> </project>
打开application.properties,内容设置为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #服务端口 server.port=8077 #服务名称 spring.application.name=eureka-server #服务地址 eureka.instance.hostname=localhost #不向注册中心注册自己 eureka.client.register-with-eureka=false #取消检索服务 eureka.client.fetch-registry=false #开启注册中心的保护机制,默认是开启 eureka.server.enable-self-preservation=true #设置保护机制的阈值,默认是0.85。 eureka.server.renewal-percent-threshold=0.5 #注册中心路径,如果有多个eureka server,在这里需要配置其他eureka server的地址,用","进行区分,如"http://address:8888/eureka,http://address:8887/eureka" eureka.client.service-url.default-zone=http://${eureka.instance.hostname}:${server.port}/eureka
在EurekaServerApplication.java类,加入:
如: EurekaServerApplication.java类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
启动后,打开浏览器输入:http://127.0.0.1:8077/ ,可以看到Eureka面板,其中 Instances currently registered with Eureka 为空,那就证明注册中心没有注册任何服务。
如图:
服务提供者 创建一个基础工程Spring Boot,命名:Demo,pom.xml内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <!-- springboot版本与springcloud须匹配 --> <version>2.1.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.demo1</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <!-- springboot版本与springcloud须匹配 --> <spring.boot.version>2.1.4.RELEASE</spring.boot.version> <spring.cloud.version>Greenwich.SR1</spring.cloud.version> <spring.maven.version>2.4.1</spring.maven.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </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> <!-- jar包的名字,默认为project/name节点 --> <!-- <finalName>demo</finalName> --> <plugins> <!--加入插件--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring.maven.version}</version> <!-- 打jar包注意事项 --> <configuration> <!-- 入口类的全限包名 --> <mainClass>com.demo1.demo</mainClass> <layout>JAR</layout> </configuration> </plugin> </plugins> <resources> <!-- 打包时将jsp文件拷贝到META-INF目录下--> <resource> <!-- 指定resources插件处理哪个目录下的资源文件 --> <directory>src/main/webapp</directory> <!--注意此次必须要放在此目录下才能被访问到--> <targetPath>META-INF/resources</targetPath> <includes> <include>**/**</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/**</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/java</directory> <excludes> <exclude>**/*.java</exclude> </excludes> </resource> </resources> </build> </project>
打开application.properties,内容设置为:
1 2 3 4 5 6 7 #服务端口 server.port=9091 #服务名称 spring.application.name=hello-service #eureka注册中心地址 eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8077/eureka/
在DemoApplication.java类,加入:
如: DemoApplication.java类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.demo1.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
创建HelloController.java,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.demo1.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient client;//服务发现客户端 @RequestMapping("/hello") public String hello() { System.out.println("Hello Spring Boot"); return "Hello Spring Boot"; } }
启动后,日志输出:
1 2 2020-12-12 22:49:40.115 INFO 4408 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_HELLO-SERVICE/PC-20190831IKWQ:hello-service:9091: registering service... 2020-12-12 22:49:40.514 INFO 4408 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_HELLO-SERVICE/PC-20190831IKWQ:hello-service:9091 - registration status: 204
转到Eureka面板,在Instances currently registered with Eureka看到服务的注册信息,
如图:
服务发现与消费 服务发现的任务由Eureka的客户端完成。
服务消费的任务由Ribbon完成。
Ribbon是一个基于HTTP和TCP的客户端负载均衡器,当将Ribbon和Eureka一起使用时,Ribbon会到Eureka注册中心去获取服务端列表,然后进行轮询访问以到达负载均衡的作用,客户端负载均衡也需要心跳机制去维护服务端清单的有效性,当然这个过程需要配合服务注册中心一起完成。
为了实验Ribbon的客户端负载均衡功能,以命令来启动两个不同端口的hello-servicer(服务提供方),
1 2 3 4 cd D:\Workspaces\demo\target\ java -jar demo-0.0.1-SNAPSHOT.jar --server.port=9001 java -jar demo-0.0.1-SNAPSHOT.jar --server.port=9002
转到Eureka面板,在Instances currently registered with Eureka看到服务的注册信息,
如图:
创建一个基础工程Spring Boot,命名: demo-consumer,pom.xml内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <!-- springboot版本与springcloud须匹配 --> <version>2.1.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo-consumer</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <!-- springboot版本与springcloud须匹配 --> <spring.boot.version>2.1.4.RELEASE</spring.boot.version> <spring.cloud.version>Greenwich.SR1</spring.cloud.version> <spring.maven.version>2.4.1</spring.maven.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </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> <version>${spring.maven.version}</version> </plugin> </plugins> </build> </project>
打开application.properties,内容设置为:
1 2 3 4 5 6 #服务端口 server.port=9101 #服务名称 spring.application.name=ribbon-consumer #eureka注册中心地址 eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8077/eureka/
在DemoConsumerApplication.java类,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.example.democonsumer; 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.client.RestTemplate; @EnableDiscoveryClient @SpringBootApplication public class DemoConsumerApplication { @Bean // 让RestTemplate在请求时拥有客户端负载均衡的能力 @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DemoConsumerApplication.class, args); } }
创建ConsumerController.java,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.example.democonsumer.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @RestController public class ConsumerController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private RestTemplate restTemplate; @RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET) public String helloConsumer() { //服务提供方服务名称 String memberUrl = "http://HELLO-SERVICE/hello"; String result = restTemplate.getForObject(memberUrl, String.class); System.out.println("访问结果" + result); return result; } }
启动后,日志输出:
1 2 2020-12-13 13:04:59.166 INFO 6620 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_RIBBON-CONSUMER/PC-20190831IKWQ:ribbon-consumer:9101: registering service... 2020-12-13 13:04:59.213 INFO 6620 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_RIBBON-CONSUMER/PC-20190831IKWQ:ribbon-consumer:9101 - registration status: 204
转到Eureka面板,在Instances currently registered with Eureka看到服务的注册信息,
如图:
打开网址,输入:http://127.0.0.1:9101/ribbon-consumer , 日志输出:
1 2 3 4 5 6 2020-12-13 13:07:07.652 INFO 6620 --- [io-9101-exec-10] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client HELLO-SERVICE initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=HELLO-SERVICE,current list of Servers=[PC-20190831IKWQ:9001, PC-20190831IKWQ:9002],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;] },Server stats: [[Server:PC-20190831IKWQ:9001; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] , [Server:PC-20190831IKWQ:9002; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] ]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@6d194ff3 访问结果Hello Spring Boot
从日志可以看到,Ribbon输出了当前客户端维护的服务列表情况:
1 NFLoadBalancer:name=HELLO-SERVICE,current list of Servers=[PC-20190831IKWQ:9001, PC-20190831IKWQ:9002])
Ribbon按此服务列表信息进行轮询访问,以实现基于客户端的负载均衡。在服务消费方,多发送几次请求:http://127.0.0.1:9101/ribbon-consumer ,可以观察判断客户端的负载均衡是否有效。