spring-alibaba-sentinel具体配置使用

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

Sentinel下载

首先我们自然要下载sentinel
2020年9月25日目前的最新版本是1.8.0
下载地址:https://github.com/alibaba/Sentinel

启动事项

而sentinel启动的默认端口8080,这和Tomcat的端口重合,所以当端口重合的时候启动就会报错,
我们要修改Sentinel的启动端口
使用下面这段代码来进行启动

java -Dserver.port=8858 -jar sentinel-dashboard-1.8.0.jar

这样就把启动的端口改为8858而不会和Tomcat的8080重合报错
在这里插入图片描述

运行界面

cmd运行成功后我们打开浏览器,输入localhost:8858进入到下面页面就是运行成功
在这里插入图片描述
账户密码初始都是sentinel
在这里插入图片描述
一开始应该是一片空白,我这里是已经运行过的。
那么我们先来配置一个服务端来登录sentinel来进行调试

配置服务端

pom

        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.qwf</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

这里有些配置后续会用到,我先导入,spring-cloud-starter-openfeignsentinel-datasource-nacos暂时用不到,后面我再慢慢讲

application.yml

server:
  port: 8401
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8858
        port: 8719
management:
  endpoints:
    web:
      exposure:
        include: "*"

这里的spring.cloud.nacos.discovery.server-addr是链接到nacos的路径
下面的spring.cloud.sentinel.transport.dashboard是链接的sentinel的路径,

port是在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收Http Server 再将规则注册到 Sentinel 中
默认这个server端口是从8719开始,如果被占就+1从8720一直到找到空闲的端口为止。

management.endpoints.web.exposure.include是把包含的节点全部暴露给监控

main方法

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

下面我们先写两个方法来测试
FlowLimitController

@RestController
@Slf4j
public class FlowLimitController {
    @GetMapping(value = "/testA")
    public String getTestA(){
        log.info(Thread.currentThread().getName()+"\t"+"........textA");
        return "************TestA";
    }
    
    @GetMapping(value = "/testB")
    public String getTestB(){
        return "************TestB";
    }

简单的配置完成,我们运行查看

运行调试

在这里插入图片描述
发现可以直接通过
接下来我们观察Sentinel发生了什么变化
在这里插入图片描述
原本空白的界面出现了我们配置的服务,sentinel是服务运行通过之后才会获取服务信息。
我们再来看一下服务监控,点击簇点链路
在这里插入图片描述
可以发现我们刚刚点的路径名testA,而上面的context是服务一步步获取的路径。
我们先点击流控
在这里插入图片描述
在这里开始解释:
针对来源是特指对调用这个服务的人进行流控,default是指没有
阈值类型QPS是每秒钟请求的次数,线程数是指电脑处理对testA的请求的线程数,
是否集群不用解释

流控模式

直接:就是直接对testA资源进行流控,
关联:比如说链接testB,单机阈值为1,textB每秒访问量超过1了,textA就不能用了,就像支付系统 要瘫痪了,下订单接口就先不能用,缓解支付系统压力。
链路:我们访问testA不是直接访问,是先访问sentinel_web_servlet_context再访问testA,可是sentinel_web_servlet_context当中还有其他方法,当这个服务的访问其他方法过多比如访问testB服务过多,为了缓解压力就不让testA访问了,把资源都给其他方法。

说了这么多不如来动手看一下
第一种:QPS直接快速失败,阈值为1
在这里插入图片描述
在我们连续点击刷新testA后
在这里插入图片描述
sentinel发现一秒访问数超过一次,在这一秒内访问都被拒绝

第二种:QPS直接warm up,阈值为3,预热时长为3
在这里插入图片描述
预热时长是指一开始点击并不是到了阈值才流控,而是阈值除以预热时长然后均匀上升直到阈值,这样防止平常无人访问突然来了很大量的访问,系统承受不住直接崩溃,一开始不让你达到阈值慢慢放开,可以防止系统崩溃。

第三种::QPS直接排队,阈值为1,超时时间为20秒
在这里插入图片描述
如果短时间内大量的请求进来,我就一秒钟处理一个一秒钟处理一个,等待超过20秒的请求就报超时错误。
下面我用postman连续300毫秒请求30次,观察后台的日志消息时间。
在这里插入图片描述
在这里插入图片描述
可以观察到一秒钟后台信息出现一次,说明后台一秒钟只处理一次信息

第四种::QPS关联快速,阈值为1
在这里插入图片描述
我们用postman用200ms调用testB40次,调用期间我们来调用testA。
在这里插入图片描述

在这里插入图片描述

可以看到testA运行失败已经被限流

第五种::QPS链路快速,阈值为1
在这里插入图片描述
此时我们对testB做相同操作
得出和上面相同的结果,但是过程不同,上方是对testB控制,这个是对入口限制。

降级

降级有三种模式
在这里插入图片描述
慢调用比例:指在一秒内发生的最小请求数(默认是5)当中的RT(请求响应的最久时间)是否超出设定阈值并且超过了全部请求的设定比例。就会熔断。
比如说如下图
在这里插入图片描述
这个图的意思是当我我一秒钟的请求大于等于5个,而且其中有一半以上的请求数的响应时间都大于200毫秒,我就停止访问5秒。

我们修改一下testA方法,使响应时间大于200毫秒

