springcloud2 (1) 基础入门

401 阅读8分钟

1. 微服务架构概念

概念:

  • 对比单体架构:
    • 单体架构开发速度慢,启动时间长,依赖庞大。
    • 微服务架构易开发,理解和维护,独立的部署和启动,但存在分布式事务问题,服务治理问题。
  • CAP理论:在一个分布式系统中,分区容错性必须满足,而一致性和可用性二选其一,无法共存:
    • 分区容错性 Partition-tolerance:分布式系统必须保证分区容错性,即使某节点崩溃,整体也要正常对外提供服务,节点越多,分区容错越高。
    • 一致性 Consistency:在响应结果之前先进行节点间完整的数据同步过程,即可保证数据一致性,但同步过程很耗时,可能会因为响应超时而报错(不满足A)。
    • 可用性 Availability:异步执行节点之间的数据同步过程,以保证响应超时,此时服务高可用,但可能会因为来不及同步而导致响应的数据和其他节点不一致(不满足C)。
  • 微服务核心概念:
    • 网关 GATWAY:用于过滤掉所有不合法的路由以及转发路由。
    • 配置中心:存放每个微服务的主配文件,支持动态更新,支持可视化界面,支持同时操作所有服务的配置文件。
    • 链路追踪:分析调用链路节点耗时的一门技术:
      • 如用户下单的链路:调用商品服务获取商品价格 -> 调用用户服务 -> 调用订单服务...,通过链路追踪分析链路上的哪个过程耗时比较久,以进行精准优化。
    • 负载均衡:进行负载分发,如果集群中的A节点压力过大,则将需求分发到集群中的B节点。
    • 熔断:保护自己,如果链路中的某个节点开了熔断保护(一般是不影响大局的节点才选择开启熔断保护),那么假设这个节点10次调用9次返回失败,,熔断机制会立即放弃这个节点,以保证整条链路的流畅性和速度,然后过一段时间后再重试这个节点。
  • 常见微服务框架:需要熟知consumer消费者,provider生产者的两种角色的概念:
    • dubbo:zookeeper + dubbo + springboot
      • dubbo官网
      • 通信方式:rpc(远程方法调用)
      • 注册中心:zookeeper/redis
      • 配置中心:diamond(一款款阿里开源组件)
      • 优点:采用rpc连接,速度快一些。
      • 缺点:框架中的技术模块比较散,需要自己组装。
    • springcloud:springcloud官网
      • 通信方式:http长连接,restful
      • 注册中心:eureka/consul
      • 配置中心:config
      • 断路器:hystrix
      • 网关:zuul
      • 分布式链路追踪系统:sleuth + zipkin
      • 优点:框架中的技术模块是全家桶套装,整合度非常高。
      • 缺点:http长连接,涉及多次握手,速度低一些。

2. 注册中心Eureka

概念: 注册中心用表格的方式来管理和维护微服务集群,以解耦微服务之间的调用过程:

  • 注册中心注册发现流程:
    • A服务启动,向注册中心进行注册登记自己的节点网络信息,如IP,端口等,方法路由信息等。
    • B服务启动,向注册中心进行注册登记自己的节点网络信息,如IP,端口等,方法路由信息等。
    • 每个服务节点都定时向注册中心发送心跳检测,若长时间未发送,则表示该节点已挂。
    • A服务向注册中心发送"调用B服务"的请求。
    • 注册中心找到B服务,并将其网络信息返回给A服务。
    • A服务调用B服务。
  • 主流注册中心:zookeeper,eureka,consul等:
    • zookeeper:CP设计,有主从结构,若主节点挂了,会进行内部投票选举新的主节点,此时不能对外提供服务,且如果半数以上节点不可用时,也无法对外提供服务,可见它无法满足可用性A,一般部分金融行业会选择。
    • eureka:AP原则,无主从节点,一个节点挂了,会自动切换另一个节点,去中心化,以效率为主,但不保证数据一致性,一般部分电商系统会选择。

2.1 创建eureka服务端

概念: Eureka 是springcloud核心组件,Netflix旗下产品,2.x版本已闭源:

  • EurekaServer:eureka服务端维护一个微服务集群列表。
  • EurekaClient:每个微服务都会嵌入一个eureka客户端(Jar包),用于跟eureka服务端交互。

流程: 新建项目 springcloud2-eureka-server

  • 勾选依赖:DevTools/Lombok/Web/Eureka Server
  • 启动类添加注解 @EnableEurekaServer 以启用eureka。
  • 主配添加:
    • server.port=8761:配置eureka服务端端口,默认8761。
    • eureka.instance.hostname=localhost:配置eureka服务端IP。
    • eureka.client.registerWithEureka=false:自己就是注册中心,不用注册自己。
    • eureka.client.fetchRegistry=false:不去注册中心获取其他服务的地址。
    • eureka.client.serviceUrl.defaultZone:配置微服务列表空间,可使用 ${} 表达式动态获取值:
      • http://${eureka.instance.hostname}:${server.port}/eureka/
  • 启动项目并访问eureka服务端界面:
    • cli: http://localhost:8761/

