5-SpringCloudAlibaba整合Sentinel

Sentinel是阿里巴巴开源的一款面向分布式系统的实时流量控制、熔断降级框架。它可以帮助开发人员在微服务架构中更好地管理服务的流量,防止因为流量激增而导致系统崩溃,提供了更好的服务保障和稳定性。
Sentinel的主要功能和作用包括:
流量控制: Sentinel可以对服务的入口流量进行实时监控和控制,通过设定阈值和规则,可以限制每个服务的请求流量,防止服务因为过载而导致性能下降或崩溃。
熔断降级: Sentinel可以根据服务的实际情况,自动开启熔断降级策略。当服务出现异常或故障时,Sentinel会及时地关闭该服务的访问,避免故障扩散,保护整个系统的稳定性。
实时监控: Sentinel提供实时的监控功能,可以查看各个服务的流量、成功率、响应时间等关键指标,帮助开发人员及时发现问题并进行处理。
规则配置: Sentinel支持动态的规则配置,可以在运行时实时修改流量控制和熔断降级的规则,方便快速适应业务场景的变化。
统计报表: Sentinel可以生成详细的统计报表,帮助开发人员了解服务的运行情况,发现潜在的性能瓶颈和问题。
总的来说,Sentinel提供了一套完善的流量控制、熔断降级和实时监控机制,帮助开发人员更好地保障分布式系统的稳定性和可靠性。它在微服务架构中起到了非常重要的作用,尤其在高并发、复杂业务场景下,Sentinel能够保护服务免受过载和故障的影响,提供更好的用户体验。

sentinel有两种配置方式,一种是在代码里面配置,这个代码入侵性太强,一般不建议这么用,所以这里不讲,有兴趣的自己了解下
我这里只演示控制台的方式来实现流量控制和熔断降级等

首先我们需要部署一套控制台服务,这个可以去https://github.com/alibaba/Sentinel/releases下载,注意下载版本要和springcloud版本一致

在这里插入图片描述

我们先在/usr/local下面建一个文件夹sentinel,然后把jar包传上去

在这里插入图片描述

然后通过下面这个命令启动(-jar后面接自己的jar包信息,端口号可以改)
建议设置成开机自启动,还有nacos和mysql这些也是,都设置成开机自动启动,不懂的自己搜一下很简单

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

开启端口

firewall-cmd --add-port=9100/tcp --permanent

firewall-cmd --reload

启动成功后我们在浏览器输入http://192.168.43.128:9100就可以看到下面这页面了(注意9100是我自己配置的端口号)

在这里插入图片描述

这里我们给它配置一下开机启动脚本
在sentinel目录下我们创建一个启动脚本

touch startup.sh

把下面的内容放进去,记得路径jar包名称什么的换成自己的

#!/bin/sh

nohup java -Dlogging.file=/usr/local/sentinel/logs/sentinel-dashboard.log -Dserver.port=9100 -Dcsp.sentinel.dashboard.server=localhost:9100 -Dproject.name=sentinel-dashboard -jar /usr/local/sentinel/sentinel-dashboard-1.8.6.jar > /usr/local/sentinel/logs/run.out 2>&1 &
echo $! > /usr/local/sentinel/pid/runing.pid

还需要一个关闭的脚本

touch shutdown.sh

顺便在sentinel目录下加两个文件夹,下面要用到

mkdir pid

mkdir logs
D=$(cat /usr/local/sentinel-1.8/pid/runing.pid)
kill -9 $PID
find /usr/local/sentinel/pid -name "*.pid" -exec rm -rf {} \;
find /usr/local/sentinel/logs -name "*.out" -exec rm -rf {} \;

我们再去添加开机脚本

cd /lib/systemd/system

touch sentinel.service
[Unit]
Description=sentinel
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/sentinel/startup.sh
ExecStop=/usr/local/sentinel/shutdown.sh
PrivateTmp=true

