sentinel熔断

sentinel分布式系统的流量防卫兵

由于Netflix中多项开源产品已进入维护阶段,不再开发新的版本,就目前来看是没有什么问题的。但是从长远角度出发,我们还是需要考虑是否有可替代产品使用。比如本文中要介绍的Alibaba Sentinel就是一款高性能且轻量级的==流量控制,熔断降级==可替换方案。

Sentinel官网: http://github.com/alibaba/Sentinel

HyStrix目前状态:

​ 官网: http://github.com/Netflix/Hystrix

1. 学习目标

 

2. Sentinel是什么

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

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel 的主要特性:

Sentinel 的开源生态:2018年 

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。【客户端】

  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。 [服务端]

3. Sentinel的核心

Sentinel的使用可以分为两个部分:

  • 核心库(Java客户端)∶不依赖任何框架/库,能够运行于Java 7及以上的版本的运行时环境,同时对Dubbo / Spring Cloud等框架也有较好的支持(见主流框架适配)。

  • 控制台(Dashboard) :控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。

4. Sentinel的控制台

Sentinel提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。

官方文档: https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0

4.1 获取控制台

您可以从 release 页面 下载最新版本的控制台 jar 包。

您也可以从最新版本的源码自行构建 Sentinel 控制台:

  • 下载 控制台 工程

  • 使用以下命令将代码打包成一个 fat jar: mvn clean package

4.2 启动控制台

注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。

使用如下命令启动控制台:

 

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080

从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel。可以参考 鉴权模块文档 配置用户名和密码。

注:若您的应用为 Spring Boot 或 Spring Cloud 应用,您可以通过 Spring 配置文件来指定配置,详情请参考 Spring Cloud Alibaba Sentinel 文档

5. 项目环境

  • shop-product: 商品服务,提供了 /product/findById/{id}

  • shop-order-rest: 订单服务,基于Ribbon通过RestTemplate调用商品服务。

  • shop-order-feign:订单服务,基于Feign通过声明式服务调用商品服务。

6. 客户端接入控制台

控制台启动后,客户端需要按照如下步骤接入到控制台:

  • 添加依赖

  • 定义资源

  • 定义规则

先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。

6.1 添加依赖

子工程需要添加如下依赖:

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

6.1.1 配置文件

客户端需要启动Transport 模块来与Sentinel控制台进行通信。

shop-order-rest 的application.yml

spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: localhost:8080

spring:

  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080

6.1.2 初始化客户端

确保客户端有访问量,Sentinel会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。

简单的理解就是:访问一次客户端,Sentinel即可完成客户端初始化操作,并持续向控制台发送心跳包。

6.1.3 访问

首先确保Sentinel是启动状态,然后依次启动 nacos,shop-product,shop-order-rest。多次访问: http://localhost:9090/order/saveOrder?pid=1&num=2然后查看控制台实时监控结果如下:

6.2 定义资源

资源是Sentinel中的核心概念之一。我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。最常用的资源是我们代码中的Java方法。Sentinel提供了@SentinelResource注解用于定义资源,并提供了AspectJ的扩展用于自动定义资源、处理BlockException等。

package shoporder.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
import shopcommon.entity.Product;

/**
 * @program: springboot-parent2
 * @description: aaaa
 * @author: 孙彦伟
 * @create: 2021-07-15 16:15
 **/
public class ProductServiceImpl_block implements ProductService {

    @Autowired
    private RestTemplate restTemplate;
    @Override
    //value定义资源
    //fallback:异常定底方案﹑必须与该方法的放回值一致,参数必须一直。额外多出一个异常对象lf
    // blockHandler:熔断空底方案
    @SentinelResource(value = "findById"
            ,blockHandler = "blockHandler"
            ,fallback = "fallback")
    public Product findByid(Integer pid) {
        return restTemplate.getForObject("http://shop-product/product/findById/"+pid,Product.class);
    }
    public Product blockHandler(Integer pid, BlockException ex){
        return new Product(pid,"服务器熔断降级限流控制-兜底的数据",4.0,0);
    }
    public Product fallback(Integer pid,Throwable ex){
        return new Product(pid,"服务器----异常--控制-兜底的数据",4.0,0);
    }

}

package com.ykq.service.impl;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.ykq.entity.Product;
import com.ykq.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
 * @Author 闫克起
 * @Date 2021/5/28 23:59
 * @Version 1.0
 */
@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private RestTemplate restTemplate;
    @Override
    @SentinelResource(value = "findByid",blockHandler = "selectByIdBlock",fallback = "selectByIdBack")
    public Product findByid(Integer pid) {
        return restTemplate.getForObject("http://shop-product/product/findById?pid="+pid,Product.class);
    }
     //熔断降级的兜底方法 异常 或者响应超时时  BlockExecption
    public Product selectByIdBlock(Integer pid, BlockException ex){
        return new Product(pid,"服务熔断降级限流控制-兜底的数据",5555.0,1000);
    }
    //限流兜底方法。 必须与资源的方法参数一致。返回类型一致。
    public Product selectByIdBack(Integer pid, Throwable ex){
        return new Product(pid,"服务异常控制-兜底的数据",6666.0,1000);
    }
}

6.3.定义规则

Sentinel的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时Sentinel 也提供相关API,供您来定制自己的规则策略。Sentinel支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则和热点参数规则

6.3.1.流量控制规则。