配置: /springcloud-eureka-server/

  • pom:pom.xml
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
  • yml:application.yml

server:
  port: 8761

eureka:
  instance:
    hostname: localhost  #eureka服务端的实例名字
  client:
    register-with-eureka: false    #表识不向注册中心注册自己
    fetch-registry: false   #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/    #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址


2.2 创建eureka客户端

创建eureka客户端文档

流程: 新建项目 springcloud2-product-service 作为客户端:

  • 勾选依赖:DevTools/Lombok/Web/Eureka Discovery Client
  • 启动类添加注解 @EnableEurekaServer 以启用eureka。
  • 主配添加:
    • server.port=8770:配置商品微服务端口。
    • eureka.instance.hostname=localhost:配置商品微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.application.name=product-service:给商品微服务起名。
  • 开发控制类 controller.ProductController
    • 开发商品全查控制方法和按主键查询商品的控制方法,数据模拟即可。
  • 启动项目,观察eureka服务端界面的 Instances currently registered with Eureka 信息:
    • cli: http://localhost:8770/api/v1/product/select-all
    • cli: http://localhost:8770/api/v1/product/find-by-id?id=1

配置: /springcloud-product-server/

  • pom :pom.xml
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

  • 配置:application.yml
#给客户端起名
spring:
  application:
    name: product-service

#配置eureka客户端端口
server:
  port: 8770

eureka:
  #配置eureka客户端IP
  instance:
    hostname: localhost
  #配置对应的eureka服务端地址
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  • src ProductController
/**
 * @author yap
 */
@RestController
@RequestMapping("/api/v1/product")
public class ProductController {

    @RequestMapping("/select-all")
    public Set<String> selectAll() {
        Set<String> result = new HashSet<>();
        result.add("手机");
        result.add("电脑");
        return result;
    }

    @RequestMapping("/select-by-id")
    public String selectById(int id) {
        return id == 1 ? "001-手机" : "002-电脑";
    }
}

3.1 使用ribbon远程通信

流程: 新建项目 springcloud2-order-service-ribbon 作为客户端:

  • 勾选依赖:DevTools/Lombok/Web/Eureka Discovery Client
  • 启动类添加注解 @EnableDiscoveryClient 以启用eureka。
  • 主配添加:
    • server.port=8771:配置订单微服务端口。
    • eureka.instance.hostname=localhost:配置订单微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.application.name=order-service-ribbon:给订单微服务起名。
  • 开发配置类 config.RestTemplateConfig
    • IOC RestTemplate 并额外标记 @LoadBalanced 以启用负载均衡:
      • 如果每个机器的硬件配置一样,则建议使用默认负载均衡策略。
      • 如果多台机器的硬件配置不一样,则可将负载均衡策略改 WeightedResponseTimeRule
  • 开发控制类 controller.OrderController
    • 注入 RestTemplate 类。
    • 开发控制方法 insert():远程调用商品微服务的 selectById() 控制方法,其余订单数据模拟。
  • 启动项目,观察eureka服务端界面的 Instances currently registered with Eureka 信息:
    • cli: http://localhost:8771/api/v1/order/insert?product-id=1 配置: /springcloud2-order-service-ribbon/
  • 配置:application.yml
server:
  port: 8771

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: order-service-ribbon
  • src:config
package com.yap.springcloud2orderserviceribbon.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @author yap
 */
@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

  • src:controller
package com.yap.springcloud2orderserviceribbon.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * @author yap
 */
@RestController
@RequestMapping("/api/v1/order")
public class OrderController {

    private RestTemplate restTemplate;

    @Autowired
    public OrderController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @RequestMapping("insert")
    public Map<String, Object> insert(@RequestParam("product-id") String productId) {

        String url = "http://product-service/api/v1/product/select-by-id?id=" + productId;
        String product = restTemplate.getForObject(url, String.class);

        Map<String, Object> order = new HashMap<>(3);
        order.put("订单号", UUID.randomUUID().toString());
        order.put("订单时间", new Date());
        order.put("商品", product);

        return order;
    }
}

3.2 使用feign远程通信

概念: Feign 是一个伪RPC客户端,其本质仍是http调用,默认集成了ribbon,采用注解方式进行配置,配置熔断等方式方便,写起来更加思路清晰和方便。