[Install]
WantedBy=multi-user.target

赋予权限添加开机自启

chmod 754 /lib/systemd/system/sentinel.service

chmod +x /usr/local/sentinel/startup.sh

chmod +x /usr/local/sentinel/shutdown.sh

systemctl daemon-reload

systemctl enable sentinel.service

然后我们在order服务里面集成sentinel
首先还是在pom文件里面加入依赖,直接覆盖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.sakura.springcloud</groupId>
        <artifactId>springcloudalibaba</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>order</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- nacos服务注册发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- nacos配置中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!-- 新版本已不再默认开启bootstrap -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>


        <!-- loadbalancer启动器 新版本的springcloud去掉了ribbon自带的负载均衡器 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

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

        <!-- sentinel启动器 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

    </dependencies>
</project>

然后在application.yml文件里面加上服务地址

server:
  port: 8010

logging:
  level:
    com.sakura.order.feign: debug # 这里我们可以单独配置feign的日志级别

spring:
  profiles:
    active: dev
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.43.128:9100

feign:
  client:
    config:
      product-service:
        logger-level: basic
        connect-timeout: 5000 # 连接超时时间,默认2s
        read-timeout: 6000 #请求处理超时时间,默认5s
        request-interceptors:
          - com.sakura.order.interceptor.feign.CustomFeignInterceptor # 开启自定义拦截器

直接启动服务,然后我们在浏览器里面多调几次http://localhost:8010/order/add
刷新一下sentinel控制台,就可以在实时监控里面看到刚才的请求了

在这里插入图片描述

我再在OrderController里面加个get方法

package com.sakura.order.controller;

import com.sakura.order.feign.ProductFeignService;
import com.sakura.order.feign.StockFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Sakura
 * @date 2023/7/19 11:25
 */
@RestController
@RequestMapping("/order")
@RefreshScope
public class OrderController {

    @Autowired
    StockFeignService stockFeignService;
    @Autowired
    ProductFeignService productFeignService;

    @Value("${user.name}")
    private String userName;

    @Value("${user.age}")
    private String userAge;

    @Value("${user.sex}")
    private String userSex;

    @RequestMapping("/add")
    public String add(){
        System.out.println("下单成功");
        String msg = stockFeignService.reduct();
        String productMsg = productFeignService.get(1);
        return userName + userAge + userSex +  "下单成功" + msg + "-" + productMsg;
    }

    @RequestMapping("/get")
    public String get(){
        return "获取订单成功";
    }

}

同样的在浏览器里面请求几次http://localhost:8010/order/get,再去sentinel控制台看一下
可以看到里面有两个接口了

在这里插入图片描述

接下来就是流控了
我们在簇点链路里面选择order/get这个接口点击操作里面的流控

在这里插入图片描述

可以看到默认是根据QPS(每秒请求数量)来的,我们在单机阈值里面填上2,也就是每秒超过2次就会流控
直接点新增(其它模式和效果大家自己研究一下)

在这里插入图片描述

然后我们在浏览器里面请求http://localhost:8010/order/get,手速要快一秒三连即可,手速慢的建议用压测工具
下面这个就是被流控了

在这里插入图片描述
上面那个是默认的流控效果,我们也可以自定义流控效果
我们在里面加上getBlockHandler方法来处理流控效果

package com.sakura.order.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.sakura.order.feign.ProductFeignService;
import com.sakura.order.feign.StockFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Sakura
 * @date 2023/7/19 11:25
 */
@RestController
@RequestMapping("/order")
@RefreshScope
public class OrderController {

    @Autowired
    StockFeignService stockFeignService;
    @Autowired
    ProductFeignService productFeignService;

    @Value("${user.name}")
    private String userName;

    @Value("${user.age}")
    private String userAge;

    @Value("${user.sex}")
    private String userSex;