选择簇点链路找到定义好的资源selectProductById 并点击对应的规则按钮进行设置。

6.3.3 .动态规则扩展

SentinelProperties内部提供了TreeMap类型的 datasource属性用于配置数据源信息。支持:·

  • 文件配置规

  • Nacos配置规则

  • ZooKeeper配置规则

  • Apollo配置规则

  • Redis配置规则

6.3.3.1.文件配置规则

Sentinel支持通过本地文件加载规则配置,使用方式如下(限流规则作为演示)︰

spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          file:
            file: classpath:flowRule.json
            data-type: json
            rule-type: flow

flowRule.json对应 com.alibaba.csp .sentinel.slots.block .RuleConstant各属性。

[

{
​ "resource":"findByid",
  "count":1,
  "grade":1,
  "limitApp":"default",
  "strategy":0,
  "controlBehavior":0
}
]

 

7. RestTemplate支持

Spring Cloud Alibaba Sentinel支持对RestTemplate调用的服务进行服务保护。需要在构造RestTemplate Bean时添加SentinelRestTemplate注解。

7.1.启动类

package shoporder;
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
//import shoporder.util.ExceptionUtil;
/**
 * @program: springboot-parent2
 * @description: 主启动类
 * @author: 孙彦伟
 * @create: 2021-07-06 19:45
 **/
@SpringBootApplication
//包扫描
@MapperScan(basePackages = {"shoporder.mapper"})
//开启openfeign微服务调用
@EnableFeignClients
public class OrderApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderApp.class,args);
    }
//    @Bean
//    //自动从注册中心获取服务清单
//    @LoadBalanced
    @SentinelRestTemplate(fallback = "fallback"
            ,fallbackClass = ExceptionUtil.class
            ,blockHandler = "handlerException"
            ,blockHandlerClass = ExceptionUtil.class)
//    public RestTemplate restTemplate(){
//        return new RestTemplate();
//    }
}

 
package com.ykq;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.ykq.handler.ExceptionUtil;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
 * @Author 闫克起
 * @Date 2021/5/24 16:48
 * @Version 1.0
 */
@SpringBootApplication
@MapperScan(basePackages = {"com.ykq.mapper"})
public class OrderApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderApp.class,args);
    }
    @Bean
    @LoadBalanced //①ribbon会自动从注册中心中拉取服务清单。按照一定的策略调用响应的服务提供者。 默认采用的策略为轮询,
    //fallback:表示异常触发的降级
    //blockback: 限流
    @SentinelRestTemplate(fallback = "fallback",fallbackClass = ExceptionUtil.class,blockHandler = "handlerException",blockHandlerClass =ExceptionUtil.class )
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
//
 

 
package com.ykq.handler;
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.fastjson.JSON;
import com.sun.deploy.security.BlockedException;
import com.ykq.entity.Product;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
/**
 * @Author 闫克起
 * @Date 2021/5/29 12:53
 * @Version 1.0
 */
@Component
public class ExceptionUtil {
    public static ClientHttpResponse fallback(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception){
        return new SentinelClientHttpResponse(JSON.toJSONString(new Product(1,"服务流量控制-兜底的数据",5555.0,1000)));
    }
    public static ClientHttpResponse handlerException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception){
        return new SentinelClientHttpResponse(JSON.toJSONString(new Product(1,"服务熔断降级控制-兜底的数据",6666.0,1000)));
    }
}

7.3.访问

控制台设置流星控制规则,定义资源访问的QPs为1(每秒能处理查询数目)。快速刷新页面多次访问: http://localhost:9090/order/1结果如下:

 

 

 

8. openfeign的支持

其实不管是Hystrix还是Sentinel对于Feign的支持,核心代码基本上是一致的,只需要修改依赖和配置文件即可。

8.1 添加依赖

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

8.2 开启Sentinel

 
 spring:

  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
feign:
  sentinel:
    enabled: true

8.3 创建一个Feign接口的实现类

package shoporder.feign;

import org.springframework.stereotype.Component;
import shopcommon.entity.Product;

/**
 * @program: springboot-parent2
 * @description: 分的实现类
 * @author: 孙彦伟
 * @create: 2021-07-15 18:40
 **/
@Component
public class ProductFeignFallBack implements ProductFeign{
    //findById的兜底方法
    @Override
    public Product findById(Long pid) {
        Product product=new Product();
        product.setPid(pid);
        product.setPname("为feign中findById的兜底方法");
        return product;
    }
}

package com.ykq.feign;

import com.ykq.entity.Product;
import org.springframework.stereotype.Component;
/**
 * @program: qy129-springcloud-alibaba
 * @description: ProductFeign远程调用的兜底方法
 * @author: 闫克起
 * @create: 2021-07-14 14:49
 **/
@Component
public class ProductFeignFallBack implements ProductFeign{
    @Override
    public Product findById(Integer pid) {
        Product product = new Product();
        product.setPid(pid);
        product.setPname("兜底数据");
        return product;
    }
}
 

8.4 在Feign上使用兜底类

package shoporder.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import shopcommon.entity.Product;

//微服务提供者的名称
//fallback指定分兜底的类
@FeignClient(value = "shop-product",fallback = ProductFeignFallBack.class)
//@RequestMapping("product")
public interface ProductFeign {
    @GetMapping("/product/findById/{pid}")
    public Product findById(@PathVariable Long pid);
}

 8.5 测试

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值