流程: 新建项目 springcloud2-order-service-feign

  • 勾选依赖:DevTools/Lombok/Web/Eureka Discovery Client
  • 添加依赖:spring-cloud-starter-openfeign
  • 主配添加:
    • server.port=8772:配置订单微服务端口。
    • eureka.instance.hostname=localhost:配置订单微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.application.name=order-service-feign:给订单微服务起名。
  • 启动类添加 @EnableFeignClients 以启用Feign功能。
  • 开发远程调用接口 ProductFeign.java 对应商品微服务中的 ProductController 类:
    • 接口标记注解 @FeignClient(name = "product-service"):指定对应的微服务名。
    • 仿写商品微服务中的控制方法:要求方法路由,方法签名,方法形参和请求方式等必须全部一致。
    • 参数必须使用 @RequestParam() 进行绑定。
    • 不建议将 @RequestMapping 提取到类上。
  • 开发控制类 controller.OrderController
    • 注入 ProductFeign 类。
    • 开发控制方法 insert():直接调用 ProductFeign 接口中的 selectById(),其余订单数据模拟。
  • 启动项目,观察eureka服务端界面的 Instances currently registered with Eureka 信息:
    • cli: http://localhost:8772/api/v1/order/insert?product-id=1 配置: /springcloud2-order-service-feign/
  • pom:pom.xml
		<!--spring-cloud-starter-openfeign-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>

  • 配置:application.yml
server:
  port: 8772

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: order-service-feign
  • src:feign
package com.yap.springcloud2orderservicefeign.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Set;

/**
 * @author yap
 */
@FeignClient(name = "product-service")
public interface ProductFeign {

    /**
     * 查询全部商品
     * @return 返回全部商品
     */
    @RequestMapping("/api/v1/product/select-all")
    Set<String> selectAll();

    /**
     * 根据主键查询商品信息
     * @param id 主键
     * @return 对应主键的商品信息
     */
    @RequestMapping("/api/v1/product/select-by-id")
    String selectById(@RequestParam("id") int id);
}
  • src:controller
package com.yap.springcloud2orderservicefeign.controller;

import com.yap.springcloud2orderservicefeign.feign.ProductFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author yap
 */
@RestController
@RequestMapping("/api/v1/order")
public class OrderController {


    private ProductFeign productFeign;

    @Autowired
    public OrderController(ProductFeign productFeign){
        this.productFeign = productFeign;
    }


    @RequestMapping("insert")
    public Map<String, Object> insert(@RequestParam("product-id") int productId) {

        String product = productFeign.selectById(productId);

        Map<String, Object> order = new HashMap<>(3);
        order.put("订单号", UUID.randomUUID().toString());
        order.put("订单时间", new Date());
        order.put("商品", product);

        return order;
    }
}

4. 熔断降级Hystrix

概念: Hystrix 豪猪断路器提供了当分布式系统发生高负载,高流量或网络异常情况下的熔断,隔离,Fallback兜底数据,Cache,监控等功能,以保证系统高可用,一般仅对不影响大局的服务开启熔断保护:

  • 熔断:当某个下游服务发生超时,异常等错误时,立刻熔断该服务可以避免整个系统崩溃,过一段时间后再重试这个服务。
  • 降级:主动抛弃一些非核心服务以暂时将更多资源分配给核心服务。

4.1 Hystrix配合ribbon

流程: 新建项目 springcloud2-order-service-ribbon-hystrix

  • 勾选依赖:DevTools/Lombok/Web/Eureka Discovery Client
  • 添加依赖:spring-cloud-starter-netflix-hystrix
  • 主配添加:
    • server.port=8773:配置订单微服务端口。
    • eureka.instance.hostname=localhost:配置订单微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.application.name=order-service-ribbon-hystrix:给订单微服务起名。
  • 启动类添加 @EnableHystrix 以启用熔断功能。
  • 开发控制类 controller.OrderController
    • 注入 RestTemplate 类。
    • 开发控制方法 insert():远程调用商品微服务的 selectById() 控制方法,其余订单数据模拟。
    • 在控制方法 insert() 上标记 @HystrixCommand(fallbackMethod = "insertFall"),指定降级方法。
    • 开发降级方法 insertFall():要求参数和返回值必须和控制方法一致,返回兜底数据,开发人员告警。
  • 测试:
    • cli: http://localhost:8773/api/v1/order/insert?product-id=1
    • 停止商品服务以触发熔断,测试是否返回兜底数据。
    • 重新启动商品服务,等一阵子,测试是否恢复功能。 源码:
  • pom:pom.xml
		<!--spring-cloud-starter-netflix-hystrix-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
			<!--自定义版本-->
			<version>2.2.6.RELEASE</version>
		</dependency>
  • 配置:application.yml
server:
  port: 8773

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: order-service-ribbon-hystrix
  • src:config
package com.yap.springcloud2orderserviceribbonhystrix.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @author yap
 */
@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • src:controller
package com.yap.springcloud2orderserviceribbonhystrix.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author yap
 */
@RestController
@RequestMapping("/api/v1/order")
public class OrderController {

    private RestTemplate restTemplate;

    @Autowired
    public OrderController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @HystrixCommand(fallbackMethod = "insertFall")
    @RequestMapping("insert")
    public Map<String, Object> insert(@RequestParam("product-id") String productId) {
        String url = "http://product-service/api/v1/product/select-by-id?id=" + productId;
        String product = restTemplate.getForObject(url, String.class);
        Map<String, Object> order = new HashMap<>(3);
        order.put("订单号", UUID.randomUUID().toString());
        order.put("订单时间", new Date());
        order.put("商品", product);
        return order;
    }