    @RequestMapping("/add")
    public String add(){
        System.out.println("下单成功");
        String msg = stockFeignService.reduct();
        String productMsg = productFeignService.get(1);
        return userName + userAge + userSex +  "下单成功" + msg + "-" + productMsg;
    }

    @RequestMapping("/get")
    @SentinelResource(value = "get", blockHandler = "getBlockHandler")
    public String get(){
        return "获取订单成功";
    }

    // 流控方法必须和原方法类型一致参数一致
    // 一定要加上BlockException
    public String getBlockHandler(BlockException blockException){
        // 我们可以在这个方法里面处理流控后的业务逻辑
        return "get接口被流控";
    }

}

重启order服务,注意因为sentinel没有做持久化处理,所以重启服务之前的配置会丢失(怎么持久化大家自己研究一下),我们需要重新请求一下http://localhost:8010/order/get
我们再看一下sentinel控制台会发现有两个get接口,一个是order/get,还有一个get,而我们要使用刚才配置的流控效果就需要给get接口配置流控规则

在这里插入图片描述
在这里插入图片描述

我们检查一下流控规则那里,如果order/get还在就删掉,不然下面那个不会生效

在这里插入图片描述

删掉order/get的流控规则后我们再快速请求http://localhost:8010/order/get三次,就可以看到自定义的效果了

在这里插入图片描述
当然要是觉得一个个的配置这个很麻烦我们还有全局的异常处理
我们加一个MyBlockExceptionHandler用来处理全局异常

package com.sakura.order.exception;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Sakura
 * @date 2023/7/27 16:07
 */
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {

    Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        log.info("MyBlockExceptionHandler ---------------" + e.getRule());

        // 处理返回参数
        JSONObject json = new JSONObject();
        json.put("code", 500);

        if (e instanceof FlowException) {
            log.info("接口限流+++++++++++++++++++");
            json.put("msg", "接口限流");
        } else if (e instanceof DegradeException) {
            log.info("服务降级+++++++++++++++++++");
            json.put("msg", "服务降级");
        } else if (e instanceof ParamFlowException) {
            log.info("热点参数限流+++++++++++++++++++");
            json.put("msg", "热点参数限流");
        } else if (e instanceof SystemBlockException) {
            log.info("触发系统保护规则+++++++++++++++++++");
            json.put("msg", "触发系统保护规则");
        } else if (e instanceof AuthorityException) {
            log.info("授权规则不通过+++++++++++++++++++");
            json.put("msg", "授权规则不通过");
        } else {
            log.info("未知异常+++++++++++++++++++");
            json.put("msg", "未知异常");
        }

        httpServletResponse.setStatus(500);
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        new ObjectMapper().writeValue(httpServletResponse.getWriter(), json);
    }
}

重启下服务,因为没有做持久化我们再请求一下http://localhost:8010/order/add
我们去sentinel控制台给order/add接口添加流控规则

在这里插入图片描述
在这里插入图片描述

然后我们继续快速请求http://localhost:8010/order/add
可以看到返回的是全局的异常处理了

在这里插入图片描述

我们再去请求http://localhost:8010/order/get
可以看到之前配置的自定义流控效果依然还在

在这里插入图片描述

流控规则就讲到这里了,其它的一些流控模式和流控效果大家自己了解一下就好

在这里插入图片描述

接下来我们来试一下熔断降级规则
我们先在OrderController里面加一个测试方法flow

package com.sakura.order.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.sakura.order.feign.ProductFeignService;
import com.sakura.order.feign.StockFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Sakura
 * @date 2023/7/19 11:25
 */
@RestController
@RequestMapping("/order")
@RefreshScope
public class OrderController {

    @Autowired
    StockFeignService stockFeignService;
    @Autowired
    ProductFeignService productFeignService;

    @Value("${user.name}")
    private String userName;

    @Value("${user.age}")
    private String userAge;

    @Value("${user.sex}")
    private String userSex;

