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

  • 相关阅读:
    Java 8 ThreadLocal 源码解析
    RabbitMQ 消息中间件
    MySQL 索引与查询优化
    MySQL EXPLAIN 命令: 查看查询执行计划
    迎来送往,开启新篇章
    mockito的用法
    推荐一个计算机的科普视频
    Golang查缺补漏(一)
    2019定个小目标
    golang 中的指针
  • 原文地址:https://www.cnblogs.com/aizhouhui/p/10837475.html
Copyright © 2020-2023  润新知