    @GetMapping(value = "/testA")
    public String getTestA(){
        try {
            TimeUnit.MILLISECONDS.sleep(800);

        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
        log.info(Thread.currentThread().getName()+"\t"+"........textA");
        return "************TestA";

    }

修改之后可以看到运行5次之后TestA开始报错误信息,因为每次响应都超过200毫秒
在这里插入图片描述
异常比例就是一秒钟报错的占全部的百分之多少就熔断。
异常数是以分钟计算,超过就熔断。

热点

为了测试热点我们先创建一个getHotKey方法,可以传入p1和p2两个字符串参数而且不用必须要传。
这里热点限流会直接报500,我们使用@SentinelResource来做服务降级

@SentinelResource很像@HystrixCommand
当发生错误时选择一个方法来作为服务降级
但是发生的Sentinel配置错误使用的是blockHandler ,不要选错。
方法运行报错使用的是fallback。而使用热点必须配置@SentinelResource。否则无法使用。
这里热点限流明显是sentinel配置错误,使用blockHandler 。

    @GetMapping(value = "/hotkey")
    @SentinelResource(value = "hotkey",blockHandler = "hotkey_Fallback")
    public String getHotKey(@RequestParam(value = "p1",required = false) String p1,
                           @RequestParam(value = "p2",required = false) String p2){
        return "************hotkey";
    }
    
    public String hotkey_Fallback(String p1, String p2, BlockException exception){
        return "************hotkey_Fallback,o(╥﹏╥)o";
    }

在这里插入图片描述
热点是只能用QPS模式,参数索引是指你传入的第几个参数,从0开始,比如说getHotKey的p1参数就是0,p2就是1。
阈值和时长就不解释了。
我们设定hotkey的热点,设定p1一秒钟只能调用一次
在这里插入图片描述
当我们不传p1时可以快速刷新而hotkey不会限流
在这里插入图片描述
而传入p1参数后刷新2次就被限流了
在这里插入图片描述

@SentinelResource讲解

首先我们创建一个新的controller来查看@SentinelResource的配置

    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "byResource_Fallback")
    public ConmonResult byResource(){
        return new ConmonResult(200,"按资源名称限流测试",new Payment(2020L,"serial0001"));
    }
    
