SpringCloud常用组件学习

文章目录

SpringCloud学习

Eureka注册中心基础搭建

还有一个集中配置中心(很方便和关键)

Netflix Eureka

服务中心,云端服务发现,一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移。这个可是springcloud最牛鼻的小弟,服务中心,任何小弟需要其它小弟支持什么都需要从这里来拿,同样的你有什么独门武功的都赶紧过报道,方便以后其它小弟来调用;它的好处是你不需要直接找各种什么小弟支持,只需要到服务中心来领取,也不需要知道提供支持的其它小弟在哪里,还是几个小弟来支持的,反正拿来用就行,服务中心来保证稳定性和质量。

Netflix Ribbon

Ribbon是一个客户端负载均衡组件,帮我们实现后端服务节点动态扩容,而不影响调用方。

Ribbon的使用方法

Eureka和Feign中已经默认集成了Ribbon,

如果项目中引入了Eureka,通过在RestTemplate上添加@LoadBalanced;

如果用的是Feign声明式REST客户端,feign默认就已经帮我们开启了ribbon负载均衡能力。

搭建工程过程:pom——yml——Application——应用层(业务代码)

1. *父工程依赖pom文件(SpringCloud-parent)

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cxp</groupId>
    <artifactId>springcloud-parent</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <!-- 定义SpringBoot依赖版本 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>2.1.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- 注意:SpringCloud最新的Greenwich版本是基于SpringBoot2.1.x(Greenwich)版本构建的
                    所以这里不支持SpringBoot2.2.x版本
                    具体SpringBoot与SpringCloud版本对应关系参见:https://spring.io/projects/spring-cloud页面最下方的Release Trains
                 -->
            <!--<version>2.2.1.RELEASE</version>-->


            <!-- 定义SpringCloud依赖版本 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

2. *SpringCloud-eureka-server(服务者)

配置文件:

server:
  port: 8761


eureka:
  instance:
    prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
    #instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
    hostname: cloud.study.com
  client:
    # 是否将当前应用注册到eureka中
    registerWithEureka: true
    # 是否从eureka注册中心中拉取服务提供者列表
    fetchRegistry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

spring:
  application:
    name: eureka-server

拓展:*jdk1.8配置( pom.xml)

<!-- 配置maven编码字符、编译版本 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>

3. *springcloud-eureka-server-cloud 模块(高可用的服务者)

spring:
  application:
    name: eureka-server

eureka:
  instance:
    prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
    #instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
    hostname: cloud.study.com
  client:
    # 是否将当前应用注册到eureka中
    registerWithEureka: true
    # 是否从eureka注册中心中拉取服务提供者列表
    fetchRegistry: true
    service-url:
      defaultZone: http://cloud02.study.com:8762/eureka/,http://cloud03.study.com:8763/eureka/

server:
  port: 8761

---
spring:
  profiles: cloud02

server:
  port: 8762

eureka:
  instance:
    hostname: cloud02.study.com
  client:
    service-url:
      defaultZone: http://cloud.study.com:8761/eureka/,http://cloud03.study.com:8763/eureka/

---
spring:
  profiles: cloud03

server:
  port: 8763

eureka:
  instance:
    hostname: cloud03.study.com
  client:
    service-url:
      defaultZone: http://cloud.study.com:8761/eureka/,http://cloud02.study.com:8762/eureka/

注:这个cloud需要一一都启动起来:才不会报错

在这里插入图片描述

4. *Provider(cloud提供者)

配置文件;

server:
  port: 8765


eureka:
  instance:
    prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
    #instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
    hostname: cloud.study.com
  client:
    # 是否将当前应用注册到eureka中
    registerWithEureka: true
    # 是否从eureka注册中心中拉取服务提供者列表
    fetchRegistry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

spring:
  application:
    name: eureka-server

5. *Consumer(cloud消费者)

yml文件:

spring:
  application:
    name: service-consumer

eureka:
  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${eureka.client.eureka-server-port}/eureka/
    eureka-server-port: 8765
  instance:
    prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
    hostname: cloud.study.com

server:
  port: 8082

学习理解:

微服务 Rpc和Rest协议

接口调用通常包含两个部分,序列化和通信协议。常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等;通信比较流行的是http、soap、websockect,RPC通常基于TCP实现,常用框架例如dubbo,netty、mina、thrift

  • Rest:严格意义上说接口很规范,操作对象即为资源,对资源的四种操作(post、get、put、delete),并且参数都放在URL上,但是不严格的说Http+json、Http+xml,常见的http api都可以称为Rest接口。
  • Rpc:我们常说的远程方法调用,就是像调用本地方法一样调用远程方法,通信协议大多采用二进制方式