    public Map<String, Object> insertFall(@RequestParam("product-id") String productId) {
        Map<String, Object> order = new HashMap<>(3);
        order.put("订单号", UUID.randomUUID().toString());
        order.put("订单时间", new Date());
        order.put("商品", "兜底数据");
        System.out.println("发短信...");
        return order;
    }
}

4.2 Hystrix配合feign

流程: 新建项目 springcloud2-order-service-feign-hystrix

  • springboot版本降为 2.3.9.RELEASE,springcloud版本降为 Hoxton.SR10
  • 勾选依赖:DevTools/Lombok/Web/Eureka Discovery Client/Hystrix[Maintenance]
  • 添加依赖:spring-cloud-starter-openfeign
  • 主配添加:
    • server.port=8774:配置订单微服务端口。
    • eureka.instance.hostname=localhost:配置订单微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.application.name=order-service-feign-hystrix:给订单微服务起名。
    • feign.client.hystrix.enabled=true:启用熔断机制。
    • feign.client.config.default.connectTimeout=2000:连接超时时间2秒。
    • feign.client.config.default.readTimeout=2000:操作超时时间2秒。
  • 启动类添加 @EnableHystrix 以启用熔断功能。
  • 启动类添加 @EnableFeignClients 以启用Feign功能。
  • 开发远程调用接口 ProductFeign 对应商品微服务中的 ProductController 类:
    • @FeignClient() 中添加 fallback,值为自定义降级类。
      • @FeignClient(name = "product-service", fallback = ProductFallBack.class)
  • 创建降级类 ProcuctFallBack
    • 实现 ProductFeign 接口。
    • 标记 @Component 以被spring管理。
  • 开发控制类 controller.OrderController
    • 注入 ProductFeign 类。
    • 开发控制方法 insert():远程调用商品微服务的 selectById() 控制方法,其余订单数据模拟。
  • 测试:
    • cli: http://localhost:8774/api/v1/order/insert?product-id=1
    • 停止商品服务以触发熔断,测试是否返回兜底数据。
    • 重新启动商品服务,等一阵子,测试是否恢复功能。 源码:
  • pom:pom.xml
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>

		<!--spring-cloud-starter-openfeign-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>

  • 配置:application.yml
server:
  port: 8774

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: order-service-feign-hystrix

feign:
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 2000
  hystrix:
    enabled: true
  • src:ProductFeign
package com.yap.springcloud2orderservicefeignhystrix.feign;

import com.yap.springcloud2orderservicefeignhystrix.fallback.ProductFallBack;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Set;

/**
 * @author yap
 */
@Qualifier("productFeign")
@FeignClient(name = "product-service", fallback = ProductFallBack.class)
public interface ProductFeign {

    /**
     * 查询全部商品
     *
     * @return 返回全部商品
     */
    @RequestMapping("/api/v1/product/select-all")
    Set<String> selectAll();

    /**
     * 根据主键查询商品信息
     *
     * @param id 主键
     * @return 对应主键的商品信息
     */
    @RequestMapping("/api/v1/product/select-by-id")
    String selectById(@RequestParam("id") int id);

}

  • src:ProcuctFallBack
package com.yap.springcloud2orderservicefeignhystrix.fallback;

import com.yap.springcloud2orderservicefeignhystrix.feign.ProductFeign;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * @author yap
 */
@Component
public class ProductFallBack implements ProductFeign {

    @Override
    public Set<String> selectAll() {
        Set<String> result = new HashSet<>();
        result.add("熔断");
        System.out.println("告警...");
        return result;
    }

    @Override
    public String selectById(int id) {
        System.out.println("告警...");
        return "熔断";
    }

}
  • src:controller
package com.yap.springcloud2orderservicefeignhystrix.controller;

import com.yap.springcloud2orderservicefeignhystrix.feign.ProductFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author yap
 */
@RestController
@RequestMapping("/api/v1/order")
public class OrderController {

    private ProductFeign productFeign;

    @Autowired
    public OrderController(@Qualifier("productFeign") ProductFeign productFeign){
        this.productFeign = productFeign;
    }

    @RequestMapping("insert")
    public Map<String, Object> insert(@RequestParam("product-id") int productId) {
        String product = productFeign.selectById(productId);
        Map<String, Object> order = new HashMap<>(3);
        order.put("订单号", UUID.randomUUID().toString());
        order.put("订单时间", new Date());
        order.put("商品", product);
        return order;
    }
}

Hystrix降级策略和调整

官方文档

  • Hystrix熔断策略有两种:
    • THREAD 线程池隔离 (默认)
    • SEMAPHORE 信号量,适用于接口并发量高的情况,超过信号量的线程会被拒绝。

配置:设置策略(无提示)

# 设置hystrix策略为thread,且超时时间为4秒,默认1000毫秒
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000

# 设置hystrix策略为semaphore,且最大信号量为50,默认为10
hystrix:
  command:
    default:
      execution:
        isolation:
          semaphore:
            maxConcurrentRequests: 50

4.3 Dashboard监控仪表

