spring Cloud

spring Cloud

一、服务注册–Eureka

1、父子工程

父工程构建与一般spring boot项目构建工程无任何区别,不同的是构建完成后对pom.xml的修改

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    //总的项目依赖,子工程将不再引入,而是用父工程替代
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    //父工程的相依信息
    <groupId>com.springcloud</groupId>
    <artifactId>cloud-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloud-parent</name>
    <description>Demo project for Spring Boot</description>
    //声明改该项目是父工程
    <packaging>pom</packaging>
    //子工程
    <modules>
        <module>eureka-server-7001</module>
        <module>comment-api</module>
        <module>order-server-8001</module>
        <module>order-server-8002</module>
        <module>order-client</module>
    </modules>
    //版本声明
    <properties>
        <java.version>1.8</java.version>
        <spring.cloud-version>Hoxton.SR8</spring.cloud-version>
        <druid.version>1.2.3</druid.version>
        <mybatis-plus.version>3.4.1</mybatis-plus.version>
        <mysql.version>8.0.22</mysql.version>
    </properties>
    //版本控制,此时不会真正引入,只是版本管理,子工程将从这里引入需要的依赖版本
    <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>
            <!--druid-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!--mybatis-plus-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    	//父工程引入子工程都需要的依赖,子工程将不再重复引入
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
                <version>2.3.6.RELEASE</version>
            </dependency>
            <!--spring -cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

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

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

子工程

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    //声明父工程
    <parent>
        <artifactId>cloud-parent</artifactId>
        <groupId>com.springcloud</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>order-client</artifactId>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.springcloud</groupId>
            <artifactId>comment-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <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-client</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2、Eureka(停更维护)

spring 官方提供的注册中心,用于服务注册,spring cloud是基于spring boot的微服务一站式解决方案

与spring boot的版本兼容:

spring cloudspring boot
Hoxton2.2.x, 2.3.x (Starting with SR5)
Greenwich2.1.x
Finchley2.0.x
Edgware1.5.x
Dalston1.5.x

在使用中常使用spring boot父子工程来构建微服务项目,便于版本的统一管理

2.1、eureka注册中心(服务端)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

在新建的子项目中引入该依赖

在主类上开启注册服务

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

配置文件

server:
  port: 7001

eureka:
  instance:
    #实例名称
    hostname: eureka7001.com
  client:
  	#不将自己注册进自己的注册中心
    register-with-eureka: false
    fetch-registry: false
    service-url:
      #其他注册中心(集群环境)
      defaultZone: http://eureka7002.com:7002/eureka/
      #单机环境
      defaultZone: http://eureka7001.com:7001/eureka/
  server:
    #关闭自我保护
    enable-self-preservation: false

服务端的控制器

@RestController
@PropertySource("classpath:application.yml")
public class OrderController {
    @Autowired
    OrdersService ordersService;
    @Value("${server.port}")
    private String port;
    @GetMapping("/producer/getAllOrders")
    public Map<String,Object> getAllOrders() {
        Map<String,Object> map = new HashMap<>();
        map.put("port",port);
        map.put("res",ordersService.getAllOrders());
        return map;
    }
}

