Introduction SpringCloud assembly and method of use

First, load balancing Robbin

Here Insert Picture Description

1.1 launch multiple service providers

The original copy of the service and start.
Here Insert Picture Description

1.2 In the service consumer configured load balancing algorithm

01. Add load balancing algorithm comment on the bootstrap class:
Here Insert Picture Description02. Use the service provider name directly in the Controller
Here Insert Picture Description03. modify load balancing strategy in the configuration file
Here Insert Picture Description

Second, the fuse Hystrix

作用:用于隔离访问远程服务、第三方库,防止出现级联失败。

2.1 avalanche problem

Hystix means to solve the problem of avalanche there are two:

  • Thread isolation
  • Service fuse

Thread isolation

== Hystrix depend on each service call is assigned a thread pool is small, if the thread pool is full call will be rejected immediately, do not use the default queue. Accelerated failure determination time.

Service degradation: priority to ensuring core service, rather than a core service is not available or weak are available.

== When a user requests a failure, it will not be blocked, but not endless wait or see the system collapse, at least you can see the results (such as returning friendly message).
== although it will lead to service degradation request fail, but will not cause obstruction, but most will affect the thread pool resources of the corresponding dependent services, other service is not responding.

2.2 Hystrix service degradation

2.2.1. Configuring Hystrix service consumers

  1. Add rely fuse in the configuration file in pom.xml
        <!-- 添加熔断器依赖 Hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
  1. Adding a dependency class guide
@SpringBootApplication
@EnableDiscoveryClient  //开启服务注册中心 Eureka
@EnableCircuitBreaker   //开启熔断器服务 Hystrix
public class ConsumerApplication {
    /* 使用RestTemplate做远程调用方法 */
    @Bean
    @LoadBalanced  //开启负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
        System.out.println("调用方启动成功!!");
    }
}
  1. Adding the corresponding control method, and fusing the binding layer
    Here Insert Picture Description4. Test
    first service provider and service consumers to stop;
    then restart the service consumer.
    Here Insert Picture Description

2.2.2 If the methods are not a lot of trouble to write a fuse, how to write global blown?

在类上添加注解@DefaultProperties指定一个全局的熔断方法
Here Insert Picture Description
Here Insert Picture Description

Hystric服务降级小结:

  1. 引入Hystrix依赖
  2. 修改配置文件(这里没做修改)
  3. 在引导类上添加注解@EnableCircuitBreaker
  4. 定义熔断方法
    4.1 局部熔断方法:要和被熔断的方法返回值列表一致
    4.2 全局熔断方法:返回值类型要和被熔断的方法一致
  5. 声明被熔断的方法@HystrixCommand(fallbackMethod="局部熔断方法名")
  6. 在类上添加注解@DefaultProperties(defaultFallback = "全局熔断方法名")

2.2.3 设置熔断超时

在之前的案例中,请求在超过1秒后都会返回错误信息,这是因为Hystix的默认超时时长为1,我们可以通过在服务调用方的配置文件中配置修改这个值:

我们可以通过hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds来设置Hystrix超时时间。该配置没有提示。

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000 # 设置hystrix的超时时间为6000ms

2.3 Hystrix 服务熔断

熔断状态机3个状态:

  • Closed:关闭状态,所有请求都正常访问。
  • Open:打开状态,所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
  • Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全关闭断路器,否则继续保持打开,再次进行休眠计时

三、声明式调用 Feign

为什么叫伪装?

Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。

3.1. 改造服务消费者

  1. 添加 Feign 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 在引导类上添加注解
//@SpringBootApplication
//@EnableDiscoveryClient  //开启服务注册中心 Eureka
//@EnableCircuitBreaker   //开启熔断器服务 Hystrix
@SpringCloudApplication   //组合注解,相当于 @SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker
@EnableFeignClients // 开启feign客户端
public class ConsumerApplication {

    /* 使用RestTemplate做远程调用方法 */
/*
    @Bean
    @LoadBalanced  //开启负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
*/
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
        System.out.println("调用方启动成功!!");
    }
}
  1. 新建 Feign 接口
    Feign 接口习惯以 client 结尾,并声明是一个Feign 接口,指定对应的微服务名称。声明被调用的方法(全局路径需要在每个类上添加)。
@FeignClient("service-provider")  //声明这是一个Feign接口,并指明微服务的名称
public interface BookClient {
    @GetMapping("/book/{id}")
    public String queryBookById(@RequestParam("id") int id);
}
  1. 修改 Controller 类
@Controller
@RequestMapping("consumer/book")
//@DefaultProperties(defaultFallback = "hystrixMethod")  //定义全局的熔断方法
public class BookController {    
    @Autowired
    private BookClient bookClient;
    
    public String queryBookById(@RequestParam("id") int id){
        return this.bookClient.queryBookById(id);
    }
}
  1. 访问
    Here Insert Picture Description

3.2 声明式调用如何集成熔断器?

  1. feign 中集成了熔断 Robbin ,但是默认是关闭的,需要自己进行手动开启。
feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能
  1. 需要在 Client 中定义方法,需要熔断哪个方法就实现哪个方法。
@Component
public class BookClientHystrix implements BookClient{
    @Override
    public String queryBookById(int id) {
        return "服务器正忙,请稍后再试!!!";
    }
}
  1. 对 Feign 接口添加熔断类
@FeignClient(value = "service-provider", fallback = BookClientHystrix.class)  //声明这是一个Feign接口,并指明微服务的名称
public interface BookClient {
    @GetMapping("/book/{id}")
    public String queryBookById(@RequestParam("id") int id);
}