概念: Dashboard 监控仪表盘通过SSE推送技术来监控服务请求状态:

流程: 新建项目 springcloud2-order-service-dashboard

  • 勾选依赖:DevTools/Lombok/Web/Eureka Discovery Client/OpenFeign/Hystrix[Maintenance]
  • 添加依赖:
    • spring-cloud-starter-netflix-hystrix-dashboard
    • spring-boot-starter-actuator
  • 启动类添加:
    • @EnableHystrixDashboard 以启用监控仪表盘功能。
    • @EnableFeignClients 以启用Feign远程连接功能。
    • @EnableHystrix 以启用熔断功能。
  • 主配添加:
    • server.port=8775:配置订单微服务端口。
    • eureka.instance.hostname=localhost:配置订单微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.application.name=order-service-dashboard:给订单微服务起名。
    • feign.client.hystrix.enabled=true:启用熔断机制。
    • feign.client.config.default.connectTimeout=2000:连接超时时间2秒。
    • feign.client.config.default.readTimeout=2000:操作超时时间2秒。
    • hystrix.dashboard.proxy-stream-allow-list=localhost:设置dashboard监控IP地址为localhost。
    • management.endpoints.web.exposure.include="*":对外暴露全部端点。
  • 创建降级类 ProcuctFallBack
    • 实现 ProductFeign 接口。
    • 标记 @Component 以被spring管理。
  • 开发远程调用接口 ProductFeign 对应商品微服务中的 ProductController 类:
    • @FeignClient() 中添加 fallback,值为自定义降级类。
  • 开发控制类 controller.OrderController
    • 注入 ProductFeign 类。
    • 开发控制方法 insert():直接调用 ProductFeign 接口中的 selectById() 控制方法,其余订单数据模拟。
  • 测试:
    • cli: http://localhost:8775/hystrix
    • Hystrix Dashboard 栏输入 http://localhost:8775/actuator/hystrix.stream
    • psm: http://localhost:8775/api/v1/order/insert?product-id=2,使用runner循环发送1K次。 源码:
  • pom:pom.xml
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
  • 配置:application.yml
server:
  port: 8775

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: order-service-dashboard

feign:
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 2000
  hystrix:
    enabled: true

hystrix:
  dashboard:
    proxy-stream-allow-list: "localhost"
# a
management:
  endpoints:
    web:
      exposure:
        include: "*"


  • src:ProductFeign
package com.yap.springcloud2orderservicefeignhystrix.feign;

import com.yap.springcloud2orderservicefeignhystrix.fallback.ProductFallBack;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Set;

/**
 * @author yap
 */
@Qualifier("productFeign")
@FeignClient(name = "product-service", fallback = ProductFallBack.class)
public interface ProductFeign {

    /**
     * 查询全部商品
     *
     * @return 返回全部商品
     */
    @RequestMapping("/api/v1/product/select-all")
    Set<String> selectAll();

    /**
     * 根据主键查询商品信息
     *
     * @param id 主键
     * @return 对应主键的商品信息
     */
    @RequestMapping("/api/v1/product/select-by-id")
    String selectById(@RequestParam("id") int id);

}

  • src:ProcuctFallBack
package com.yap.springcloud2orderservicefeignhystrix.fallback;

import com.yap.springcloud2orderservicefeignhystrix.feign.ProductFeign;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * @author yap
 */
@Component
public class ProductFallBack implements ProductFeign {

    @Override
    public Set<String> selectAll() {
        Set<String> result = new HashSet<>();
        result.add("熔断");
        System.out.println("告警...");
        return result;
    }

    @Override
    public String selectById(int id) {
        System.out.println("告警...");
        return "熔断";
    }

}
  • src:controller
package com.yap.springcloud2orderservicefeignhystrix.controller;

import com.yap.springcloud2orderservicefeignhystrix.feign.ProductFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author yap
 */
@RestController
@RequestMapping("/api/v1/order")
public class OrderController {

    private ProductFeign productFeign;

    @Autowired
    public OrderController(@Qualifier("productFeign") ProductFeign productFeign){
        this.productFeign = productFeign;
    }

    @RequestMapping("insert")
    public Map<String, Object> insert(@RequestParam("product-id") int productId) {
        String product = productFeign.selectById(productId);
        Map<String, Object> order = new HashMap<>(3);
        order.put("订单号", UUID.randomUUID().toString());
        order.put("订单时间", new Date());
        order.put("商品", product);
        return order;
    }
}

5. 网关zuul

