深入理解Sentinel系列-1.初识Sentinel

  • 👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家
  • 📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理
  • 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
  • 🍂博主正在努力完成2023计划中:源码溯源,一探究竟
  • 📝联系方式:nhs19990716,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬👀 我们引入中间件是为了解决我们应用场景中的某些特定问题 对于后端来说,我们需要提供一些接口去进行交互,比如登陆注册,支付下单等这样的一些功能,所以我们需要搭建一个整体的架构,早期的话可能没那么复杂,就是通过ssm框架组成的架构,然后通过部署tomcat来提供一个端口,随着整个并发量上去之后,我们需要去提供高性能的服务。

当我们的客户端,用户量的访问大了之后,对于后端系统的并发量会更高,并发量越高对于后端整个处理的能力就是一个挑战,因为我们需要保证,用户从10个到10000个的时候,我们需要提供给用户的是 它的响应时间不能超过多少。因为用户的操作是存在一个心理预期的,这就是所谓的用户体验。其次就是系统是否能够支撑这么大的量,是否会挂掉,挂掉之后网站无法提供对外服务的情况下,你无法产生商业价值。

比如说双十一零点的时候,那一瞬间瞬时的流量一定会大于正常时间的吞吐量,所以需要采用一定的机制来限流

限流的作用

  • 保护系统避免被瞬时流量冲垮
  • 预防恶意请求(如果自己公司不提供安全的话,可以去买高防的服务器)

  • 针对请求进行限制

服务器能支撑的连接数是多少

接口的处理能力(QPS/TPS),可以使用Jmeter来测试平均响应时间

资源限制(cpu(线程池)、内存、网络资源)


  • 如何控制流量

限流的指标(可以容纳的流量、已经容纳的流量、可以接受的流量) 阈值(基于这个指标)

限流的过程(通过算法来实现)

限流的结果(处理策略)

限流的算法

计数器

(Zookeeper:RequestThrottle 限流阀)、线程池大小、连接数大小

滑动窗口

实际上发送方和接收方都维护了一个滑动窗口

当发送端发送了一个数据包,等到接收端接收到后,接收端窗口开始滑动,发送端需要等待返回后才能滑动

其限流的核心就是流量只能在这个窗口里面,但是在tcp里面,其窗口是可以灵活的扩大的,其会根据当前网络拥挤的程度来决定窗口大小。

最大只能发送五个(阈值),超过了就不能发送了

所以说io通信是一个阻塞通信其实就是这样,基于数据包处理的结果,等到这个数据返回,如果数据一直不返回,那么这个时候请求是阻塞的。

漏桶

(用来控制传输速率的)本质上控制的是发送者的速度

流入水滴的速率代表的是请求,而滴出水滴的速度代表是处理的请求,不管来的请求有多少,但是能够处理的请求就这么多。

漏桶算法的特点:

  • 水的流出速度是固定的
  • 桶的大小也是固定的

令牌桶

其恒定的生成速率决定了并发数,假如说我每秒生成10个令牌,那么我的qps 就是 10

令牌桶对比漏桶的区别是,其能够处理瞬时突发流量,而不像漏桶一样,流出的速度是固定的。

令牌桶的设计:

  • 桶的大小

  • 令牌标记

  • 定时任务生成令牌

  • 提供令牌获取的接口

限流的实现

Semphore 信号量

分布式限流

其大小怎么计算呢?通过压测来进行计算

java 复制代码
//单机实现
//令牌桶算法
    RateLimiter rateLimiter=RateLimiter.create(10); //TPS=10

    public void doRequest(){
        if(rateLimiter.tryAcquire()){ //获取令牌
            System.out.println("success");
        }else{
            System.out.println("failed");
        }
    }
// 令牌桶不需要释放,处理完后自动丢弃

Sentinel

Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。

其中对于Sentinel最重要的两个东西:

  • 资源(需要被保护的东西)
  • 规则(限流的规则/熔断规则)

所有的流量经过这个组件后,会根据这个规则去控制这个流量来进行处理。

而熔断是一个这样的概念:

上图存在很多相互调用的情况,里面存在很多服务调用的链路,当Service D出现故障,会导致G F阻塞,间接的又会导致A B阻塞,如果特别多的请求阻塞在这里之后,会占用特别多的资源,内存、服务器、cpu的资源,这时候会导致服务器因为大量的资源被占用而导致其他问题。

当出现这种情况的时候,会触发一种熔断的方式,熔断以后会触发降级。

服务熔断

Sentinel的服务熔断有两种方式:基于响应时间的熔断和基于异常比率的熔断。基于响应时间的熔断是根据服务的响应时间来判断是否需要熔断,当服务的响应时间超过设定的阈值时,触发熔断。基于异常比率的熔断是根据服务的异常比率来判断是否需要熔断,当服务的异常比率超过设定的阈值时,触发熔断。这两种方式可以根据具体的业务场景和需求来选择使用。

demo