    @RequestMapping("/add")
    public String add(){
        System.out.println("下单成功");
        String msg = stockFeignService.reduct();
        String productMsg = productFeignService.get(1);
        return userName + userAge + userSex +  "下单成功" + msg + "-" + productMsg;
    }

    @RequestMapping("/get")
    @SentinelResource(value = "get", blockHandler = "getBlockHandler")
    public String get(){
        return "获取订单成功";
    }

    // 流控方法必须和原方法类型一致参数一致
    // 一定要加上BlockException
    public String getBlockHandler(BlockException blockException){
        // 我们可以在这个方法里面处理流控后的业务逻辑
        return "get接口被流控";
    }

    @RequestMapping("/flow")
    public String flow() throws Exception {
        Thread.sleep(3000);
        return "正常访问";
    }

}

重启一下服务,然后先请求一下http://localhost:8010/order/flow
接着我们去sentinel控制台给order/flow配置熔断规则

在这里插入图片描述
在这里插入图片描述

然后我们再快速请求几次http://localhost:8010/order/flow
可以看到已经降级了,这里走的都是刚才全局异常配置的,你也可以和流控一样配置自定义的降级规则,这个自己研究一下这里不讲
注意上面配置的那个熔断时长,一旦出现这个降级,那么在这一段时间内所有的请求都会提示服务降级,直到这个时间过去了接口又会恢复的

在这里插入图片描述

好了,熔断降级规则就讲到这里,其它的熔断策略大家自己研究一下

在这里插入图片描述

最后我们来看下怎么在openfeign中来实现降级

首先我们需要在openfeign中开启sentinel
直接覆盖order服务的application.yml文件

server:
  port: 8010

logging:
  level:
    com.sakura.order.feign: debug # 这里我们可以单独配置feign的日志级别

spring:
  profiles:
    active: dev
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.43.128:9100

feign:
  sentinel:
    enabled: true
  client:
    config:
      product-service:
        logger-level: basic
        connect-timeout: 5000 # 连接超时时间,默认2s
        read-timeout: 6000 #请求处理超时时间,默认5s
        request-interceptors:
          - com.sakura.order.interceptor.feign.CustomFeignInterceptor # 开启自定义拦截器

然后我们在order服务feign里面加一个StockFeignServiceFallback类实现StockFeignService接口

package com.sakura.order.feign;

import org.springframework.stereotype.Component;

/**
 * @author Sakura
 * @date 2023/7/27 17:30
 */
@Component
public class StockFeignServiceFallback implements StockFeignService {

    @Override
    public String reduct() {
        // 我们可以在这里处理降级逻辑,比如记录日志或者发短信提示管理用户等
        return "stock服务异常降级";
    }
}

我们在StockFeignService加上fallback

package com.sakura.order.feign;

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

/**
 * @description: stock服务接口
 * @author: Sakura
 * @date: 2023/7/20 14:38
 */
@FeignClient(name = "stock-service", path = "/stock", fallback = StockFeignServiceFallback.class)
public interface StockFeignService {

    @RequestMapping("/reduct")
    public String reduct();
}

我们改一下stock服务StockController里面的reduct方法,让它报异常

package com.sakura.stock.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Sakura
 * @date 2023/7/19 11:35
 */
@RestController
@RequestMapping("/stock")
public class StockController {

    @Value("${server.port}")
    String port;

    @RequestMapping("/reduct")
    public String reduct(){
        int a = 1/0;
        System.out.println("扣减库存");
        return "扣减库存" + port;
    }

}

我们请求一下http://localhost:8010/order/add
可以看到已经走了降级方法,但是因为没有抛异常所以接口还是能正常使用,不会影响整个服务

在这里插入图片描述

好了,整合sentinel就讲到这里,需要代码的自取(https://github.com/PX1206/SpringCloudAlibaba)

移步到下一章 6-SpringCloudAlibaba整合Seata

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子非衣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值