Eureka的角色

Eureka 是 Netflix 开源的服务注册发现组件,服务端通过 REST 协议暴露服务,提供应用服务的注册和发现的功能。
所有的Eureka服务都被称为实例(instance)。Eureka服务又分为两类角色:Eureka Server和Eureka Client
Eureka-Client又分为Application Provider 和Application Consumer
Application Provider :服务提供者,内嵌 Eureka-Client ,它向 Eureka-Server 注册自身服务、续约、下线等操作
Application Consumer :服务消费者,内嵌 Eureka-Client ,它从 Eureka-Server 获取服务列表,分为全量获取和增量。

遇到的问题:

1. *两个注解

  • 开启应用的Eureka Server功能
    在应用启动类上加 @EnableEurekaServer注解

  • 开启应用的Eureka Client功能
    在应用启动类上加 @EnableEurekaClient注解

    • @EnableDiscoveryClient 注解

    这是SpringCloud通过的一个注解,所有的服务发现中心组件都可以使用(客户端和服务端使用的注解一样)

Feign声明式REST客户端

依赖eureka和Ribbon

Feign底层会根据我们配置的注解属性拼接得到最终访问的URI,根据接口中定义的方法的参数和返回值将请求参数、返回结果处理好,这些都是Feign通过帮我们生成代理实现类的方式完成的。

实现过程:

还是需要三方配合,那好处在哪里

过程:

  1. (外部路线)首先消费者的控制层——提供者的控制层(返回responseInfo)——返回页面(页面展示数据)
  2. 其次消费者的控制层通过(接口注解以及@RequestMapping("/calc"))——访问提供者的控制层(通过处理得到数据可以看成是消费者层级的接口实现)——回到消费者控制层返回页面数据
  3. 最后server端默默的做着他们之间的桥梁。

消费者控制层

@Controller
@RequestMapping("/calc")
public class CalcController {

    @Autowired
    private CalcServiceFeign calcServiceFeign;

    @RequestMapping("/add")
    public String add(@RequestParam int num1, @RequestParam int num2, Model model) {
        ResponseInfo responseInfo = calcServiceFeign.add(num1, num2);
        Map data = (Map) responseInfo.getData();
        model.addAttribute("num1", num1);
        model.addAttribute("num2", num2);
        model.addAttribute("result", data.get("result"));
        return "index";
    }
}

消费者的Feign(接口)

//提供者名字(provider)
@FeignClient(name = "SERVICE-PROVIDER")
@RequestMapping("/calc")
public interface CalcServiceFeign {

    @GetMapping("/add/{num1}/{num2}")
    ResponseInfo add(@PathVariable("num1") int num1,@PathVariable("num2") int num2);
}

提供者的控制层

@RestController
@RequestMapping("/calc")
public class CalcController {

    @Autowired
    private CalcServiceImpl calcService;

    @RequestMapping("/add/{num1}/{num2}")
    public ResponseInfo add(@PathVariable int num1, @PathVariable int num2) {
        int result = calcService.add(num1, num2);
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("num1", num1);
        data.put("num2", num2);
        data.put("operator", "+");
        data.put("result", result);
        return new ResponseInfo(200, "请求成功", data);

    }

} 

提供者的实现类

@Service
public class CalcServiceImpl {

    @Autowired
    private Registration registration;

    public int add(int num1, int num2) {

        String serviceInfo = registration.getHost() + "-" + registration.getInstanceId();

       
        return num1 + num2;
    }
} 	

server端默默的做着连接桥梁工作。

Hystrix 服务熔断、降级、限流、隔离

消费者模块两种方式

Ribbon: RestTemplate

Feign。分别做降级处理、步骤如下:

pom文件依赖

 <dependencies>
   
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

        <!-- 添加SpringBoot Actuator端点监控依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

    </dependencies>

完整配置文件:

spring:
  application:
    name: service-consumer-hystrix

server:
  port: 8082


eureka:
  instance:
    prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
    hostname: cloud.study.com

  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${eureka.client.eureka-server-port}/eureka/
    eureka-server-port: 8765

#hystris的配置
hystrix:
  command:
    calc_add_command:
##对应@HystrixCommand注解的commandKey属性,指定特定熔断器的属性(一般建议在代码中通过注解配置),此处换成default可修改全局属性。
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000 #设置熔断器判定超时的时间,超过此时间的请求会执行降级逻辑,默认1s
      circuitBreaker:
        requestVolumeThreshold: 2 #设置熔断阈值,在熔断统计窗口期内,错误请求(超时、异常)次数达到阈值就会触发熔断,执行降级逻辑,默认20
        sleepWindowInMilliseconds: 10000  #设置熔断器多久进入半开状态,然后再次尝试确定熔断器是否应再次关闭,默认5s
        errorThresholdPercentage: 50  #设置在熔断统计窗口期内,错误请求达到百分之多少触发熔断,默认50
      metrics:
        rollingStats:
          timeInMilliseconds: 5000 #熔断度量窗口期时间, 默认10s