四、网关路由 Zuul(Zuul的四种路由)

Zuul为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。

路由:分发给不同的微服务(服务名)
负载均衡:同一个微服务,不同的实体类

4.1 快速入门(通过路径进行访问)

  1. 构建SpringCloud项目
    Here Insert Picture DescriptionHere Insert Picture Description
  2. 修改 zuul 网关的配置文件 application.yml
server:
  port: 10000

spring:
  application:
    name: xxacker-zuul

zuul:
  routes:
    service-provider:   #路由名称,可以随便写,习惯上写服务名
      path: /service-provider/**    #此处为路由到服务的提供方,也可以路由到服务的消费方
      url: http://localhost:8190    #服务提供方的地址
  1. 为引导类添加注解
@SpringBootApplication
@EnableZuulProxy  //启用zuul网关组件
public class XxackerZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(XxackerZuulApplication.class, args);
        System.out.println("Zuul启动成功!!!");
    }
}
  1. 启动zuul网关项目,并进行访问
    Here Insert Picture Description

4.2 面向服务的路由(通过服务Id进行访问)

在原先路由规则中,路由的路径对应的服务地址写死了!如果同一服务有多个实例的话,这样做显然就不合理了。应该根据服务的名称,去Eureka注册中心查找服务对应的所有实例列表,然后进行动态路由
对 xxackerZuul 服务进行优化:

  1. 添加 Eureka 的客户端依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  1. 添加 Eureka配置,修改路由的方式,获取服务信息
zuul:
  routes:
    service-provider:   #路由名称,可以随便写,习惯上写服务名
      path: /service-provider/**    #此处为路由到服务的提供方,也可以路由到服务的消费方
      #url: http://localhost:8190    #服务提供方的地址
      serviceId: service-provider    #服务名
      
eureka:
  client:
    registry-fetch-interval-seconds: 5 # 获取服务列表的周期:5s
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  1. 开启Eureka客户端发现功能
@SpringBootApplication
@EnableZuulProxy  //启用zuul网关组件
@EnableDiscoveryClient  //启用 Eureka 的客户端
public class XxackerZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(XxackerZuulApplication.class, args);
        System.out.println("Zuul启动成功!!!");
    }
}
  1. 访问
    Here Insert Picture Description

4.3 简化路由配置

zuul:
  routes:
    service-provider: /service-provider/**  #路由名称,可以随便写,习惯上写服务名
      #path: /service-provider/**    #此处为路由到服务的提供方,也可以路由到服务的消费方
      #url: http://localhost:8190    #服务提供方的地址
      #serviceId: service-provider    #服务名

4.4 默认的路由规则

在使用Zuul的过程中,上面讲述的规则已经大大的简化了配置项。但是当服务较多时,配置也是比较繁琐的。因此Zuul就指定了默认的路由规则:

  • 默认情况下,一切服务的映射路径就是服务名本身。例如服务名为:service-provider,则默认的映射路径就 是:/service-provider/**

也就是说,刚才的映射规则我们完全不配置也是OK的,不信就试试看。

添加路由前缀:

zuul:
  routes:
    service-provider: /service-provider/**
    service-consumer: /service-consumer/**
  prefix: /api # 添加路由前缀

4.5 Zuul过滤器

Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。

4.5.1 ZuulFilter

ZuulFilter是过滤器的顶级父类。其中定义的4个最重要的方法:

public abstract ZuulFilter implements IZuulFilter{

    abstract public String filterType();

    abstract public int filterOrder();
    
    boolean shouldFilter();// 来自IZuulFilter

    Object run() throws ZuulException;// IZuulFilter
}
  • shouldFilter: Returns a Booleanvalue, it is determined whether the filter needs to be performed. Execution returns true and false is not executed.
  • run: Specific business logic filter.
  • filterType: Returns the string representing the type of filter. It contains the following four:
    • pre: Request execution before being routed
    • route: Call routing request
    • post: Called after route and errror filter
    • error: An error occurred while processing the request to call
  • filterOrder: To define the filter int value returned by the execution order, the lower the number the higher the priority.

Custom filter 4.5.2

Analog verify a login. Basic logic: if there is access-token request parameters, the request is considered valid, release.

  1. Filter class definitions
    Here Insert Picture Description
  2. content
@Component
public class LoginFilter extends ZuulFilter {
    /*过滤器的类型: pre route post error*/
    @Override
    public String filterType() {
        return "pre";
    }

    /*执行顺序:返回值越小,优先级越高*/
    @Override
    public int filterOrder() {
        return 5;
    }

    /*是否执行该过滤器:true:执行run;false:不执行run*/
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /*编写过滤器的业务逻辑*/
    @Override
    public Object run() throws ZuulException {
        //初始化context上下文对象,servlet spring
        RequestContext context = RequestContext.getCurrentContext();

        //获取request对象
        HttpServletRequest request = context.getRequest();

        //获取参数
        String token = request.getParameter("token");

        if(StringUtils.isBlank(token)){
            //拦截
            context.setSendZuulResponse(false);  //是否转发请求,false:表示不转发请求
            context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);  //401-身份未认证 设置相应状态码
            context.setResponseBody("Request Error ! ! !");  //设置相应的提示
        }
        // 校验通过,把登陆信息放入上下文信息,继续向后执行
        context.set("token", token);
        /*返回null,表示过滤器什么都不做*/
        return null;
    }
}
  1. access
    Here Insert Picture Description
Published 92 original articles · won praise 49 · views 40000 +

Guess you like

Origin blog.csdn.net/Xxacker/article/details/104392806