第三章 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 分析

原文地址:https://www.cnblogs.com/aizhouhui/p/10837475.html