springcloud sentinel

简介: springcloud sentinel

资源

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

规则

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

sentinel 资源保护的实现

api 实现

引入依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.0</version>
</dependency>

yml 配置

server:
  port: 8033
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  application:
    name: sentinel-server

添加SentinelDemoController 类

package com.jiuge.study.controller;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.common.reflection.qual.GetConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
@RestController
@Slf4j
public class SentinelDemoContoller {
    private static final String RESOURCE_NAME = "hello";
    @GetMapping("/hello")
    public String hello() {
        Entry entry = null;
        try {
            // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
            entry = SphU.entry(RESOURCE_NAME);
            // 被保护的业务逻辑
            String str = "hello world";
            log.info(" ==== " + str);
            return str;
        } catch (BlockException e) {
            // 资源访问阻止,被限流或被降级
            // 进行相应的处理操作
            log.info("block!");
        } catch (Exception ex) {
            // 若需要配置降级规则,需要通过这种方式记录业务异常
            Tracer.traceEntry(ex, entry);
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
        return null;
    }
    /**
     * 定义流控规则
     */
    @PostConstruct
    @GetConstructor
    private static void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        //设置受保护的资源
        rule.setResource(RESOURCE_NAME);
        // 设置流控规则 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置受保护的资源阈值
        // Set limit QPS to 20.
        rule.setCount(1);
        rules.add(rule);
        // 加载配置好的规则
        FlowRuleManager.loadRules(rules);
    }
}

测试验证

jmeter 配置如下   100 个请求 10s 钟请求,就是1s钟10个请求, 因为这个qps 是限制了1s1个请求,看日志结果输出是达到限流。

@SentinelResource注解实现

注解用来标识资源是否被限流、降级。

blockHandler: 定义当资源内部发生了BlockException应该进入的方法(捕获的是Sentinel定义的异常)

fallback: 定义的是资源内部发生了Throwable应该进入的方法

exceptionsToIgnore:配置fallback可以忽略的异常

引入依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
    <version>1.8.0</version>
</dependency>

添加配置类 SentinelAspectConfiguration

package com.jiuge.user.config;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SentinelAspectConfiguration {
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
}

在UserController 请求上添加注解@SentinelResource

@RequestMapping(value = "/findOrderByUserId/{id}")
@SentinelResource(
        value = "findOrderByUserId", fallback = "fallback", fallbackClass = MyExceptionUtil.class, blockHandler = "handlerException", blockHandlerClass = MyExceptionUtil.class
)
public Mono<R> findOrderByUserId(@PathVariable("id") Integer id) {
    log.info("根据userId:" + id + "查询订单信息");
    String url = "http://localhost:8020/order/findOrderByUserId/" + id;
      Mono<R> result = webClient.get().uri(url).retrieve().bodyToMono(R.class);
    if(id==4){
        throw new IllegalArgumentException("非法参数异常");
    }
    return result;
}

编写异常请求工具类MyExceptionUtil

package com.jiuge.user.util;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jiuge.common.utils.R;
public class MyExceptionUtil {
    public static R fallback(Integer id, Throwable e) {
        return R.error(-2, "===被异常降级啦===");
    }
    public static R handleException(Integer id, BlockException e) {
        return R.error(-2, "===被限流啦===");
    }
}

正常参数请求

{"msg":"success","code":0,"orders":[{"id":2,"userId":"2","commodityCode":"TH3332324323444","count":2,"amount":2}]}

请求ID为4的时候, 抛出异常


流控规则可以通过 Sentinel Dashboard 配置

客户端需要引入Transport 模块与sentinel  控制台继续通信

启动Sentinel Dashboard

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

不懂的可以参考其官方文档说明

https://sentinelguard.io/zh-cn/docs/dashboard.html


sentinel 整合应用

SpringCloud 整合 Sentinel

引入依赖

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

修改application.yml 内容

