第三章 spring cloud eureka 配置 2.1.4版本


前言

服務治理

服務治理是微服務中最為核心和基礎的模塊,主要實現各個微服務的自動化注冊和發現;為什么使用服務治理:隨着業務的發展,系統功能越來越復雜,相應的微服務也不斷增加,那么多的微服務應用當修改服務命名等,如果通過手工維護方式,容易出現命名沖突等問題;
服務注冊: 在服務治理框架中,通過創建一個注冊中心,每個服務向注冊中心注冊自己的服務,將端口號,版本號,通訊協議等信息上報注冊中心,注冊中心按照服務名進行分類,當注冊上來后,注冊中心會根據心跳方式去檢測上報的服務是否存活,如不存活就賜予飛機票;

服務發現

在服務治理框架中,服務調用不是指定具體實例來調用,而是通過請求服務名來調用;服務調用方調用時不知具體服務在何方,而是通過注冊中心獲取服務清單,當服務調用方發起調用時通過某種輪訓機制取出一個服務去掉用;

高可用的注冊中心

當注冊中心發生故障時候會導致服務群癱瘓,所以需要高可用的注冊中心,eureka server支持高可用的配置,在eureka服務治理中,所有節點既是服務提供方也是服務消費方,注冊中心也一樣;eureka server的高可用實際上將自己當做服務向其他注冊中心注冊,多個服務相互注冊,這樣就形成了一組高可用的注冊中心,注冊中心相互注冊獲取清單,如果有一個掛了,也不會影響服務群;

高可用比率

通過時間計算;比如:保證一年的可用性為99.99%;

可用時間就是:365 * 24 * 3600 * 99.99%
不可用時間就是:365 * 24 * 3600 * 0.01% = 3153.6s
單台機器不可用比率:1%
兩台機器不可用比率:1% * 1%
N 機器不可用比率:1% ^ n

可靠性

一次調用a->b->c 99%->99%->99%=97%
a->b->c->d 99%->99%->99%->99%=96%

總結

增加機器可以提高可用性,增加服務調用會降低可靠性,同時降低了可用性;

 

spring-cloud-eureka-server

失效剔除

eureka.server.eviction-interval-timer-in-ms: 清理無效節點的時間間隔;
服務如果正常下線,會告知eureka server,eureka server會剔除當前下線的服務,但是如果異常下線,將不會告知eureka server,這時eureka server會啟動一個定時任務,默認每個一段時間(60s) 將當前清單中超過一段時間(90s)的沒有續約服務剔除

自我保護

eureka.server.enable-self-preservation: 
eureka server 中會出現一個問題,如圖
該警告觸發Eureka Server 自我保護機制,服務注冊到eureka server都會維護一個心跳,告訴eureka server我還活着,eureka server 在運行期間,會統計心跳失敗的比例,15分鍾之內低於85%;他會保留當前的實例注冊信息,讓他們不過期,但是調用服務時候會出現調用失敗情況,這時候就要有容錯機制,請求重試或者斷路器等;這個系統默認開啟自我保護機制;官方解釋https://github.com/Netflix/eureka/wiki/Understanding-Eureka-Peer-to-Peer-Communication 
更多的eureka server配置項查看EurekaServerConfigBean

訪問start.spring.io, 引入web,actuator,eureka-server

主程序入口

 1 package cn.cold.springcloudeurekaserver.springcloudeurekaserverdemo;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
 6 
 7 @SpringBootApplication
 8 @EnableEurekaServer
 9 public class SpringCloudEurekaServerDemoApplication {
10 
11     public static void main(String[] args) {
12         SpringApplication.run(SpringCloudEurekaServerDemoApplication.class, args);
13     }
14 }

properties文件

application-peer1.properties

1 spring.application.name=spring-cloud-eureka-server
2 server.port=9090
3 #是否檢索服務
4 eureka.client.fetch-registry=false
5 #是否注冊到eureka,這里如果配置相互依賴那么必須要設置為true
6 eureka.client.register-with-eureka=true
7 #服務注冊中心的配置內容,指定服務注冊中心的位置
8 eureka.client.service-url.defaultZone=http://localhost:9091/eureka/

application-peer2.properties