#hystris.stream的配置
management:
  server:
    port: 8092
  endpoints:
    web:
      base-path: /actuator
      exposure:
        include: "*"



通过Properties修改指定HystrixCommand的参数

hystrix:
  command:
    hystrixCommandName (如:calc_add_command):  #对应@HystrixCommand注解的commandKey属性,指定特定熔断器的属性(一般建议在代码中通过注解配置),此处换成default可修改全局属性。
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000 #设置熔断器判定超时的时间,超过此时间的请求会执行降级逻辑,默认1s
      circuitBreaker:
        requestVolumeThreshold: 2 #设置熔断阈值,在熔断统计窗口期内,错误请求(超时、异常)次数达到阈值就会触发熔断,执行降级逻辑,默认20
        sleepWindowInMilliseconds: 10000  #设置熔断器多久进入半开状态,然后再次尝试确定熔断器是否应再次关闭,默认5s
        errorThresholdPercentage: 50  #设置在熔断统计窗口期内,错误请求达到百分之多少触发熔断,默认50
      metrics:
        rollingStats:
          timeInMilliseconds: 5000 #熔断度量窗口期时间, 默认10s

启动类(Ribbon方式):

@SpringBootApplication
@EnableEurekaClient
//@EnableHystrix    /*不是此注解*/
@EnableCircuitBreaker   //启用断路器
public class ConsumerHystrixApplication {

    @Bean
    @LoadBalanced      //(Ribbon)开启负载均衡
    public RestTemplate restTemplate(){

        return new RestTemplate();
    }
    public static void main(String[] args) {

        SpringApplication.run(ConsumerHystrixApplication.class,args);
    }
}

成功配置、添加hystrix的fallback方法

*在需要的方法上边添加注解

@HystrixCommand(
            fallbackMethod = "addFallback",
            commandKey = "calc_add_command"             
    )

//服务正常通过的方法。
public String add(){}



/**
     * 定义add方法的降级方法,当add方法调用远程服务出现问题,发生熔断时,hystrix会自动放弃调用原来的服务,转而调用降级方法
     * @param num1
     * @param num2
     * @param model
     * @return
     */
    public String addFallback(@RequestParam int num1, @RequestParam int num2, Model model) {
        model.addAttribute("num1", num1);
        model.addAttribute("num2", num2);
        model.addAttribute("result", "-1");
        return "index";
    }


模拟处理时间(provider——impl):