java 复制代码
public static void main(String[] arg) {
        initFlowRule(); //初始化限流规则
        while(true){
            //ResourceName表示资源,控制访问流量的点
            /*try(Entry entry=SphU.entry("helloWorld")){
                System.out.println("hello world");
            }catch (BlockException e){
                System.out.println("被拒绝");
            }*/
            if (SphO.entry("helloWorld")) {
                System.out.println("Hello World");
                SphO.exit();// 释放
            }
        }
    }
    private static void initFlowRule(){
        List<FlowRule> rules=new ArrayList<>();
        FlowRule flowRule=new FlowRule();
        flowRule.setResource("helloWorld"); //针对那个资源设置规则
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);//QPS或者并发数
        flowRule.setCount(5); //QPS=5
        rules.add(flowRule);
        FlowRuleManager.loadRules(rules);
    }

Demo 运行之后,我们可以在日志 ~/logs/csp/${appName}-metrics.log.xxx 里看到下面的输出:`

sql 复制代码
-timestamp- -date time - -resource- 5表示, 通过的请求, block: 被拒绝的请
求 ,
1600608724000|2023-09-20 21:32:04|helloWorld|5|6078|5|0|5|0|0|0
1600608725000|2023-09-20 21:32:05|helloWorld|5|32105|5|0|0|0|0|0
1600608726000|2023-09-20 21:32:06|helloWorld|5|41084|5|0|0|0|0|0
1600608727000|2023-09-20 21:32:07|helloWorld|5|72211|5|0|0|0|0|0
1600608728000|2023-09-20 21:32:08|helloWorld|5|60828|5|0|0|0|0|0
1600608729000|2023-09-20 21:32:09|helloWorld|5|41696|5|0|0|0|0|0

java 复制代码
@RestController
public class SentinelController {

    @Autowired
    TestService testService;

    @GetMapping("/hello/{name}")
    public String sayHello(@PathVariable("name") String name){
        return testService.doTest(name);
    }
}


@Service
public class TestService {

    @SentinelResource(value = "doTest",blockHandler ="blockHandler",fallback = "fallback") //声明限流的资源
    public String doTest(String name){
        return "hello , "+name;
    }
    public String blockHandler(String name, BlockException e){ //降级,限流触发的
       return "被限流了";
    }
    // 降级和限流是不一样的,限流可以触发降级,降级是因为已经被触发了
    // 降级是第三方业务调用的时候,针对下游的一个返回
    // 限流是针对当前服务访问的限制
    // 这两个配置只会调用一个
    public String fallback(String name){ //降级,熔断触发的
        return "被降级了";
    }

}


@SpringBootApplication
public class SpringbootSentinelApplication {

    public static void main(String[] args) {
        initFlowRule();
        SpringApplication.run(SpringbootSentinelApplication.class, args);
    }

    private static void initFlowRule(){
        List<FlowRule> rules=new ArrayList<>();
        FlowRule flowRule=new FlowRule();
        flowRule.setResource("doTest"); //针对那个资源设置规则
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);//QPS或者并发数
        flowRule.setCount(5); //QPS=5
        rules.add(flowRule);
        FlowRuleManager.loadRules(rules);
    }


}

Sentinel中的流量控制

维度 + 规则 + 资源

不管是通过什么样的方式,其核心原理就是,监控应用流量的qps或者并发线程数的指标,然后去判断这些指标的阈值去对流量进行控制,防止瞬时流量高峰导致系统被压垮。

SphU.entry(resourceName) ->

正常,则通过

被限制,抛出 FlowException( FlowException extends BlockException)

同一个资源也可以创建不同的规则,这个主要是通过List rules=new ArrayList<>();实现的,如果有多个规则,会去遍历,如果发现那个规则被触发则就执行,否则就顺利通过。

一个规则由什么组成?

  • resource 资源
  • count 阈值
  • grade 类型(基于QPS 还是 并发线程数)
  • limitApp,针对的调用来源.
  • strategy , 调用关系限流
  • controlBehavior . (直接拒绝, 冷启动,匀速排队)
相关推荐
用户67570498850212 分钟前
告别数据库瓶颈!用这个技巧让你的程序跑得飞快!
后端
千|寻31 分钟前
【画江湖】langchain4j - Java1.8下spring boot集成ollama调用本地大模型之问道系列(第一问)
java·spring boot·后端·langchain
程序员岳焱44 分钟前
Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解
后端·sql·mysql
龚思凯1 小时前
Node.js 模块导入语法变革全解析
后端·node.js
天行健的回响1 小时前
枚举在实际开发中的使用小Tips
后端
wuhunyu1 小时前
基于 langchain4j 的简易 RAG
后端
techzhi1 小时前
SeaweedFS S3 Spring Boot Starter
java·spring boot·后端
写bug写bug2 小时前
手把手教你使用JConsole
java·后端·程序员
苏三说技术2 小时前
给你1亿的Redis key,如何高效统计?
后端
JohnYan3 小时前
工作笔记- 记一次MySQL数据移植表空间错误排除
数据库·后端·mysql