1 spring.application.name=spring-cloud-eureka-server
2 server.port=9091
3 eureka.client.fetch-registry=false
4 eureka.client.register-with-eureka=true
5 eureka.client.service-url.defaultZone=http://localhost:9090/eureka/

以上兩個就可以構成高可用注冊中心,使用命令行進行打包,執行

java -jar spring-cloud-eureka-server-demo-0.0.1-SNAPSHOT.jar --management.endpoints.web.exposure.include=* --eureka.server.enable-self-preservation=false --spring.profiles.active=peer1

java -jar spring-cloud-eureka-server-demo-0.0.1-SNAPSHOT.jar --management.endpoints.web.exposure.include=* --eureka.server.enable-self-preservation=false --spring.profiles.active=peer2

分別啟動兩個注冊中心,讓他們相互注冊如圖:

 

spring-cloud-eureka-client

start.spring.io,引入web,actuator,eureka discovery 

這里我們將刪除src目錄,然后添加pom文件中

<packaging>pom</packaging>

 

然后在當前目錄添加maven子項目,如圖

創建子項目后,在父項目的pom一定要有

 <modules>
        <module>user-api</module>
        <module>user-consumer</module>
        <module>user-service-provider</module>
 </modules>

目錄結構,如圖

  

user-api 

User.java

 1 package cn.cold.user.api.domain;
 2 
 3 /*
 4  * @create 2019-05-07 19:46
 5  * @Author 江湖人稱洗發水
 6  * @Description //TODO
 7  **/
 8 public class User {
 9     private int id;
10     private String name;
11 
12     public int getId() {
13         return id;
14     }
15 
16     public void setId(int id) {
17         this.id = id;
18     }
19 
20     public String getName() {
21         return name;
22     }
23 
24     public void setName(String name) {
25         this.name = name;
26     }
27 
28     @Override
29     public String toString() {
30         return "User{" +
31                 "id=" + id +
32                 ", name='" + name + '\'' +
33                 '}';
34     }
35 }
UserService.java
 1 package cn.cold.user.api.service;
 2 
 3 import cn.cold.user.api.domain.User;
 4 
 5 import java.util.List;
 6 
 7 /**
 8  * @author mengll
 9  * @date 2019/5/7 19:47
10  */
11 public interface UserService {
12 
13     boolean save(User user);
14 
15     List<User> findAll();
16 }

pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <parent>
 6         <groupId>org.springframework.boot</groupId>
 7         <artifactId>spring-boot-starter-parent</artifactId>
 8         <version>2.1.4.RELEASE</version>
 9         <relativePath/> <!-- lookup parent from repository -->
10     </parent>
11     <groupId>cn.cold</groupId>
12     <artifactId>user-api</artifactId>
13     <version>0.0.1-SNAPSHOT</version>
14     <name>user-api</name>
15     <description>Demo project for Spring Boot</description>
16 
17 </project>

user-service-consumer

 

UserServiceProxy.java
 1 package cn.cold.user.consumer.service;
 2 
 3 import cn.cold.user.api.domain.User;
 4 import cn.cold.user.api.service.UserService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.stereotype.Service;
 7 import org.springframework.web.client.RestTemplate;
 8 
 9 import java.util.List;
10 
11 /*
12  * @create 2019-05-07 19:49
13  * @Author 江湖人稱洗發水
14  * @Description //TODO
15  **/
16 @Service
17 public class UserServiceProxy implements UserService {
18 
19     private static final String PROVIDER_SERVER_URL_PREFIX = "http://user-service-provider";
20 
21     @Autowired
22     private RestTemplate restTemplate;
23 
24     @Override
25     public boolean save(User user) {
26         //端口會自動加上
27         return restTemplate.postForEntity(PROVIDER_SERVER_URL_PREFIX + "/user/save", user, User.class) != null;
28     }
29 
30     @Override
31     public List<User> findAll() {
32         return restTemplate.getForObject(PROVIDER_SERVER_URL_PREFIX + "/user/list", List.class);
33     }
34 }
UserRestApiController.java
 1 package cn.cold.user.consumer.web.controller;
 2 
 3 import cn.cold.user.api.domain.User;
 4 import cn.cold.user.api.service.UserService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.cloud.client.discovery.DiscoveryClient;
 7 import org.springframework.web.bind.annotation.GetMapping;
 8 import org.springframework.web.bind.annotation.PostMapping;
 9 import org.springframework.web.bind.annotation.RequestParam;