启动该子项目,访问http://eureka7001.com:7001

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q9QHZFat-1615558639620)(https://i.loli.net/2020/12/07/Lkyl7sUtXAKOirT.png)]

说明配置成功

2.2、eureka(客户端)

引入客户端依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

主类开启服务

@SpringBootApplication
@EnableEurekaClient
@MapperScan("com.springcloud.Mapper")
public class OrderServer8001Application {
    public static void main(String[] args) {
        SpringApplication.run(OrderServer8001Application.class, args);
    }
}

配置文件

server:
  port: 8001

spring:
  application:
    name: OrderServer

#eureka配置
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

一般服务端都是具体的微服务提供者,除了上述的配置,还有其他具体的业务类

访问http://eureka7001.com:7001

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xsn2KoZU-1615558639622)(https://i.loli.net/2020/12/07/qFXzl7jELVf9HSW.png)]

服务注册成功

2.3、eureka(服务的访问客户端)

服务的访问客户端也是微服务,要注册进注册中心,与以上配置相同

客户端访问服务时采用的是远程调用,最原始的方法使用RestTemplate

import org.springframework.cloud.client.loadbalancer.LoadBalanced;

@Configuration
public class RestTemplateConfig {
    @Bean
    @LoadBalanced  #开启负载均衡,默认是轮询
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

向容器注入RestTemplate对象

@RestController
public class OrderController {
    @Autowired
    RestTemplate restTemplate;
    #服务地址
    private static final String URL = "http://ORDERSERVER";
    @GetMapping("/consumer/getAllOrders")
    public Map<String,Object> getAllOrders(){
        Map<String,Object> map = new HashMap<>();
        map.put("flag","consumer");
        #get请求路径为服务的controller请求
        map.put("res",restTemplate.getForObject(URL+"/producer/getAllOrders",Map.class));
        return  map;
    }
}

在浏览器中访问客户端,客户端会去访问具体的服务(注意端口的变化)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5lFWUKLN-1615558639625)(https://i.loli.net/2020/12/07/XUd6ir3mONwtG7g.png)]

2.4、自我保护

与zookeeper不同的是有服务下线、或暂时与注册中心断绝通信时eureka不会将服务删

注册中心还有zookeeperconsulalibaba Nacos

3、zookeeper使用:

3.1、导入依赖

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-zookeeper-discovery -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <version>2.2.4.RELEASE</version>
</dependency>

3.2、yml

spring: 
	application:
		name: sever-name
	cloud: 
		zookeeper: 
			connect-string: zookeeper地址

3.3、主启动类

@SpringBootApplication
@EnableDiscoveryClient

4、consul使用:

4.1、导入依赖

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-consul-discovery -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

4.2、yml

spring: 
	cloud: 
		consul: 
			host: localhost
			port: 8500
			discovery: 
				service-name: ${spring.application.name}

4.3、主启动类:

@SpringBootApplication
@EnableDiscoveryClient

5、三个注册中心异同点:

组件名语言CAP
EurekajavaAP
consulgoCP
zookeeperjavaCP

6、服务发现DiscoveryClient

@Autowired
private DiscoveryClient discoveryClient;

@GetMapping("/getServer")
public Map<String,Object>  discovery(){
    List<ServiceInstance> orderserver = discoveryClient.getInstances("ORDERSERVER");
    Map<String,Object> map = new HashMap<>();
    for (ServiceInstance serviceInstance : orderserver) {
        map.put(serviceInstance.getServiceId()+serviceInstance.getPort(),serviceInstance.getUri());
    }
    return map;
}

主类上配置

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@MapperScan("com.springcloud.Mapper")
public class OrderServer8001Application {
    public static void main(String[] args) {
        SpringApplication.run(OrderServer8001Application.class, args);
    }
}

访问服务发现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EVhYHwaV-1615558639628)(https://i.loli.net/2020/12/07/io4kwtvzM7lxsau.png)]

二、服务调用–openfeign

1、Ribbon(停更维护)

替换方案:spring cloud loadbalance

一个客户端负载均衡的工具(进程内的本地负载均衡)

主要功能:提供客户端的软件负载均衡算法与服务调用(负载均衡+RestTemplate)

原理:

  • ribbon会首先访问注册中心获取服务列表

  • 根据访问规则即负载均衡算法,访问服务

  • 负载均衡有自带的,也可有自己实现的

    ribbon在最新的spring-cloud-eureka中做了整合

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Upyg3BRa-1615558639630)(https://i.loli.net/2020/12/07/f3gAvmxlybzBDkG.png)]

还整合了spring cloud loadbalance

2、自带负载均衡算法

ribbon自带了7中负载均衡算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcc9nv6Q-1615558639632)(https://i.loli.net/2020/12/07/W8MuDGrflCowj2Z.png)]

有轮询、随机等

负载均衡方法替换

编写配置类(不能在主类所在包及子包中)

@Configuration
public class RibbonLB {
    @Bean
    public IRule MyRule(){
        return  new RandomRule();
    }
}

主类

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="ORDERSERVER",configuration = RibbonLB.class)
public class OrderClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderClientApplication.class, args);
    }
}

负载均衡原理:

  • 获取服务地址列表

  • 当前访问次数与服务总数取余,作为服务地址的下标

2、RestTemplate深入

RestTemplate常用有两请求方式即post、get

方法返回类型
getForObjectjson
postForObjectjson
getForEntityresponse对象
postForEntityresponse对象