spring:
  application:
    name: user-server
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: 2a57e550-6295-4269-b1b4-268c46021020
    # 不适用ribbon
    loadbalancer:
      ribbon:
        enabled: false
    sentinel:
      transport:
        # 添加sentinel的控制台地址
        dashboard: 127.0.0.1:8080
        # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
        port: 8719

在sentinel 控制台配置流控规则


请求 http://localhost:8010/user/findOrderByUserId/2验证,可以看出被流控的结果


Blocked by Sentinel (flow limiting)

RestTemplate 整合Sentinel

Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,在构造 RestTemplate bean的时候需要加上 @SentinelRestTemplate 注解。

@SentinelRestTemplate 注解的属性支持限流(blockHandler, blockHandlerClass)和降级(fallback, fallbackClass)的处理。

Sentinel RestTemplate 限流的资源规则提供两种粒度:

  • httpmethod:schema://host:port/path:协议、主机、端口和路径
  • httpmethod:schema://host:port:协议、主机和端口

引入依赖

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

自定义全局控制类

package com.jiuge.user.util;
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jiuge.common.utils.R;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
public class GlobalExceptionUtil {
    /**
     * 注意:static修饰,参数类型不能出错
     * @param request  org.springframework.http.HttpRequest
     * @param body
     * @param execution
     * @param ex
     * @return
     */
    public static SentinelClientHttpResponse handlerException(HttpRequest request,
                                                             byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
        R r = R.error(-1, "===被限流啦===");
        try {
            return new SentinelClientHttpResponse(new ObjectMapper().writeValueAsString(r));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static SentinelClientHttpResponse fallback(HttpRequest request,
                                                      byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
        R r = R.error(-2, "===被异常降级啦===");
        try {
            return new SentinelClientHttpResponse(new ObjectMapper().writeValueAsString(r));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

在RestTemplate bean 实例方法上添加注解 @SentinelRestTemplate

/**
 * @author jiuge
 */
@Configuration
public class RestConfig {
    @Bean
    @LoadBalanced
    @SentinelRestTemplate(
            blockHandler = "handleException",blockHandlerClass = GlobalExceptionUtil.class,
            fallback = "fallback",fallbackClass = GlobalExceptionUtil.class)
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

在UserController 上添加方法 findOrderByUserIdForRestTemplate

@GetMapping("/findOrderByUserIdForRestTemplate/{id}")
public R findOrderByUserIdForRestTemplate(@PathVariable("id")Integer id){
    String url = "http://order-server/order/findOrderByUserId/" + id;
    R result = restTemplate.getForObject(url, R.class);
    return result;
}

在application.yml  添加配置

#true开启sentinel对resttemplate的支持,false则关闭  默认true
resttemplate:
  sentinel:
    enabled: true

验证 请求 http://localhost:8010/user/findOrderByUserIdForRestTemplate/1,测试


达到阈值2的时候,会触发流控

Blocked by Sentinel (flow limiting)

OpenFeign 整合 Sentinel

引入依赖

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

配置文件 application.yml  打开对sentinel 的支持

feign:
  sentinel:
    enabled: true   #开启sentinel对feign的支持 默认false

修改接口 OrderFeignService,添加 fallback

package com.jiuge.user.feign;
import com.jiuge.common.utils.R;
import com.jiuge.user.feign.impl.FallbackOrderFeignServiceFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
 * @author jiuge
 * @version 1.0
 * @date 2021/8/5 10:56
 */
// feignConfig 的局部配置
@FeignClient(value = "order-server", path = "order", fallbackFactory = FallbackOrderFeignServiceFactory.class)
public interface OrderFeignService {
    @RequestMapping("/findOrderByUserId/{id}")
        // @RequestLine("GET /findOrderByUserId/{id}")
    R findOrderByUserId(@PathVariable("id") Integer id);
}

添加两个实现类 ,FallbackOrderFeignService实现  OrderFeignService

package com.jiuge.user.feign.impl;
import com.jiuge.common.utils.R;
import com.jiuge.user.feign.OrderFeignService;
import org.springframework.stereotype.Component;
@Component   //必须交给spring 管理
public class FallbackOrderFeignService implements OrderFeignService {
    @Override
    public R findOrderByUserId(Integer id) {
        return R.error(-1,"=======服务降级了========");
    }
}

FallbackOrderFeignServiceFactory 实现 FallbackFactory<OrderFeignService>

package com.jiuge.user.feign.impl;
import com.jiuge.common.utils.R;
import com.jiuge.user.feign.OrderFeignService;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
@Component
public class FallbackOrderFeignServiceFactory implements FallbackFactory<OrderFeignService> {
    @Override
    public OrderFeignService create(Throwable throwable) {
        return new OrderFeignService() {
            @Override
            public R findOrderByUserId(Integer id) {
                return R.error(-1, "===========服务降级了==========");
            }
        };
    }
}

请求地址 http://localhost:8010/user/findOrderByUserIdForOpenFeign/1测试,验证输出

{"msg":"接口限流了","code":100}

dubbo 整合sentinel

引入依赖

<!--加入sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--Sentinel 对 Dubbo的适配 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-apache-dubbo-adapter</artifactId>
</dependency>

在consumer 端和 provider 端  的application.yml 文件上 接入sentinel 配置

spring:
  cloud:
    sentinel:
      transport:
        # 添加sentinel的控制台地址
        dashboard: 127.0.0.1:8080
#暴露actuator端点   
management:
  endpoints:
    web:
      exposure:
        include: '*'

限流粒度可以是服务接口和服务方法两种粒度:

  • 服务接口:resourceName 为 接口全限定名,如com.jiuge.product.service.ProductService
  • 服务方法:resourceName 为 接口全限定名:方法签名,如 com.jiuge.product.service.impl.ProductServiceImpl.findById(Integer id)

Sentinel Dubbo  Adapter 支持配置全局的fallback 函数

Sentinel Dubbo Adapter 还支持配置全局的 fallback 函数,可以在 Dubbo 服务被限流/降级/负载保护的时候进行相应的 fallback 处理。用户只需要实现自定义的 DubboFallback 接口,并通过 DubboAdapterGlobalConfig注册即可。默认情况会直接将 BlockException 包装后抛出。同时,我们还可以配合 Dubbo 的 fallback 机制 来为降级的服务提供替代的实现。


provider  端 在 ProductServiceImpl 类上 修改添加 下面代码  两个地方  

findById 方法上添加  @SentinelResource 注解

添加方法init   注解为PostConstruct

@Override
@GetMapping("/findById/{id}")
@SentinelResource("findById")
public ProductEntity findById(@PathVariable("id") Integer id) {
    return productDao.findById(id);
}
@PostConstruct
public void init() {
    DubboAdapterGlobalConfig.setProviderFallback(
            (invoker, invocation, ex) -> AsyncRpcResult.newDefaultAsyncResult(new ProductEntity(0,"===provider fallback=="), invocation));
}

consumer 端 添加类  ProductServiceDubboMock

package com.jiuge.product.mock;
import com.product.entity.ProductEntity;
import com.product.service.ProductService;
import java.util.List;
public class ProductServiceDubboMock implements ProductService {
    @Override
    public List<ProductEntity> list() {
        return null;
    }
    @Override
    public ProductEntity findById(Integer id) {
        return new ProductEntity(0, "====mock===");
    }
}

修改ProductController 类  两个地方

在引用类ProductService类上加上注解

@DubboReference(mock = "com.jiuge.product.mock.ProductServiceDubboMock")

加入方法 init(),使用@PostConstruct

@DubboReference(mock = "com.jiuge.product.mock.ProductServiceDubboMock")
private ProductService productService;
@GetMapping("/info/{id}")
public ProductEntity info(@PathVariable("id") Integer id) {
    return productService.findById(id);
}
@PostConstruct
public void init() {
    DubboAdapterGlobalConfig.setConsumerFallback(
            (invoker, invocation, ex) -> AsyncRpcResult.newDefaultAsyncResult(
                    new ProductEntity(0,"===fallback=="), invocation));
}

配置consumer 端的流控规则

测试结果

{"id":0,"productName":"===fallback==","productType":null,"productUnit":null}

配置provider 端的流控规则

测试结果

{"id":0,"productName":"===provider fallback==","productType":null,"product

至此,完成了sentinel dubbo 简单案例整合

目录
相关文章
|
4月前
|
Java UED Sentinel
微服务守护神:Spring Cloud Sentinel,让你的系统在流量洪峰中稳如磐石!
【8月更文挑战第29天】Spring Cloud Sentinel结合了阿里巴巴Sentinel的流控、降级、熔断和热点规则等特性,为微服务架构下的应用提供了一套完整的流量控制解决方案。它能够有效应对突发流量,保护服务稳定性,避免雪崩效应,确保系统在高并发下健康运行。通过简单的配置和注解即可实现高效流量控制,适用于高并发场景、依赖服务不稳定及资源保护等多种情况,显著提升系统健壮性和用户体验。
98 1
|
6月前
|
监控 Java Sentinel
使用Sentinel进行服务调用的熔断和限流管理(SpringCloud2023实战)
Sentinel是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
167 3
|
2月前
|
负载均衡 算法 Java
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
40岁老架构师尼恩分享了关于SpringCloud核心组件的底层原理,特别是针对蚂蚁集团面试中常见的面试题进行了详细解析。内容涵盖了Nacos注册中心的AP/CP模式、Distro和Raft分布式协议、Sentinel的高可用组件、负载均衡组件的实现原理等。尼恩强调了系统化学习的重要性,推荐了《尼恩Java面试宝典PDF》等资料,帮助读者更好地准备面试,提高技术实力,最终实现“offer自由”。更多技术资料和指导,可关注公众号【技术自由圈】获取。
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
|
3月前
|
监控 Java Nacos
SpringCloud基础5——微服务保护、Sentinel
sentinel、雪崩问题、流量控制、隔离和降级、授权规则、规则持久化
SpringCloud基础5——微服务保护、Sentinel
|
5月前
|
监控 Java 应用服务中间件
SpringCloud面试之流量控制组件Sentinel详解
SpringCloud面试之流量控制组件Sentinel详解
247 0
|
5月前
|
监控 Dubbo 应用服务中间件
通用快照方案问题之Sentinel与SpringCloud和Dubbo的整合如何解决
通用快照方案问题之Sentinel与SpringCloud和Dubbo的整合如何解决
52 0
|
6月前
|
Java 开发者 Sentinel
Spring Cloud系列——使用Sentinel进行微服务保护
Spring Cloud系列——使用Sentinel进行微服务保护
76 5
|
6月前
|
监控 Java API
深入解析 Spring Cloud Sentinel:分布式系统流量控制与熔断降级的全面指南
深入解析 Spring Cloud Sentinel:分布式系统流量控制与熔断降级的全面指南
147 0
深入解析 Spring Cloud Sentinel:分布式系统流量控制与熔断降级的全面指南
|
6月前
|
自然语言处理 监控 开发者
springCloud之Sentinel流量路由、流量控制、流量整形、熔断降级
springCloud之Sentinel流量路由、流量控制、流量整形、熔断降级
144 0
|
7月前
|
监控 Java Sentinel
Spring Cloud Sentinel:概念与实战应用
【4月更文挑战第28天】在分布式微服务架构中,确保系统的稳定性和可靠性至关重要。Spring Cloud Sentinel 为微服务提供流量控制、熔断降级和系统负载保护,有效预防服务雪崩。本篇博客深入探讨 Spring Cloud Sentinel 的核心概念,并通过实际案例展示其在项目中的应用。
112 0