10 import org.springframework.web.bind.annotation.RestController;
11 
12 import java.util.List;
13 
14 /*
15  * @create 2019-05-07 19:50
16  * @Author 江湖人稱洗發水
17  * @Description //TODO
18  **/
19 @RestController
20 public class UserRestApiController {
21 
22     @Autowired
23     private UserService userService;
24     @Autowired
25     private DiscoveryClient discoveryClient;
26 
27 
28     @PostMapping("/save")
29     public User save(@RequestParam String name) {
30         User user = new User();
31         user.setName(name);
32         if (userService.save(user)) {
33             return user;
34         } else {
35             return null;
36         }
37     }
38 
39     @GetMapping("/list")
40     public List<User> list(){
41         System.out.println(discoveryClient.description());
42         System.out.println("11111111111111");
43         return userService.findAll();
44     }
45 }

主程序

 1 package cn.cold.user.consumer;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 6 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.web.client.RestTemplate;
 9 
10 @SpringBootApplication
11 @EnableDiscoveryClient
12 public class UserConsumerApplication {
13 
14     public static void main(String[] args) {
15         SpringApplication.run(UserConsumerApplication.class, args);
16     }
17 
18     @Bean
19     @LoadBalanced  //負載均衡
20     public RestTemplate restTemplate(){
21         return new RestTemplate();
22     }
23 }

application.properties

1 spring.application.name=user-service-consumer
2 ## 服務消費方端口
3 server.port=8080
4 ## Eureka Server 服務 URL,用於客戶端注冊
5 eureka.client.serviceUrl.defaultZone=\
6   http://localhost:9090/eureka,http://localhost:9091/eureka
7 ## Management 安全失效
8 management.endpoints.web.exposure.include=*

pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <parent>
 6         <groupId>cn.cold.springcloudeurekaclient</groupId>
 7         <artifactId>spring-cloud-eureka-client-demo</artifactId>
 8         <version>0.0.1-SNAPSHOT</version>
 9     </parent>
10     <groupId>cn.cold</groupId>
11     <artifactId>user-consumer</artifactId>
12     <version>0.0.1-SNAPSHOT</version>
13     <name>user-consumer</name>
14     <description>Demo project for Spring Boot</description>
15 
16     <dependencies>
17         <dependency>
18             <groupId>cn.cold</groupId>
19             <artifactId>user-api</artifactId>
20             <version>${project.version}</version>
21         </dependency>
22     </dependencies>
23 
24 </project>

 

user-service-provider

UserRepository.java
 1 package cn.cold.user.service.provider.repository;
 2 
 3 import cn.cold.user.api.domain.User;
 4 import org.springframework.stereotype.Repository;
 5 
 6 import java.util.ArrayList;
 7 import java.util.Collection;
 8 import java.util.List;
 9 import java.util.concurrent.ConcurrentHashMap;
10 import java.util.concurrent.ConcurrentMap;
11 import java.util.concurrent.atomic.AtomicInteger;
12 import java.util.concurrent.atomic.AtomicLong;
13 
14 /*
15  * @create 2019-05-07 20:17
16  * @Author 江湖人稱洗發水
17  * @Description //TODO
18  **/
19 @Repository
20 public class UserRepository {
21 
22     private List<User> repository = new ArrayList<>();
23 
24     private static final AtomicInteger idGenerator =
25             new AtomicInteger(0);
26 
27     public List<User> findAll() {
28         return repository;
29     }
30 
31     public boolean save(User user) {
32         Integer id = idGenerator.incrementAndGet();
33         user.setId(id);
34         return repository.add(user);
35     }
36 }
UserServiceImpl.java
 1 package cn.cold.user.service.provider.service;
 2 
 3 import cn.cold.user.api.domain.User;
 4 import cn.cold.user.api.service.UserService;
 5 import cn.cold.user.service.provider.repository.UserRepository;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.stereotype.Service;
 8 
 9 import java.util.List;
