SpringCloud学习(二)服务治理

SpringCloud 服务治理

  1. Actuator

    微服务架构中我们将原本庞大的单体系统拆分为多个提供不同服务的应用,随着应用不断的增加,系统集群出现故障的服务也变得越来越多,要做到高效的运维需要实现一套自动化监控运维机制,用来不间断地收集各个微服务应用的各项指标来制定监控和预警规则,SpringBoot提供了一个特殊依赖模块spring-boot-starter-actuator为应用提供了一系列用于监控的端点,如

    • 为服务治理组件Eureka提供/health端点增加相关信息
    • 为API网管组件Zuul提供/routes端点返回路由信息

    这样可以大量减少监控系统在采集应用指标时的开发量

    1. 引入Actuator依赖

      1
      2
      3
      4
      5
      <!--actuator服务监控与管理模块-->
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
    2. 配置Actuator:在application.properties中编写配置暴露所有监控端点信息

      1
      2
      3
      4
      5
      # ACTUATOR
      # 暴露所有端点
      management.endpoints.web.exposure.include = *
      # 详细的health信息
      management.endpoint.health.show-details=always
    3. 原生端点:spring-boot-starter-actuator模块实现了一些原生端点,根据作用可以分为三类

      • 应用配置类:获取程序中加载的应用配置、环境配置等配置类信息
        • beans:获取Spring Context创建所有Bean
        • configprops:获取应用中配置(@ConfigurationProperties )的属性信息报告
        • env:获取应用的环境属性报告
        • mappings:获取所有SpringMVC的(@RequestMapping)路径的整理列表
        • info:获取应用自定义信息
      • 度量指标类:获取程序运行过程中监控的度量指标,如内存信息、线程池信息、HTTP请求统计等
        • metrics:当前应用的各类度量指标,如内存、线程、垃圾回收信息
        • health:应用各类健康指标信息
      • 操作控制类:提供对应用关闭等操作类操作
        • shutdown:关闭应用
    4. 使用Actuator获取信息:Actuator采用RESTful Api方式返回JSON形式的信息,开启应用后访问[localhost:端口号/actuator/端点名称]即可获取数据

  2. 服务治理-Spring Cloud Eureka

    Spring Cloud对基于Netflix Eureka服务治理组件进行二次封装来完成服务治理架构,对于集群规模大、服务多的系统,使用服务治理来进行注册、发现服务比静态配置指定服务方便管理和开发,Netflix Eureka实现了服务注册和服务发现模块,提供了服务端和客户端组件

    • 服务端组件:服务注册中心,提供高可用配置(集群部署),可以通过异步模式在集群的服务注册中心中相互复制各自的注册信息、状态等
    • 客户端组件:服务提供者和消费者,主要处理服务的注册和发现,服务注册通过向注册中心提供的服务信息并周期发送心跳来更新其服务租约,服务发现通过从注册中心查询当前注册的服务信息并将它们缓存到本地并周期性更新服务状态

    我们通过在本机简单搭建服务注册中心实现服务注册和发现功能来感受服务治理架构

    1. 搭建服务注册中心:

      1. 引入依赖:在Spring Boot的基础上在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
        <!--指定编码、JDK版本、SpringCloud版本-->
        <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
        </properties>
        <dependencies>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</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>
      2. 添加注解:在启动Spring Boot的主类中添加@EnableEurekaServcer注解启动Eureka服务端

        1
        2
        3
        4
        5
        6
        7
        @EnableEurekaServer
        @SpringBootApplication
        public class EurekaServerApplication {
        public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
        }
        }
      3. 服务端配置:在Spring Boot的配置文件如application.properties中配置Eureka服务端相应的参数

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        # 服务端运行端口
        server.port=1111

        # 配置主机名 默认为操作系统源语读取
        eureka.instance.hostname=localhost
        # 注册服务 默认true 由于注册中心本身不注册 改为false
        eureka.client.register-with-eureka=false
        # 发现服务 即是否从eureka服务器缓存eureka注册表信息 默认true
        eureka.client.fetch-registry=false
        # eureka服务器用于交互的URL 即服务器地址
        eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

        # 本机调试不使用注册中心的保护机制 保护机制统计心跳比例不能过低 过低则保护实例注册信息永不过期
        eureka.server.enable-self-preservation=false
      4. 运行服务端:启动项目,在浏览器输入服务器运行端口(不要输入服务器用于交互的地址)可浏览Eureka注册中心

    2. 编写服务提供者和服务消费者

      往往客户端实例即是服务提供者又是服务消费者

      • 服务提供者:主要功能为向服务注册中心注册提供的服务信息并周期发送心跳来更新其服务租约
      • 服务消费者:主要功能为向服务注册中心查询当前注册的服务信息并将它们缓存到本地并周期性更新服务状态

      我们编写一个Eureka客户端实例,在实例内实现一个Controller扮演服务提供者和一个Service扮演服务消费者

      1. 引入依赖:

        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
        <!--指定编码、JDK版本、SpringCloud版本-->
        <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
        </properties>
        <dependencies>
        <!--Spring Boot的Web依赖-->
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.0.3.RELEASE</version>
        </dependency>

        <!--actuator服务监控与管理模块-->
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!--Eureka服务治理依赖-->
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</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>
      2. 开启Eureka客户端:在Spring Boot的入口类中添加注解@EnableDiscoveryClient开启Eureka客户端

        • @EnableDiscoveryClient:基于spring-cloud-commons 在classpath实现 eureka、consul、zookeeper均可使用
        • @EnableEurekaClient:基于spring-cloud-netflix 只能为eureka使用
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        @EnableDiscoveryClient
        @SpringBootApplication
        public class EurekaClientApplication {

        @LoadBalanced //负载均衡
        @Bean //利用RestTemplate发现服务消费服务
        public RestTemplate restTemplate() {
        return new RestTemplate();
        }

        public static void main(String[] args) {
        SpringApplication.run(EurekaClientApplication.class, args);
        }
        }
      3. 编写配置:在Spring Boot的配置文件如application.properties中配置Eureka需要的相应的参数

        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
        # ACTUATOR 监控配置
        # 暴露所有端点
        management.endpoints.web.exposure.include = *
        # 详细的health信息
        management.endpoint.health.show-details=always

        # Eureka
        # 注册服务信息
        # 服务名称
        spring.application.name=TEST-SERVICE
        spring.profiles.active=default
        spring.cloud.config.allow-override=true

        # 配置服务中心信息
        # 注册服务的ip而不是服务器的名称
        eureka.instance.prefer-ip-address=true
        # 注册服务
        eureka.client.register-with-eureka=true

        # 获取服务 本地缓存服务信息清单
        eureka.client.fetch-registry=true
        # 缓存服务信息的更新时间
        eureka.client.registry-fetch-interval-seconds=30

        # 配置eureka服务中心地址
        eureka.client.service-url.defaultZone:http://localhost:1111/eureka/

        # eureka服务器在lease-expiration-duration-in-seconds内未接受到实例的心跳则从试图中删除实例
        # 服务续约任务调用时间 即向eureka服务器发送心跳的时间
        eureka.instance.lease-renewal-interval-in-seconds=30
        # 服务失效时间 即在此时间内未收到心跳则此实例的服务失效
        eureka.instance.lease-expiration-duration-in-seconds=90
      4. 创建服务提供者和服务消费者:服务提供一般采取controller将其接口暴露出来,服务消费者一般使用service调用服务接口,由于我们要验证service调用服务接口的效果,于是我们通过编写一个controller将其调用接口的返回结果展示出来

        项目结构:

        • controller.ProviderController:注册服务提供服务

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          @RestController
          public class ProviderController {

          @RequestMapping(value = "/demo",method = RequestMethod.GET,produces = "application/json;charset=UTF-8")
          public Map demo(
          @RequestParam("name") String name
          ){
          Map<Object,String> map=new HashMap<>();
          map.put("GetName",name);
          return map;
          }
          }
        • service.ConsumerService:发现服务消费服务

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          @Service
          public class ConsumerService {

          @Autowired
          RestTemplate restTemplate;

          //利用RestTemplate发现TEST-SERVICE服务并消费其demo接口
          public String getTestServiceDemo(String name){
          return restTemplate.getForEntity("http://TEST-SERVICE/demo?name="+name,String.class).toString();
          }

          }
        • controller.ConsumerController:调用service.ConsumerService消费ProviderController提供的服务并将其返回结果展示

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          @RestController
          public class ConsumerController {

          @Autowired
          ConsumerService consumerService;

          @RequestMapping(value = "/getDemo",method = RequestMethod.GET)
          public String demo(
          @RequestParam("name") String name
          ){
          String response=consumerService.getTestServiceDemo(name);
          return response;
          }
          }
      5. 运行实例测试服务:

        • 运行实例,打开Eureka注册中心可看到实例注册后提供的服务

        • 测试服务提供的接口

        • 测试发现服务消费服务