流程: 新建项目 springcloud2-order-service-zuul

  • springboot版本降为 2.3.9.RELEASE,springcloud版本降为 Hoxton.SR10
  • 勾选依赖:DevTools/Lombok/Web/Eureka Discovery Client/OpenFeign/Hystrix[Maintenance]
  • 启动类添加:
    • @EnableFeignClients 以启用Feign远程连接功能。
    • @EnableHystrix 以启用熔断功能。
  • 主配添加:
    • server.port=8776:配置订单微服务端口。
    • eureka.instance.hostname=localhost:配置订单微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.application.name=order-service-zuul:给订单微服务起名。
    • feign.client.hystrix.enabled=true:启用熔断机制。
    • feign.client.config.default.connectTimeout=2000:连接超时时间2秒。
    • feign.client.config.default.readTimeout=2000:操作超时时间2秒。
  • 开发降级处理类 fallback.ProductFallBack
    • 实现 ProductFeign 接口。
    • 标记 @Component 以被spring管理。
    • 重写商品微服务中 ProductController 的控制方法,方法体开发降级处理,返回兜底数据。
  • 开发远程调用接口 feign.ProductFeign 对应商品微服务中的 ProductController 类:
    • @FeignClient() 中添加 fallback,值为自定义降级类。
  • 开发控制类 controller.OrderController
    • 注入 ProductFeign 类。
    • 开发控制方法 insert():直接调用 ProductFeign 接口中的 selectById() 控制方法,其余订单数据模拟。
    • 开发控制方法 getCookie():在形参中注入 HttpServletRequest 实例,返回cookie内容。
  • 测试:
    • cli: http://localhost:8776/api/v1/order/insert?product-id=1
    • cli: http://localhost:8776/api/v1/order/get-cookie 源码:
  • 配置:application.yml

server:
  port: 8777

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: order-service-zuul

feign:
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 2000
  hystrix:
    enabled: true
  • src:ProductFeign
package com.yap.springcloud2orderservicefeignhystrix.feign;

import com.yap.springcloud2orderservicefeignhystrix.fallback.ProductFallBack;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Set;

/**
 * @author yap
 */
@Qualifier("productFeign")
@FeignClient(name = "product-service", fallback = ProductFallBack.class)
public interface ProductFeign {

    /**
     * 查询全部商品
     *
     * @return 返回全部商品
     */
    @RequestMapping("/api/v1/product/select-all")
    Set<String> selectAll();

    /**
     * 根据主键查询商品信息
     *
     * @param id 主键
     * @return 对应主键的商品信息
     */
    @RequestMapping("/api/v1/product/select-by-id")
    String selectById(@RequestParam("id") int id);

}

  • src:ProcuctFallBack
package com.yap.springcloud2orderservicefeignhystrix.fallback;

import com.yap.springcloud2orderservicefeignhystrix.feign.ProductFeign;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * @author yap
 */
@Component
public class ProductFallBack implements ProductFeign {

    @Override
    public Set<String> selectAll() {
        Set<String> result = new HashSet<>();
        result.add("熔断");
        System.out.println("告警...");
        return result;
    }

    @Override
    public String selectById(int id) {
        System.out.println("告警...");
        return "熔断";
    }

}
  • src:controller
package com.yap.springcloud2orderservicefeignhystrix.controller;

import com.yap.springcloud2orderservicefeignhystrix.feign.ProductFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author yap
 */
@RestController
@RequestMapping("/api/v1/order")
public class OrderController {

    private ProductFeign productFeign;

    @Autowired
    public OrderController(@Qualifier("productFeign") ProductFeign productFeign){
        this.productFeign = productFeign;
    }

    @RequestMapping("insert")
    public Map<String, Object> insert(@RequestParam("product-id") int productId) {
        String product = productFeign.selectById(productId);
        Map<String, Object> order = new HashMap<>(3);
        order.put("订单号", UUID.randomUUID().toString());
        order.put("订单时间", new Date());
        order.put("商品", product);
        return order;
    }
}

流程: 新建项目 springcloud2-zuul

  • springboot版本降为 2.3.9.RELEASE,springcloud版本降为 Hoxton.SR10
  • 勾选依赖:Eureka Discovery Client/Zuul
  • 启动类添加:
    • @EnableZuulProxy 以启用Zuul网关功能。
  • 主配添加:
    • server.port=9000:配置网关微服务的端口号。
    • eureka.instance.hostname=localhost:配置网关微服务的IP地址。
    • spring.application.name=zuul:设置网关微服务名字。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
  • 测试:启动服务,网关就开启了,在eureka服务端界面中可以查看到该9000服务,然后通过网关访问订单微服务:
    • psm: localhost:9000/order-service-zuul/api/v1/order/insert?product-id=1
    • psm: localhost:9000/order-service-zuul/api/v1/order/get-cookie:无法通过网关获取请求头信息。
    • 开启多个网关节点以部署集群,可以在启动界面的 VM Options 中添加 -Dserver.port=9001 后再启动一个新的网关。 源码:
  • 配置:application.yml
server:
  port: 9000
eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: zuul

隐私

  • zuul.routes.prefix=/zuul:设置自定义路由前缀。
  • zuul.routes.order-service-zuul=/order/**:为order-service-zuul设置别名以保护隐私,全值需要拼前缀。
  • zuul.routes.product-service=/product/**:为product-service设置别名以保护隐私,全值需要拼前缀。
  • zuul.ignored-patterns=/*-service*/**:将指定的路由屏蔽,此时URL不可以直接访问。
  • zuul.sensitive-headers::zuul网关默认屏蔽掉了请求头中的 Cookie/Set-Cookie/Authorization,该值设置为空不屏蔽敏感头。