3、Openfeign

一个声明式的web服务客户端(主要服务调用),整合Eureka、Ribbon支持负载均衡

(实际是对ribbon和RestTemplate的封装)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MpiWHd6l-1615558639633)(https://i.loli.net/2020/12/07/XtAk2UqwPJSMIdh.png)]

3.1、引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

3.2、主类

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

3.4、接口

@Component
@FeignClient(value = "ORDERSERVER")
public interface OrderFeignService {
    @GetMapping("/producer/getAllOrders")
    public Map<String,Object> getAllOrders();
}

OpenFeign使用与dobbu类似(面向接口),封装了RestTemplate和Ribbn

3.5、超时控制

openfeign默认等待1秒,超时则报错

若服务超时超过1秒,可进行超时延长

ribbon: 
	#读取时间
	ReadTimeout: 5000
	#建立连接时间
	ConnectTimeout: 5000

3.6、日志增强

级别:

NONE: 默认
BASIC: 仅记录请求方法
HEABERS: 记录请求方法,包括请求、响应头消息
FULL: 记录请求方法,包括请求、响应头消息+正文响应体元数据

配置类

@Configuration
public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}

配置文件:

server:
  port: 8081
logging:
  level:
    com.springcloud.Service.OrderFeignService: debug

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WNLRcPi4-1615558639635)(https://i.loli.net/2020/12/07/A6oXvBaynzxTkPm.png)]

三、服务降级–hystrix

3.1、断路器–hystrix(停更进维)

处理延迟、容错的开源库框架,长链路调用避免级联故障,保证在一个依赖出问题的情况下,不会导致整体服务失败,提高分布式系统的弹性

功能:

  • 服务降级

    在服务器忙等情况下,资源紧张,不上客户端等待立刻返回一个友好提示,fallback函数

    触发:

    • 程序运行异常
    • 超时
    • 服务熔断触发服务降级
    • 线程池\信号量打满也会导致服务降级(没有空闲线程资源)

    降级的目的是为了解决整体项目的压力,而牺牲掉某一服务模块而采取的措施。

  • 服务熔断

    ​ 服务熔断是为了当服务中某段代码出现错误时,为了不影响其他客户端的请求而采取的措施

    ​ 一般是出现错误,引起服务降级,进而服务熔断、最后链路恢复

    ​ 根据错误率判断

  • 限流

    在高并发场景下,为了方式大流量导致系统资源耗尽,进而发生系统奔溃、缓慢等对请求进行限制

3.2、hystrix在微服务中解决的问题

3.2.1、微服务中存在的问题

微服务有少则几种,多则几十、成百上千,在服务相互调用过程中,会产生多种问题来影响整体系统的运行性能等:

  • 网络超时
    • 网络原因导致服务调用超时(openfeign调用默认时间是2秒,超过则返回错误页面),则返回错误界面,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8qYta4aM-1615558639637)(https://i.loli.net/2020/12/09/xh78erGM91s2oNL.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQ77ui3G-1615558639638)(https://i.loli.net/2020/12/09/opkRyA5QTs7FHEq.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rbUxr0vi-1615558639639)(https://i.loli.net/2020/12/09/XrhvF1xHSBcjpJz.png)]

  • 流量过大,导致系统资源耗尽,等待超时发生以上错误

  • 代码运行异常报错,导致系统异常

    以上情况有多种方案:

    • 使用openfeign实现超时控制,延长超时时间(延长时间难以确定)

    • 使用hystrix处理:

      • 服务降级
      • 服务熔断
      • 限流

      为相应的方法提供托底方案(fallback)

服务端降级保护
1、引入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>
2、主类配置
@SpringBootApplication
@EnableEurekaClient
@MapperScan("com.springcloud.Mapper")
@EnableCircuitBreaker
3、拖底函数
    @GetMapping("/producer/timeOut/{id}")
    //声明降级规则
	@HystrixCommand(fallbackMethod = "timeOut2",commandProperties = {
    //超时时间设置,表示该函数执行超出3秒\报错等,执行托底函数timeOut2
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",
                     value ="3000")
    })
    public Map<String,Object> timeOut(@PathVariable("id") Integer id) {
        try {
            Thread.sleep(id*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Map<String,Object> map = new HashMap<>();
        map.put("port",port);
        map.put("id",id);
        map.put("res",ordersService.getAllOrders());
        return map;
    }
    public Map<String,Object> timeOut2(@PathVariable("id") Integer id) {
        Map<String,Object> map = new HashMap<>();
        map.put("msg","超时请稍后访问!!!");
        map.put("id",id);
        return map;
    }

测试[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oWxnfp7F-1615558639641)(https://i.loli.net/2020/12/10/PtoKGXSmQqF6ph5.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HZZPS76F-1615558639643)(https://i.loli.net/2020/12/10/3msyxS5FZUfMBJi.png)]

客户端访问时需要参考客户端feign远程访问的超时设置,feign的默认超时时间是2秒

超时问题中主要有几个参数

  • openfeign集成了ribbon所以有一个默认的连接时间

  • 客户端开启feign.hystrix.ebable=true时,feignclient下所有的方法都会被Hystrix包裹,openfeign默认的连接时间是1秒

    所以只要超过以上一个超时时间就会报超时异常

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c8LP4c5M-1615558639644)(https://i.loli.net/2020/12/10/B5LPKmXDWzoAeyw.png)]

所以在客户端时间超过设定的访问控制时间,也可进行客户端的服务降级,为客户端服务设置fallback托底函数

客户端降级保护
1、如上引入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

客户端使用openfeign来进行服务的调用,其中继承了Hystrix的一些服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-37KowG3P-1615558639646)(https://i.loli.net/2020/12/10/GX6Iq7DY1yPoki4.png)]

2、主类配置
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
@EnableHystrix
public class OrderClientHystrix8082Application {
    public static void main(String[] args) {
        SpringApplication.run(OrderClientHystrix8082Application.class, args);
    }
}
3、接口编写
@GetMapping("/comsumer/timeOut/{id}")
@HystrixCommand(fallbackMethod = "timeOut2",commandProperties = {
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",
                     value = "3000")  //3秒钟以内就是正常的业务逻辑
})
public Map<String,Object> timeOut(@PathVariable("id") String id){
    Map<String,Object> map = new HashMap<>();
    map.put("port",port);
    map.put("res",orderFeignService.timeOut(id));
    return map;
}
public  Map<String,Object> timeOut2(@PathVariable("id") String id){
    Map<String,Object> map = new HashMap<>();
    map.put("meg","我是消费者8082,对付支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,(┬_┬)");
    return map;
}

4、yml配置

ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000
  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000
feign:
  hystrix:
    enabled: true


测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G3TiIrmB-1615558639647)(C:\Users\wjh\AppData\Roaming\Typora\typora-user-images\image-20201210145016920.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b0c4Hqyt-1615558639648)(C:\Users\wjh\AppData\Roaming\Typora\typora-user-images\image-20201210145043056.png)]

