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 ,可以觀察判斷客戶端的負載均衡是否有效。