zuul:
  routes:
    prefix: /zuul
    order-service-zuul: /order/**
    product-service: /product/**
  ignored-patterns: /*-service*/**
  sensitive-headers:

网关过滤器鉴权

流程: 依赖 springcloud2-zuul

  • 开发一个鉴权过滤器:
    • 继承 ZuulFilter 类。
    • 标记 @Component 以被spring管理。
    • 重写 FilterType():设置过滤器为前置过滤器。
    • 重写 FilterOrder():返回值越小,优先级越高。
    • 重写 shouldFilter():设置对下单接口order进行过滤:
      • 获取请求,判断uri路径中是否存在 /zuul/order,若存在,则需要被过滤。
    • 重写 run():被过滤后执行的业务处理:
      • 从请求头获取token,如果为空再尝试从请求参数中获取,若都为空,阻止向下运行,并响应 "认证失败"。
  • 测试:
    • psm: localhost:9000/zuul/order/api/v1/order/insert?product-id=1,不带token。
    • psm: localhost:9000/zuul/order/api/v1/order/insert?product-id=1,带token。 源码:
package com.yap.springcloud2zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author yap
 */
@Component
public class AuthFilter extends ZuulFilter {

    /**
     * 配置过滤器为前置过滤器还是后置过滤器
     *
     * @return FilterConstants.PRE_TYPE表示前置过滤器,FilterConstants.POST_TYPE表示后置过滤器
     */
    @Override
    public String filterType() {
        // 设置本过滤器在请求分发之前执行
        return FilterConstants.PRE_TYPE;
    }

    /**
     * 配置过滤器执行顺序
     *
     * @return 值越小,优先级越高
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 配置哪些请求被过滤
     *
     * @return true 需要被过滤,false 直接放行
     */
    @Override
    public boolean shouldFilter() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest req = currentContext.getRequest();
        String uri = req.getRequestURI();
        // 若当前请求中包含 "/zuul/order",则需要被过滤
        return uri.contains("/zuul/order");
    }

    /**
     * 配置对所有过滤出来的请求做的操作
     *
     * @return 直接返回null即可
     */
    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest req = currentContext.getRequest();
        String token = req.getHeader("token");
        if (StringUtils.isBlank(token)) {
            token = req.getParameter("token");
            if (StringUtils.isBlank(token)) {

                // 返回给调用方一个HTTP未认证状态
                currentContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                currentContext.setResponseBody("token error...");
                // 阻止分发请求
                currentContext.setSendZuulResponse(false);
            }
        }
        return null;
    }
}

网关过滤器限流

概念: 限流的意义是保护下游服务:

  • 令牌桶算法:每秒放置100个令牌,请求进来,尝试获取令牌,获取成功进入,失败拒绝。

流程: 依赖 springcloud2-zuul

  • 开发一个限流过滤器:
    • 继承 ZuulFilter 类。
    • 标记 @Component 以被spring管理。
    • 重写 FilterType():设置过滤器为前置过滤器。
    • 重写 FilterOrder():返回值越小,优先级越高。
    • 重写 shouldFilter():设置对下单接口order进行过滤:
      • 获取请求,判断uri路径中是否存在 /zuul/order,若存在,则需要被过滤。
    • 重写 run():被过滤后执行的业务处理:
      • 设置令牌桶 RateLimiter 属性,设置每秒产生1000个令牌。
      • 每个请求尝试从令牌桶中获取令牌,若失败则阻止向下运行,阻止向下运行,并响应 "请求过多"。
  • 测试:压测。 源码:
package com.yap.springcloud2zuul.filter;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author yap
 */
@Component
public class RequestLimitFilter extends ZuulFilter {

    /**
     * 新建一个令牌桶每秒产生1000个令牌
     */
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);

    /**
     * 配置过滤器为前置过滤器还是后置过滤器
     *
     * @return FilterConstants.PRE_TYPE表示前置过滤器,FilterConstants.POST_TYPE表示后置过滤器
     */
    @Override
    public String filterType() {
        // 设置本过滤器在请求分发之前执行
        return FilterConstants.PRE_TYPE;
    }

    /**
     * 配置过滤器执行顺序
     *
     * @return 值越小,优先级越高
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 配置哪些请求被过滤
     *
     * @return true 需要被过滤,false 直接放行
     */
    @Override
    public boolean shouldFilter() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest req = currentContext.getRequest();
        String uri = req.getRequestURI();
        // 若当前请求中包含 "/zuul/order",则需要被过滤
        return uri.contains("/zuul/order");
    }

    /**
     * 配置对所有过滤出来的请求做的操作
     *
     * @return 直接返回null即可
     */
    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        if (!RATE_LIMITER.tryAcquire()) {
            // 返回给调用方一个请求过多状态
            currentContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
            currentContext.setResponseBody("too many requests...");
            // 阻止分发请求
            currentContext.setSendZuulResponse(false);
        }
        return null;
    }
}