小结:

客户端设定的超时时间是6秒,hystrix的测试时间是4秒,ribbon超过5秒,执行客户端的兜底函数

问题:

  1. 代码膨胀:

    为每个方法提供一个兜底函数,会出现代码臃肿的情况

    解决:

    1> 创建默认统一的兜底函数

    2> 为特殊的处理创建自定义的兜底函数

方式一:

1、在controller中编写全局统一的兜底函数

在controller类上添加注解

//payment_Global_FallbackMethod为兜底函数名(全局的兜底函数)
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")

在controller中添加兜底方法

public String payment_Global_FallbackMethod(){
    return "Global异常处理信息,请稍后再试,(┬_┬)";
}

在需要兜底的方法上添加注解

 @HystrixCommand

2、自定义的兜底函数与之前相同

方式二 编写降级服务类提供降级的兜底函数,将业务函数与兜底函数分离

1> 实现接口该服务的接口

@Component
public class HystrixFallBackService implements OrderFeignService {
    @Override
    public Map<String, Object> getAllOrders() {
        return null;
    }
    @Override
    public Map<String, Object> timeOut(Integer id) {
        Map<String,Object> map = new HashMap<>();
        map.put("meg","我是消费者8082,对付支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,(┬_┬)");
        return map;
    }
}

2> yml配置

feign:
  hystrix:
    enabled: true #开启降级服务
ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000
  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000

3> 修改服务接口

@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)

4> 业务类