    public ConmonResult byResource_Fallback(BlockException e){
        return new ConmonResult(444,e.getClass().getCanonicalName()+"\t"+"服务不可用");
    }

@SentinelResource当中的value为sentinel当中看到的资源名,可以随意命名,但为了规范最好和方法名或者路径名相同。

blockHandler 是指当发生限流时,该使用那个服务降级方法。默认的就是sentinel limited
我们可以测试一下发生降级时调用了哪个方法名
在这里插入图片描述
在这里插入图片描述
发生降级会调用com.alibaba.csp.sentinel.slots.block.flow.FlowException这个方法来进行服务降级

sentinel配置持久化

但是会发现一个问题,当我们重启服务时,我这边的服务是8401
在这里插入图片描述
我们再看一下sentinel
在这里插入图片描述
可以看到我们之前配置的流控,热点,降级方法都没有了。如果这样每次我们更新都要重新配置一次。那是多么大而且麻烦的工作。

我们可以在application.yml中修改spring,在里面修改成下面这段代码

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8858
        port: 8719
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

我们链接到nacos,创建下面这个配置cloudalibaba-sentinel-service,名称就是spring.cloud.sentinel.datasource.ds1.nacos.dataId的内容,格式为json在这里插入图片描述
resource是资源名
limitApp是来源应用
grade是阈值类型,0是线程,1是QPS
count是阈值
strategy是流控模式,0是直接,1是关联,2是链接
controlBehavior是流控效果,0是直接,1是warm up,2是排队
clusterMode是集群模式
这样就配置成功每次运行时都会使byGlobalRescource按照QPS快速直接,阈值为1非集群环境下限流,实现了持久化。

全局服务降级方法

但是@ServiceResource每次都要编写一个服务降级方法,既增加了代码量,耦合还更高了。自然可以写一个方法全局调用
我们写一个全局服务降级方法的handler

public class ConsumerBlockHandler {
    public static ConmonResult handlerException1(BlockException e){
        return new ConmonResult(4444,"handlerException1的fallback");
    }
    public static ConmonResult handlerException2(BlockException e){
        return new ConmonResult(4444,"handlerException2的fallback");
    }
}

再在controller中添加一个应用全局配置的方法