配置中心config

概念: 配置中心可以统一管理微服务的配置,以及快速切换各个环境的配置:

  • 配置中心服务端:负责连接github/gitee等云配置中心地址。
  • 配置中心客户端:从服务端拉取配置。

流程: 创建gitee项目:

  • 创建一个 product-service-test.yml 文件:
    • server.port=8777:端口号。
    • env=test:当前为测试环境。
    • branch=master:当前分支为master。
  • 创建一个 product-service-dev.yml 文件:
    • server.port=8777:端口号。
    • env=dev:当前为开发环境。
    • branch=master:当前分支为master。

流程: 新建配置中心服务端项目 springcloud2-config-server

  • 勾选依赖:Eureka Discovery Client/Config Server
  • 启动类添加:
    • @EnableConfigServer 以启用config配置中心服务端。
  • 主配添加:
    • server.port=9100:配置配置中心微服务端口。
    • spring.application.name=gitee-config:给配置中心微服务起名。
    • eureka.instance.hostname=localhost:配置配置中心微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.cloud.config.server.git.uri:值为gitee项目地址。
    • spring.cloud.config.server.git.username:值为gitee账号,如 springcloudconfig@163.com
    • spring.cloud.config.server.git.password:值为gitee密码,如 config123456
    • spring.cloud.config.server.git.timeout:值为gitee连接超时时间,单位秒。
    • spring.cloud.config.server.git.default-label:值为gitee库分支,默认master。
  • 启动eureka配置中心,启动配置中心微服务:
    • cli: http://localhost:9100/master/product-service-test.yml:分支为master时可以省略。
    • cli: http://localhost:9100/master/product-service-dev.yml:分支为master时可以省略。 源码:
  • 配置:application.yml
# config配置中心微服务的端口
server:
  port: 9100

# config配置中心微服务的名字
spring:
  application:
    name: gitee-config
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/yang-aopeng/product-service.git
          username: xxxxxxxxxx@qq.com
          password: xxxxxxxxxx
          timeout: 5
          default-label: master

# eureka注册中心
eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

流程: 新建配置中心客户端项目 springcloud2-product-service-config

  • 勾选依赖:DevTools/Lombok/Web/Eureka Discovery Client/Config Client
  • 主配添加:主配的名字必须修改为 bootstrap.yml
    • eureka.instance.hostname=localhost:配置商品微服务的IP。
    • eureka.client.serviceUrl.defaultZone:配置对应的eureka服务端地址:
      • http://localhost:8761/eureka/
    • spring.application.name=product-service-config:给商品微服务起名。
    • spring.cloud.config.name=product-service:指定gitee上的配置文件的名字,无需添加环境和分支。
    • spring.cloud.config.profile=test:指定gitee上的配置文件的环境。
    • spring.cloud.config.label=master:指定gitee上的配置文件的分支。
    • spring.cloud.config.uri=http://localhost:9100/:指定gitee上的配置文件的分支。
  • 开发控制类 controller.ProductController
    • 开发商品全查控制方法,数据模拟即可。
  • 启动eureka注册中心,再启动配置中心,再启动本微服务:
    • cli: http://localhost:8777/api/v1/product/select-all 源码:
  • 配置:bootstrap.yml
#指定注册中心地址
eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

#服务的名称
spring:
  application:
    name: product-service-config
  #指定从哪个配置中心读取
  cloud:
    config:
      name: product-service
      profile: dev
      label: master
      uri: http://localhost:9100/
  • src:ProductController
package com.yap.z25springcloud2productserviceconfig.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashSet;
import java.util.Set;

/**
 * @author yap
 */
@RestController
@RequestMapping("/api/v1/product")
public class ProductController {

    @RequestMapping("select-all")
    public Set<String> selectAll() {
        Set<String> result = new HashSet<>();
        result.add("手机");
        result.add("电脑");
        return result;
    }
}

alibaba sentinel

概念: 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 Sentinel特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
  • Sentinel分为:服务端和客户端
    • 服务端有可视化界面,便于操作,功能十分强大和实用。
    • 客户端如果是maven项目,需引入jar后,大家都知道,既然分为服务端和客户端,客户端必须配置连接服务端的地址,即可和服务端通信并完成限流功能。

流程: pom.xml中引入依赖

<!--spring-cloud-starter-alibaba-sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

主配添加:

  • spring.application.name=frms
  • spring.cloud.sentinel.transport.dashboard=localhost:8080
  • spring.cloud.sentinel.transport.heartbeat-interval-ms=500 测试:
  • 启动客户端服务,调用接口,可在服务端查看客户端信息
    • 给selectUnitTreeList查询接口添加流控规则,它的QPS(每秒请求数)为1,如图:   - 通过频繁调用selectUnitTreeList查询接口,通过监控可以看到如图信息:
  • 降级规则配置
    • 给selectUnitTreeList接口查询添加一个降级规则配置,如果QPS大于1,且平均响应时间大于20ms,则接口下来接口在2秒钟无法访问,之后自动恢复。

image.png