@RestController
@PropertySource("classpath:application.yml")
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderController {
    @Autowired
    OrderFeignService orderFeignService;
    @Value("${server.port}")
    private String port;
    @GetMapping("/comsumer/getAllOrders")
    @HystrixCommand
    public Map<String,Object> getAllOrders() {
        int s = 10/0;
        Map<String,Object> map = new HashMap<>();
        map.put("port",port);
        map.put("res",orderFeignService.getAllOrders());
        return map;
    }
    @GetMapping("/comsumer/timeOut/{id}")
    @HystrixCommand(fallbackMethod = "timeOut",commandProperties ={
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value ="6000")
    })
    public Map<String,Object> timeOut(@PathVariable("id") Integer id){
    Map<String,Object> map = new HashMap<>();
        map.put("port",port);
        map.put("res",orderFeignService.timeOut(id));
        return map;
    }
    public  Map<String,Object> payment_Global_FallbackMethod(){
        Map<String,Object> map = new HashMap<>();
        map.put("meg","全局兜底");
        return map;
    }
}

测试:

(只注解了HystirxCommend)的方法执行兜底函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SoLznCM4-1615558639650)(https://i.loli.net/2020/12/10/iQL9Ax1VeXDHhvm.png)]

指明了兜底函数则执行指定的兜底函数

熔断保护
1、什么是熔断
2、熔断配置
//服务熔断
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),  //是否开启断路器
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),   //请求次数
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),  //时间范围
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    if (id < 0){
        throw new RuntimeException("*****id 不能负数");
    }
    String serialNumber = IdUtil.simpleUUID();

    return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
    return "id 不能负数,请稍候再试,(┬_┬)/~~     id: " +id;
}

使用HystrixCommand来进行服务熔断,在设定的时间窗口,调用发生异常即服务调用的次数/设定的总调用的次数=失败率达到某一阈值,将发生服务的熔断

当成功率上升、失败率下降到阈值时服务恢复

多次错误,然后慢慢正确,发现刚开始不满足条件,就算是正确的访问地址也不能进行访问,需要慢慢的恢复链路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1o9GdRcv-1615558639652)(https://i.loli.net/2020/12/10/RWlETzi1C74AFex.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eNMVGRC4-1615558639653)(https://i.loli.net/2020/12/10/t3d8AwGXZDu9LEl.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E8Nylcez-1615558639655)(https://i.loli.net/2020/12/10/aTUkQ3uOime6PMZ.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kKZi8SST-1615558639656)(https://i.loli.net/2020/12/10/m9su2ArKelcMPEO.png)]

四、服务网关–gateway

1、简介

gateway是spring cloud提供的为了简单有效的统一的管理路由的组件,可提供以下服务:

  • 反向代理
  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控

2、gateway三大组件

  • 路由Router

    路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由

  • 断言Predicate

    开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

  • 过滤器Filter

    使用过滤器,可以在请求被路由前或者之后对请求进行修改。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-scCbeTOo-1615558639658)(https://i.loli.net/2020/12/10/LUxGVMqfSskIXmu.png)]

3、工作原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Pvt4SZC-1615558639660)(https://i.loli.net/2020/12/11/elOd58N3iRmUYDT.png)]

​ 客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。该处理程序通过特定于请求的过滤器链运行请求。筛选器由虚线分隔的原因是,筛选器可以在发送代理请求之前和之后运行逻辑。所有“前置”过滤器逻辑均被执行。然后发出代理请求。发出代理请求后,将运行“后”过滤器逻辑。

4、使用方式一(yml配置)

server:
  port: 9001
spring:
  application:
    name: cloud-gateway-9001
  cloud:
    gateway:
      routes:
        - id: order-server_routh1      #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001   #匹配后提供服务的路由地址
          predicates:
            - Path=/producer/getAllOrders   #断言,路径相匹配的进行路由

        - id: order-server_routh2
          uri: http://localhost:8001
          predicates:
            - Path=/getServer   #断言,路径相匹配的进行路由

#注册中心配置
eureka:
  instance:
    hostname: cloud-gateway-9001
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

5、使用方式二(编码类配置)

@Configuration
public class GateWayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("path_rote_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
}

6、动态路由

原理:

以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

spring:
  application:
    name: cloud-gateway-9001
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #
      routes:
        - id: order-server_routh1            #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://OrderServer   #匹配后提供服务的路由地址
          predicates:
            - Path=/producer/getAllOrders   #断言,路径相匹配的进行路由
        - id: order-server_routh2
          uri: lb://OrderServer
          predicates:
            - Path=/getServer   #断言,路径相匹配的进行路由

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s1HmqM88-1615558639662)(https://i.loli.net/2020/12/11/tqKNCs6IxfB4keA.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dHMmwA0b-1615558639663)(https://i.loli.net/2020/12/11/wU7RuLkgSt9fcnr.png)]

需要注意的是uri的协议为lb,表示启用Gateway的负载均衡功能

7、Predicate断言

作用:

​ 如果请求与断言相匹配则进行路由(所有的谓词都会匹配Http请求的不同属性)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ARZJPOed-1615558639666)(https://i.loli.net/2020/12/11/NTmYgGMPh1UERWs.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-goed6nFP-1615558639667)(https://i.loli.net/2020/12/11/xPzwgEb3p7MyrsN.png)]

官网实例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w45J5Yyq-1615558639669)(https://i.loli.net/2020/12/11/rBMF6coivhmkXVR.png)]

说明:在如图在谓词After之后的时间点,该路由才可以匹配成功

Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理

8、路由过滤器Filter

修改HTTP请求和返回的HTTP响应,只能通过指定路由进行使用

内置了多种路由过滤器

return routes.build();
}
}