    @GetMapping("/byGlobalResource")
    @SentinelResource(value = "byGlobalResource",blockHandlerClass=
    ConsumerBlockHandler.class,blockHandler = "handlerException1")
    public ConmonResult byGlobalResource(){
        return new ConmonResult(200,"按资源名称限流测试",new Payment(2020L,"serial0001"));
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
可以看到调用服务降级方法成功,这样减少了代码量还减少了耦合,看起来舒服了很多。

我们再来修改一下byGlobalResource()方法

    @GetMapping("/byGlobalResource")
    @SentinelResource(value = "byGlobalResource",blockHandlerClass=
    ConsumerBlockHandler.class,blockHandler = "handlerException1",fallback="byGlobalResourceFallback" )
    public ConmonResult byGlobalResource(){
        Integer a=10/0;
        return new ConmonResult(200,"按资源名称限流测试",new Payment(2020L,"serial0001"));
    }
    
    public ConmonResult byGlobalResourceFallback(){
        return new ConmonResult(445,"运行错误,调用byGlobalResourceFallback",new Payment(2020L,"error"));
    }

当blockHandler 和fallback同时存在时,会调用哪一个呢
我们设置了一个除0错误。运行时出现
在这里插入图片描述
发现了是调用fallback当中的服务降级方法,但是如果我们也设置限流然后多运行几次会发生什么呢?
在这里插入图片描述
发现一开始几次是fallback错误,后面限流开始调用blockHandler 错误。由此我们也明白了sentinel的优先级。

sentinel和openfeign结合

首先我们要在父工程pom中的依赖最上方添加

      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-openfeign-dependencies</artifactId>
        <version>2.2.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

用最新的openfeign会报错

看了一下代码,问题的表现是从Sentinel抛出,本质是由于feign核心接口方法命名纠正拼写错误导致

Hoxton.SR7 中,fegin.context接口方法的定义为parseAndValidateMetadata

很明显是为了纠正拼写错误。我们先降低openfeign版本到2.2.0.RELEASE

我们先创建一个服务端

pom

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.qwf</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--基础配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

application.yml

server:
  port: 9001
spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8858
        port: 8719
management:
  endpoints:
    web:
      exposure:
        include: "*"

main

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

controller

@RestController
public class VirtualDatabaseController {
    @Value("${server.port}")
    private String port;

    public static HashMap<Long, Payment> hashMap=new HashMap<>();
    static {
        hashMap.put(1L,new Payment(1L,"6eb391a3-345f-43e5-a940-d2ca5001e589"));
        hashMap.put(2L,new Payment(2L,"63cf224d-79af-41a7-b0c6-3a992da6dd46"));
        hashMap.put(3L,new Payment(3L,"f5d8d70b-f15f-47fd-9251-b809939955e5"));
    }
    @GetMapping("/paymentSQL/{id}")
    public ConmonResult<Payment> paymentSQL(@PathVariable(value = "id") Long id){
        Payment payment=hashMap.get(id);
        ConmonResult<Payment> result=new ConmonResult(200,"from mysql, porr="+port,payment);
        return result;
    }
}

用户端

pom

    <dependencies>
        <!--SpringCloud openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.qwf</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

application.yml

server:
  port: 84
spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8858
        port: 8719
service-url:
  nacos-user-service: http://nacos-payment-provider
feign:
  sentinel:
    enabled: true

相比于服务端多了一个feign.sentinel.enabled=true
main方法

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

service接口

@Component("PaymentService")
@FeignClient(value = "nacos-payment-provider",fallback = PaymentServiceImpl.class)
public interface PaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")
    public ConmonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}

service当中使用了@FeignClient,其中value是链接服务的服务名,fallback是发生服务降级调用方法的类名
PaymentServiceImpl

@Component
public class PaymentServiceImpl implements PaymentService {
    @Override
    public ConmonResult<Payment> paymentSQL(Long id) {
        return new ConmonResult<>(44444,"发生服务降级,--PaymentFallbackService",new Payment(id,"errorSerial"));
    }
}

controller

    @Resource
    private PaymentService paymentService;

    @GetMapping("/consumer/openFeign/paymentSQL/{id}")
    public ConmonResult<Payment> paymentSQL(@PathVariable(value = "id") Long id){
        ConmonResult<Payment> result= paymentService.paymentSQL(id);
        if(id==4){
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
        }
        else if(result.getData()==null){
            throw new NullPointerException("空指针异常");
        }
        return result;

    }
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
spring-cloud-starter-alibaba-sentinel是一款用于微服务架构中实现流量控制、熔断降级、系统负载保护等功能的API库。 首先,它可以实现流量控制,通过设置限流规则,对微服务进行限制,避免大量请求进入服务,导致服务不可用或资源耗尽。可以设置QPS、线程数、并发数等限制条件,对请求进行控制,保障系统的稳定性。 其次,它还支持熔断降级功能。当微服务出现异常或超时时,它会根据预设的熔断规则,将服务降级,避免故障的扩散。可以通过设置异常比例、异常数等规则,对服务进行自动降级,保障系统的可用性。 另外,它还支持系统负载保护功能。通过设置系统负载的阈值,当系统负载超过一定限制时,它会自动出发保护机制,拒绝服务请求,保护系统免受过载的影响。可以设置CPU使用率、内存使用率等指标来判断系统负载情况,保持系统的稳定运行。 此外,spring-cloud-starter-alibaba-sentinel还提供了实时监控、统计和报警功能,可以通过可视化的控制台查看服务的运行状态和性能指标,及时发现问题并进行相应的调整和优化。 总之,spring-cloud-starter-alibaba-sentinel是一款功能强大的API库,可以帮助开发人员在微服务架构中实现流量控制、熔断降级、系统负载保护等功能,确保系统的稳定性和可用性。它可以有效地保护系统不受高流量、异常情况和系统负载的影响,提高系统的弹性和可扩展性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值