// 只是模拟处理时间长的服务调用
        Random random = new Random();
        int sleepTime = random.nextInt(3000);
        log.info("休眠时间:" + sleepTime+"ms.");
        try {
            Thread.sleep(sleepTime);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

Feign方式

配置文件也不同;(多个Feign的配置)

spring:
  application:
    name: service-consumer-feign-with-hystrix

server:
  port: 8082

eureka:
  instance:
    prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
    hostname: cloud.study.com

  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${eureka.client.eureka-server-port}/eureka/
    eureka-server-port: 8765

hystrix:
  command:
    default:
#    calc_add_command:
      ##对应@HystrixCommand注解的commandKey属性,指定特定熔断器的属性(一般建议在代码中通过注解配置),此处换成default可修改全局属性。
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000 #设置熔断器判定超时的时间,超过此时间的请求会执行降级逻辑,默认1s
      circuitBreaker:
        requestVolumeThreshold: 2 #设置熔断阈值,在熔断统计窗口期内,错误请求(超时、异常)次数达到阈值就会触发熔断,执行降级逻辑,默认20
        sleepWindowInMilliseconds: 10000  #设置熔断器多久进入半开状态,然后再次尝试确定熔断器是否应再次关闭,默认5s
        errorThresholdPercentage: 50  #设置在熔断统计窗口期内,错误请求达到百分之多少触发熔断,默认50
      metrics:
        rollingStats:
          timeInMilliseconds: 5000 #熔断度量窗口期时间, 默认10s
#hystris.stream的配置
management:
  server:
    port: 8092
  endpoints:
    web:
      base-path: /actuator
      exposure:
        include: "*"
feign:
  client:
    config:
      #calc-service-provider:  这一级可以写具体的微服务名称或者default,default代表全局配置,影响所有微服务的调用
      default:
        connectTimeout: 1000
        readTimeout: 2000
  hystrix:
    enabled: true

pom文件主要依赖(全)

<!-- 引入feign依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringCloud 格林威治版本中需要单独将hystrix依赖也添加上 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

        <!-- 引入eureka客户端依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入eureka依赖会自动将ribbon依赖一并引入,我们不需要自己单独添加 -->
        <!--<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>-->

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</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-actuator</artifactId>
        </dependency>
    </dependencies>

成功配置、添加hystrix的fallback方法

(改动地方:一个注解一个实现类(fallback))

//提供者名字(provider)
@FeignClient(name = "SERVICE-PROVIDER",fallback = CalcClientFallback.class)
@RequestMapping("/calc")
public interface CalcServiceFeign {

    @GetMapping("/add/{num1}/{num2}")

    ResponseInfo add(@PathVariable("num1") int num1, @PathVariable("num2") int num2);
}


有个坑(错误信息:)

There is already ‘calcClientFallback’ bean method

@Component
@RequestMapping("/fallback")  //此处只是为了避免重复(实现接口的时候和RestMapping一并继承了)
public class CalcClientFallback implements CalcServiceFeign{
    public ResponseInfo add(int num1, int num2) {
        Map data = new HashMap();
        data.put("num1", num1);
        data.put("num2", num2);
        data.put("result", -1);
        ResponseInfo responseInfo = new ResponseInfo(203,  "降级结果", data);
        return responseInfo;
    }
}

Feign和Ribbon(RestTemplate方式)

  1. 配置文件不同

Feign多了它自己的配置

feign:
  client:
    config:
#      calc-service-provider:  这一级可以写具体的微服务名称或者default,default代表全局配置,影响所有微服务的调用
      default:
        connectTimeout: 1000
        readTimeout: 2000
  hystrix:
    enabled: true

  1. 熔断的回调方式不同

    (RestTemplate 放在消费者的控制层复写方法加注解建立联系):[目录](*在需要的方法上边添加注解)

    Feign是通过接口添加另一个实现类也是通过注解建立联系:【目录】(上高亮处)

监控

基于spring-boot-starter-actuator的一项可视化图表工具

消费者工程添加依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

Dashboard、turbine

1. Hystrix Dashboard

Hystrix Dashboard是Hystrix给我们提供的实时查看单机熔断情况的工具。需要配合SpringBoot Actuator使用。

Hystrix Dashboard使用方法

Hystrix Dashboard就是一个独立的图表工具,与业务没有任何关联。我们可以单独创建一个工程,引入dashboard的包

  1. 需要的依赖
<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
    </dependencies>

  1. 启动类注解:@EnableHystrixDashboard

  2. 浏览器中访问:http://localhost:9000/hystrix 就可以打开dashboard首页了

    在这里插入图片描述

dashboard地址和turbine地址说明:

http://localhost:8092/actuator/hystrix.stream

ping的数据供dashboard收集成图表工具

把上述地址放到搜索框里面得到以下现象

在这里插入图片描述

上条地址的图表数据来源如下:

springboot 提供的监控数据

首页访问信息(基于actuator的hystrix.stream)

访问地址:http://localhost:8092/actuator/

后面可拼的其他路径:

beans、mappings、info、health。。。等

#hystris.stream的配置
management:
  server:
    port: 8092
  endpoints:
    web:
      base-path: /actuator
      #默认是health、info
      exposure:
        include: "*"

昨天还有一个知识点没练习完

2. Turbine(聚合服务)

  • DashBoard、turbine、hystrix stream三者之间的关系

在复杂的分布式系统中,相同服务的节点经常需要部署上百甚至上千个,很多时候,运维人员希望能够把相同服务的节点状态以一个整体集群的形式展现出来,这样可以更好的把握整个系统的状态。 为此,Netflix提供了一个开源项目(Turbine)来提供把多个hystrix.stream的内容聚合为一个数据源供Dashboard展示。

Turbine与Dashboard、Hystrix EventStream的关系

Turbine与Dashboard关系图

Turbine的使用方法

  1. 引入Turbine依赖

    <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-netflix-turbine</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
        </dependencies>
    
    
  2. 配置Turbine要监控的服务

    server:
      port: 9005
      
    #turbine 配置@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    turbine:
      app-config: calc-service-consumer-hystrix,calc-service-feign-consumer-with-hystrix
      cluster-name-expression: "'default'"
      aggregator:
        cluster-config: default
    
    #eureka配置Turbine需要从Eureka中获取服务列表,然后遍历每个服务每个节点上的hystrix.stream数据,然后汇聚到一起
    eureka:
      instance:
        prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
        instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
        hostname: node1.john.com
      client:
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${eureka.client.eureka-server-port}/eureka/
        eureka-server-port: 8761
    
    #hystrix.stream的配置@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
    
    
    • turbine.appConfig:配置Eureka中的serviceId列表,表明监控哪些服务
    • turbine.aggregator.clusterConfig:指定聚合哪些集群,多个使用”,”分割,默认为default。可使用http…turbine.streamcluster={clusterConfig之一}访问
    • turbine.clusterNameExpression
      1. clusterNameExpression指定集群名称,默认表达式appName;此时:turbine.aggregator.clusterConfig需要配置想要监控的应用名称;
      2. 当clusterNameExpression default时,turbine.aggregator.clusterConfig可以不写,因为默认就是default;
      3. 当clusterNameExpression metadata[‘cluster’]时,假设想要监控的应用配置了eureka.instance.metadata-map.cluster ABC,则需要配置,同时turbine.aggregator.clusterConfig ABC
    1. 启动类:
    @SpringBootApplication
    @EnableTurbine
    public class TurbineConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(TurbineConsumerApplication.class,args);
        }
    }
    
    
    
    1. 访问turbine.stream
      在浏览器中访问http://localhost:9005/turbine.stream 就可以看到配置到Turbine上的所有微服务产生的流式事件数据

    2. 在Hystrix Dashboard中查看所有、指定微服务的实时熔断监控。
      将上述地址输入到Hystrix Dashboard中即可查看所有微服务的监控情况,或者加上cluster=[clusterName] 参数,只看某个微服务的情况

    3. 在dashboard中查看聚合图表数据地址:http://localhost:9005/turbine.stream ?cluster=default

      在这里插入图片描述

Zuul(Netflix) - 统一网关、地址路由

主要用途:

1. 反向代理

2. 统一权限校验

3. 和hystrix的整合

​ 设置整体的熔断。


Zuul介绍

(在前端调用后台的时候加一层工程(看似就访问了一个端口服务,也就不存在跨域问题))

Zuul是Netflx开源的微服务网关。可以和Eureka、Ribbon、Hystrix配合使用,一个主要的功能就是可以将后端众多的微服务屏蔽、整合,对前端提供一套统一的服务(有点像是后端的Facade)

反向代理用法:

  1. 添加依赖

    <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
        </dependencies>
    
  2. 配置文件

    server:
      port: 9100
    spring:
      application:
        name: zuul-server
    
    eureka:
      client:
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${eureka.client.eureka-server-port}/eureka/
        eureka-server-port: 8765
      instance:
        prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
        instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
        hostname: cloud.study.com
    
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
    zuul:
      routes:
        # 这种方式配置路由规则:前面的key是微服务名称,后面是匹配路径(更安全)
        #service-provider: /calcApi/**
    
        # 这种方式配置路由规则:第一级的key可以随便取(路由名称),下面可以配置更多key、value(相比上面一种配置更强大)
        calc-proxy:
          serviceId: service-provider # 有效的微服务名称
          path: /calc/**  # 访问路径
          strip-prefix: false # 是否在网关层面消耗掉指定服务的路由规则前缀
        #    taotao-rest-proxy:
        #      serviceId: taotao-rest
        #      path: /rest/**
        taotao-rest-proxy-forward: # 使用forward本地转发(就是将匹配到路由规则的请求,转发到网关本地应用中去处理)
          path: /rest-f/**
          url: forward:/rest
        # 比如浏览器访问:http://localhost:9100/api/rest-f/content/getall/89
        # 会被转发到:http://localhost:9100/rest/content/getall/89
    
    
      ignored-services: "*" # 忽略所有未显示配置路由规则的微服务
      prefix: /api
      strip-prefix: true  # 是否在网关层面消耗掉全局前缀
    
    #淘淘商城测试
    # 使用Zuul代理未接入Eureka的传统服务
    taotao-rest:
      ribbon:
        NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList #如果不配置ServerList类型为ConfigurationBasedServerList的话就需要禁用ribbon的eureka支持
        ConnectTimeout: 500
        ReadTimeout: 2000
        listOfServers: http://localhost:8081
    
    #和hystrix不同  (配置超时)
    service-provider:   #微服务名称
      ribbon:
        ReadTimeout: 2000
        ConnectTimeout: 500
    
    
  3. 启动类

    @SpringBootApplication
    @EnableZuulProxy
    @EnableEurekaClient
    public class ZuulApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ZuulApplication.class,args);
        }
    }
    
    

    重点主要在它的application.yml文件中的配置。

Zuul的访问超时控制

通过ServiceId代理的请求

由于通过ServiceId的方式代理的请求(包括手动配置的Ribbon 服务和自动服务发现的服务)会走Ribbon和Hystrix,所以我们要控制超时就包括Ribbon请求的超时和Hystrix的访问超时。

test-service:
  ribbon:
    ReadTimeout:100
    ConnectTimeout:500
    MaxAutoRetries:1
    MaxAutoRetriesNextServer:1

上面这段配置通过Zuul访问test-service服务时,Ribbon的ConnectTimeout是500ms,ReadTimeout是100ms,重试次数为1次; Zuul会根据ribbon设置的超时时间和重试次数,自动设置Hystrix的超时时间(上面这段配置, Zuul会把Hystrix的超时时间设置为:(100+500)*2=1200ms
当然,我们也可以通过添加下面的配置显示指定Hystrix参数

hystrix:
  command:
    service-calc-ribbon:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

这里如果不显示设置,Zuul会根据ribbon设置的ConnectionTimeout和ReadTimeout自动确定Hystrix的超时时间(所以一般可以通过配置ribbon的超时时间来控制hystrix超时),由于ribbon默认重试次数是1,所以Hystrix的超时时间会被设置为(500+2000)*2=5000

Zuul的核心——Filter

Filter是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是“PRE”、“ROUTING”、“POST”、“ERROR”,
Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。
Zuul中默认实现的Filter
类型顺序过滤器功能
pre-3ServletDetectionFilter标记处理Servlet的类型
pre-2Servlet30WrapperFilter包装HttpServletRequest请求
pre-1FormBodyWrapperFilter包装请求体
route1DebugFilter标记调试标志
route5PreDecorationFilter处理请求上下文供后续使用
route10RibbonRoutingFilterserviceId请求转发
route100SimpleHostRoutingFilterurl请求转发
route500SendForwardFilterforward请求转发
post0SendErrorFilter处理有错误的请求响应
post1000SendResponseFilter处理正常的请求响应
禁用指定的Filter
zuul:
  FormBodyWrapperFilter:
    pre:
	  disable: true

自定义Filter示例

我们假设有这样一个场景,因为服务网关应对的是外部的所有请求,为了避免产生安全隐患,我们需要对请求做一定的限制,比如请求中含有Token便让请求继续往下走,如果请求不带Token就直接返回并给出提示。

  1. 首先自定义一个Filter,在run()方法中验证参数是否含有Token。

    /**
     * 自定义网关过滤器
     */
    @Component
    public class TokenFilter extends ZuulFilter {
    
        /**
         * 过滤器类型
         * @return
         */
        public String filterType() {
            return "pre";
        }
    
        /**
         * 过滤器顺序
         * @return
         */
        public int filterOrder() {
            return 2;
        }
    
        /**
         * 是否开启过滤
         * @return
         */
        public boolean shouldFilter() {
            return true;
        }
    
        /**
         * 过滤器中要执行的具体逻辑
         * @return
         * @throws ZuulException
         */
        public Object run() throws ZuulException {
    
            RequestContext ctx = RequestContext.getCurrentContext();
            HttpServletRequest req = ctx.getRequest();
    
            String token = req.getHeader("token");
            if(token == null) {
                // 不对其进行路由,直接返回错误
                ctx.setSendZuulResponse(false);
                ctx.setResponseStatusCode(403);
                ctx.setResponseBody("forbidden");
                return null;
            }
            // 检查token
            if(token.startsWith("abc")) {
                ctx.setSendZuulResponse(true);
                ctx.setResponseStatusCode(200);
                return null;
            }
            // 不对其进行路由,直接返回错误
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(403);
            ctx.setResponseBody("invalid token");
            return null;
        }
    }
    
    
    
    1. 将TokenFilter加入到请求拦截队列,在启动类中添加以下代码
    @Bean
    public TokenFilter tokenFilter() {
    	return new TokenFilter();
    }
    
    

    通过上面这例子我们可以看出,我们可以使用“PRE”类型的Filter做很多的验证工作,在实际使用中我们可以结合shiro、oauth2.0等技术去做鉴权、验证。

配置中心(基于git仓库)

1. 解决重复配置

2. 基于web的加密解密

3.热更新配置(动态)


单台服务端的更新方式。

基于Springcloud bus (rabbitmq。。。或 kafka方式的更新配置

解决重复配置

需要依赖:

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

        <!-- 添加SpringCloud Bus amqp依赖,用于bus通知各个微服务刷新配置 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
    </dependencies>

配置文件:

#这个文件不是必要的使用bootstrap.yml

server:
  port: 7000
spring:
  application:
    name: config-server
    #主要有关配置。
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/checkChen/Springcloud-config-server.git
          search-paths: test_repo  #精确到文件夹
          #也可以是本地地址
          #uri: file://${user.home}/work/test_repo
  #          username: xxx
  #          password: xxx
  #基于客户端配置消息中间件
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest

encrypt:
  key: lanou3g  # 配置一个自己的秘钥,用于对称加密算法加密


management:
  endpoints:
    web:
      exposure:
        include: bus-refresh


启动类:

@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class,args);
    }
}

模拟查看匹配到的配置文件(后面地址是模糊查询也可以很具体。)

http://localhost:8888/app/dev

全都不匹配的话有个默认的application.properties/yml

客户端使用springcloud-config:

server配置完成接下来consumer使用:

首先配置文件:

bootstrap.yml是云配置优先级高于application.yml

所需依赖:

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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-thymeleaf</artifactId>
        </dependency>
        <!--基于普通consumer新添加依赖-->
        <!-- 配置中心客户端依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</artifactId>
        </dependency>

        <!-- 为了使用/refresh端点动态刷新配置,需要添加actuator依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
    </dependencies>

配置文件

application.yml:

spring:
  application:
    name: service-config-consumer

    
#git上已经配置
#eureka:
#  client:
#    service-url:
#      defaultZone: http://${eureka.instance.hostname}:${eureka.client.eureka-server-port}/eureka/
#    eureka-server-port: 8765
#  instance:
#    prefer-ip-address: true #在某些情况下,Eureka优先使用IP地址而不是主机名。设置为true,当应用程序向eureka注册时,它将使用其IP地址而不是其主机名
#    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
#    hostname: cloud.study.com

server:
  port: 8082
  
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh  #或者"*"

bootstrap.yml:

spring:
  cloud:
    config:
      uri: http://localhost:7000   #config-server文件地址
      name: config-calc-consumer
#      profile: dev
#  拉取的二级路径profile

配置映射参数

在SpringCloudConfig中,

  • {application}对应客户端配置的“spring.application.name”参数(如果指定了spring.cloud.config.name则以其为准。);

  • {profile} 对应客户端配置的“spring.profiles.active”参数(如果指定了spring.cloud.config.profile则以其为准。);

  • {label}对应版本库中的branch(或tag)名称,取决于客户端的“spring.cloud.config.label”参数决定。

    如果分支名称中包含“/”,label配置中应该使用“(_)”替换,如foot/dev配置为foot(_)dev。

git仓库加密解密

命令:id_rsa.pub公钥、id_rsa秘钥(公钥的钥匙)

$ cd ~/.ssh/

$ ls
id_rsa  id_rsa.pub  known_hosts

$ cat id_rsa

配置加密解密

(数据库如:用户名密码)

方法:

使用命令行(参考SpringCloud笔记之微服务配置中心Config.pdf)

使用postman:http://localhost:7000/encrypt

对称加密

配置文件config-server加密、在客户端接收的发送回来的信息是解密后的。

encrypt:
  key: lanou3g  # 配置一个自己的秘钥,用于对称加密算法加密

#加密后的串提交git仓库。(.yml文件必须加引号、.properties文件必须不加引号。)
password:
'{cipher}fda4hu54sd7a7df78sadf9aga7d6g'

遇到的问题:非法的key需要jce

在SpringCloud中实现RSA对称加密需要一些前提条件,首先要给jdk/jre配置JCE安装JCE加密可扩展。替换两个文件

非对称加密

参见官网或笔记

动态更新配置:

单台客户端动态更新

由于SpringCloud Config-Server端在每次客户端拉取配置时都会从远程仓库拉取最新的配置,所以Config- Server端的配置其实已经更新了, 我们要做的是让客户端应用更新配置,如果是单台客户端的话,我们直接通过SpringBoot提供的小下文断电中的:”/refresh“ 断电就可以了。具体步骤如下:

  1. 加入SpringBoot actuator依赖
  2. 在需要支持动态刷新配置的类中添加@RefreshScope注解
  3. 访问http://localhost:port/refresh,即可刷新配置。(不支持get请求、可以使用postman)

但是工作量很大、容易遗漏、要做到同时让所有客户端都刷新配置很麻烦。基于此SpringCould Config Server给我们提供了一种更便利的方式、基于Spring Cloud Bus的方式充当中间人通知所有客户端(配置变更相关的客户端)更新配置。

多台客户端动态更新

使用工具,环境搭建:

erlang_otp_win64_21.3.exe

rabbitmq-server-3.7.22.exe

安装之后修改rabbitmq_server-3.7.22\etc下的rabbitmq.config.example文件。

在这里插入图片描述

登录密码

在这里插入图片描述

启动和访问地址

http://localhost:15672

在这里插入图片描述

RabbitMQ 端口

- 4369 (epmd), 25672 (Erlang distribution)

- 5672, 5671 (AMQP 0-9-1 without and with TLS)

- 15672 (if management plugin is enabled)

- 61613, 61614 (if STOMP is enabled)

- 1883, 8883 (if MQTT is enabled)

在这里插入图片描述

安装步骤:

Windows安装ribbitmq步骤:
https://blog.csdn.net/qq_38931949/article/details/95513014
https://www.rabbitmq.com/install-windows.html(官方说明)


配置中心加密错误: https://bbs.csdn.net/topics/392514733
解决办法: https://blog.csdn.net/qq_36827957/article/details/81777333
SpringCloud Config Server端配置
  1. 添加bus依赖

    <!-- 添加SpringCloud Bus amqp依赖,用于bus通知各个微服务刷新配置 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-bus-amqp</artifactId>
            </dependency>
    

这里我们用的是rabbitmq,所以添加的是amqp依赖、如果消息中间件用的是kafka的话就换成bus-kafka依赖。

  1. 配置消息中间件

    #基于客户端配置消息中间件
      rabbitmq:
        host: 127.0.0.1
        port: 5672
        username: guest
        password: guest
    
  2. 当配置修改完成,并且push到远程仓库之后,执行下面的请求。

    新版地址不同有变化。

    旧版本:http://localhost:7000/bus/refresh

    新版本:http://localhost:7000/actuator/bus-refresh

    必须要配置如下server - config端

    management:
    endpoints:
     web:
       exposure:
         include: bus-refresh  #或者"*"
    

    访问Config Server 的actuator/bus-refresh端点,触发Config 的检查更新。(必须post请求)

SpringCloud -client端

重复 1.添加bus依赖 2. 配置消息中间件

课堂知识:

查看可调用的服务(可以配个虚假的就是不和服务名保持一致(提高安全性)):http://localhost:9100/actuator/routes (方式如下)

理解如下:

此地址用来查看使用zuul代理服务(如:taotao-rest(只是服务的名字))的访问路径地址 配合(属性strip-prefix: true # 是否在网关层面消耗掉全局前缀即path:/api——最简化通过zuul的访问地址)

# 这种方式配置路由规则:前面的key是微服务名称,后面是匹配路径(更安全)
    service-provider: /calcApi/**
    
    # 这种方式配置路由规则:第一级的key可以随便取(路由名称),下面可以配置更多key、value(相比上面一种配置更强大)
    calc-proxy:
      serviceId: service-provider # 有效的微服务名称
      path: /calc/**  # 访问路径
      strip-prefix: false # 是否在网关层面消耗掉指定服务的路由规则前缀
    
    
    
  ignored-services: "*" # 忽略所有未显示配置路由规则的微服务

遇到的问题

  1. 所需工具:

在这里插入图片描述

  1. 安装步骤:
Windows安装步骤:
https://blog.csdn.net/qq_38931949/article/details/95513014
https://www.rabbitmq.com/install-windows.html(官方说明)


配置中心加密错误: https://bbs.csdn.net/topics/392514733
解决办法: https://blog.csdn.net/qq_36827957/article/details/81777333
  1. 小知识

    iml是 intellij idea的工程配置文件,里面是当前 project 的一些配置信息。.Idea 存放项目的配置信息,包括历史记录,版本控制信息等。

  2. 通过配置代理服务

    # 使用Zuul代理未接入Eureka的传统服务
    taotao-rest:
      ribbon:
        NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList #如果不配置ServerList类型为ConfigurationBasedServerList的话就需要禁用ribbon的eureka支持
        ConnectTimeout: 500
        ReadTimeout: 2000
        listOfServers: http://localhost:8081
    
  3. 属性:(通过)

    zuul:
      routes:
        microserver-calc: /calcs/**  #指定的服务下
    
      prefix: /api
      strip-prefix: true  # 是否在网关层面消耗掉全局前缀即/api
    
  4. 测试forward的路径

    @RestController
    //@RequestMapping("/rest")
    public class TestController {
    
        //@RequestMapping("/content/getall/{id}")
      @RequestMapping("/**")
     public void handlerRequest(HttpServletRequest req) {
            StringBuffer requestURL = req.getRequestURL();
          //得到完整路径forward后的地址。
            System.out.println(requestURL.toString());
        }
    
    }
    
    
  5. 本地转发(forward);地址栏没变forward只是把结果带到页面:在地址栏拼路径

    zuul:
      routes:
        route-name:
          path: /path-a/**
          url: forward:/path-b
          
          
          
          
    taotao-rest-proxy-forward: # 使用forward本地转发(就是将匹配到路由规则的请求,转发到网关本地应用中去处理)
          path: /rest-f/**
          url: forward:/rest
        # 比如浏览器访问:http://localhost:9100/api/rest-f/content/getall/89
        # 会被转发到:http://localhost:9100/rest/content/getall/89
    
    
  6. nginx代理很重要!(实现集群)


Author:CheckChen

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值