## 6、动态路由

原理:

以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

```yaml
spring:
  application:
    name: cloud-gateway-9001
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #
      routes:
        - id: order-server_routh1            #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://OrderServer   #匹配后提供服务的路由地址
          predicates:
            - Path=/producer/getAllOrders   #断言,路径相匹配的进行路由
        - id: order-server_routh2
          uri: lb://OrderServer
          predicates:
            - Path=/getServer   #断言,路径相匹配的进行路由

测试:

[外链图片转存中…(img-s1HmqM88-1615558639662)]

[外链图片转存中…(img-dHMmwA0b-1615558639663)]

需要注意的是uri的协议为lb,表示启用Gateway的负载均衡功能

7、Predicate断言

作用:

​ 如果请求与断言相匹配则进行路由(所有的谓词都会匹配Http请求的不同属性)

[外链图片转存中…(img-ARZJPOed-1615558639666)]

[外链图片转存中…(img-goed6nFP-1615558639667)]

官网实例:

[外链图片转存中…(img-w45J5Yyq-1615558639669)]

说明:在如图在谓词After之后的时间点,该路由才可以匹配成功

Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理

8、路由过滤器Filter

修改HTTP请求和返回的HTTP响应,只能通过指定路由进行使用

内置了多种路由过滤器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
Spring Cloud是一个用于构建分布式系统的开发工具集合。它提供了一些常用的组件和框架,包括服务注册和发现、负载均衡、断路器、分布式配置等等。在使用Spring Cloud时,有一些常见的错误和注意事项需要注意。 首先,关于Spring Boot和Spring Cloud版本对应错误。在使用Spring Cloud时,需要确保Spring Boot和Spring Cloud的版本兼容。不同版本之间可能存在依赖冲突或不兼容的情况,因此需要根据官方文档或者相关文档来选择合适的版本。 另外,Spring Cloud Config是一个用于集中管理和动态获取配置的工具。它支持从Git、SVN或本地文件系统中获取配置文件,并提供了服务器和客户端支持。你可以通过官方使用说明文档了解更多关于Spring Cloud Config的详细信息。 此外,关于选择使用Nacos还是Eureka作为服务注册和发现组件的问题。Nacos是一个功能更强大的服务注册和发现组件,它整合了Spring Cloud Eureka、Spring Cloud Config和Spring Cloud Bus的功能。使用Nacos可以实现配置的中心动态刷新,而不需要为配置中心新增集群或使用消息队列。另一方面,Eureka是Spring Cloud原生全家桶的一部分,相对来说更加稳定一些。选择使用哪个组件需要根据具体的需求和项目特点来决定。 综上所述,Spring Cloud是一个用于构建分布式系统的开发工具集合,它提供了一些常用的组件和框架。在使用Spring Cloud时,需要注意Spring Boot和Spring Cloud版本的兼容性,并可以使用Spring Cloud Config来动态获取配置。同时,可以选择使用Nacos或Eureka作为服务注册和发现组件,具体选择需要根据项目需求来决定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值