10 
11 /*
12  * @create 2019-05-07 20:16
13  * @Author 江湖人稱洗發水
14  * @Description //TODO
15  **/
16 @Service
17 public class UserServiceImpl implements UserService {
18 
19     @Autowired
20     private UserRepository userRepository;
21 
22     @Override
23     public boolean save(User user) {
24         return userRepository.save(user);
25     }
26 
27     @Override
28     public List<User> findAll() {
29         return userRepository.findAll();
30     }
31 }
UserServiceProviderRestApiController.java
 1 package cn.cold.user.service.provider.web.controller;
 2 
 3 import cn.cold.user.api.domain.User;
 4 import cn.cold.user.api.service.UserService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.web.bind.annotation.GetMapping;
 7 import org.springframework.web.bind.annotation.PostMapping;
 8 import org.springframework.web.bind.annotation.RequestBody;
 9 import org.springframework.web.bind.annotation.RestController;
10 
11 import java.util.List;
12 
13 /*
14  * @create 2019-05-07 20:14
15  * @Author 江湖人稱洗發水
16  * @Description //TODO
17  **/
18 @RestController
19 public class UserServiceProviderRestApiController {
20     @Autowired
21     private UserService userService;
22 
23     @PostMapping("/user/save")
24     public User saveUser(@RequestBody User user) {
25         if (userService.save(user)) {
26             System.out.println("UserService 服務方:保存用戶成功!" + user);
27             return user;
28         } else {
29             return null;
30         }
31     }
32 
33     @GetMapping("/user/list")
34     public List<User> list() {
35         return userService.findAll();
36     }
37 }

主程序

 1 package cn.cold.user.service.provider;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 6 
 7 @SpringBootApplication
 8 @EnableDiscoveryClient
 9 public class UserServiceProviderApplication {
10 
11     public static void main(String[] args) {
12         SpringApplication.run(UserServiceProviderApplication.class, args);
13     }
14 
15 }

application.properties

更多的eureka client配置項可以查看EurekaInstanceConfigBean和EurekaClientConfigBean;
org.springframework.cloud.spring-cloud-netflix-eureka-client.2.1.1.RELEASE.spring-cloud-netflix-eureka-client-2.1.1.RELEASE.jar!\META-INF\spring-configuration-metadata.json;這個json也有比較詳細描述
其他配置可在spring-configuration-metadata.json找到這里就不一一舉例了;

 1 spring.application.name=user-service-provider
 2 ## 服務消費方端口
 3 server.port=7071
 4 ## Eureka Server 服務 URL,用於客戶端注冊
 5 eureka.client.serviceUrl.defaultZone=\
 6   http://localhost:9090/eureka,http://localhost:9091/eureka
 7 ## Management 安全失效
 8 management.endpoints.web.exposure.include=*
 9 # 心跳時間,即服務續約間隔時間(缺省為30s)
10 eureka.instance.lease-renewal-interval-in-seconds=5
11 # 即服務續約到期時間(缺省為90s)
12 eureka.instance.lease-expiration-duration-in-seconds=15  

pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <parent>
 6         <groupId>cn.cold.springcloudeurekaclient</groupId>
 7         <artifactId>spring-cloud-eureka-client-demo</artifactId>
 8         <version>0.0.1-SNAPSHOT</version>
 9     </parent>
10     <groupId>cn.cold</groupId>
11     <artifactId>user-service-provider</artifactId>
12     <version>0.0.1-SNAPSHOT</version>
13     <name>user-service-provider</name>
14     <description>Demo project for Spring Boot</description>
15     <dependencies>
16         <dependency>
17             <groupId>cn.cold</groupId>
18             <artifactId>user-api</artifactId>
19             <version>0.0.1-SNAPSHOT</version>
20         </dependency>
21     </dependencies>
22 
23 </project>

 

以上就是eureka client的代碼;這里啟動一個consumer,然后啟動兩個provider, 這里consumer和一個provider用idea,另外一個provider用命令行啟動

 java -jar user-service-provider-0.0.1-SNAPSHOT.jar --server.port=7070

注冊好了如圖:

 

測試

 

 

 

這里再次訪問http://localhost:8080/list ,一會有值,一會沒值,這里因為是兩個服務,沒有做數據同步,所以出現該情況,但是也證明了@LoadBalanced確實負載均衡了;

由於篇幅原因,配置的就到此為止,后期會補一些Netflix Ribbon和RestTemplate,還有一些eureka 分析


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM