Java小案例-Sentinel的实现原理
前言
Sentinel是阿里开源的一款面向分布式、多语言异构化服务架构的流量治理组件。
主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
核心概念
要想理解一个新的技术,那么首先你得理解它的一些核心概念
资源
资源是Sentinel中一个非常重要的概念,资源就是Sentinel所保护的对象。
资源可以是一段代码,又或者是一个接口,Sentinel中并没有什么强制规定,但是实际项目中一般以一个接口为一个资源,比如说一个http接口,又或者是rpc接口,它们就是资源,可以被保护。
资源是通过Sentinel的API定义的,每个资源都有一个对应的名称,比如对于一个http接口资源来说,Sentinel默认的资源名称就是请求路径。
规则
规则也是一个重要的概念,规则其实比较好理解,比如说要对一个资源进行限流,那么限流的条件就是规则,后面在限流的时候会基于这个规则来判定是否需要限流。
Sentinel的规则分为流量控制规则、熔断降级规则以及系统保护规则,不同的规则实现的效果不一样。
来个Demo
为了兼顾文章的完整性和我一贯的风格,必须要来个demo,如果你已经使用过了Sentinel,那么就可以直接pass这一节,直接快进到核心原理。
1、基本使用
引入依赖
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.6</version>
</dependency>
测试代码
public class SentinelSimpleDemo {public static void main(String[] args) {//加载流控规则initFlowRules();for (int i = 0; i < 5; i++) {Entry entry = null;try {entry = SphU.entry("sayHello");//被保护的逻辑System.out.println("访问sayHello资源");} catch (BlockException ex) {System.out.println("被流量控制了,可以进行降级处理");} finally {if (entry != null) {entry.exit();}}}}private static void initFlowRules() {List<FlowRule> rules = new ArrayList<>();//创建一个流控规则FlowRule rule = new FlowRule();//对sayHello这个资源限流rule.setResource("sayHello");//基于qps限流rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//qps最大为2,超过2就要被限流rule.setCount(2);rules.add(rule);//设置规则FlowRuleManager.loadRules(rules);}}
解释一下上面这段代码的意思
-
initFlowRules方法就是加载一个限流的规则,这个规则作用于
sayHello
这个资源,基于qps限流,当qps超过2之后就会触发限流。 -
SphU.entry("sayHello")
这行代码是Sentinel最最核心的源码,这行代码表面看似风平浪静,实则暗流涌动。这行代码表明接下来需要访问某个资源(参数就是资源名称),会去检查需要被访问的资源是否达到设置的流控、熔断等规则。对于demo来说,就是检查sayHello
这个资源是否达到了设置的流量控制规则。 -
catch BlockException也很重要,当抛出BlockException这个异常,说明触发了一些设置的保护规则,比如限流了,这里面就可以进行降级操作。
-
System.out.println("访问sayHello资源")
这行代码表面是一个打印语句,实则就是前面一直在说的需要被保护的资源。
所以上面这段代码的整体意思就是对sayHello
这个需要访问的资源设置了一个流控规则,规则的内容是当qps到达2的时候触发限流,之后循环5次访问sayHello
这个资源,在访问之前通过SphU.entry("sayHello")
这行代码进行限流规则的检查,如果达到了限流的规则的条件,会抛出BlockException。
测试结果
从结果可以看出,当前两次访问sayHello
成功之后,qps达到了2,之后再访问就被限流了,失败了。
2、集成Spring
在实际的项目使用中一般不会直接写上面的那段demo代码,而是集成到Spring环境底下。
引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.2.5.RELEASE</version>
</dependency>
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.5.RELEASE</version>
</dependency>
之后提供一个/sayHello
接口
@RestController
public class SentinelDemoController {@GetMapping("/sayHello")public String sayHello() throws InterruptedException {return "hello";}}
配置文件
server:port: 9527spring:application:name: SentinelDemo
到这demo就搭建完成了。
此时你心理肯定有疑问,那前面提到的资源和对应的规则去哪了?
前面在说资源概念的时候,我提到Sentinel中默认一个http接口就是一个资源,并且资源的名称就是接口的请求路径。
而真正的原因是Sentinel实现了SpringMVC中的HandlerInterceptor
接口,在调用Controller接口之前,会将一个调用接口设置为一个资源,代码如下
而getResourceName
方法就是获取资源名,其实就是接口的请求路径,比如前面提供的接口路径是/sayHello
,那么资源名就是/sayHello
。
再后面的代码就是调用上面demo中提到表面风平浪静,实则暗流涌动的SphU.entry(..)
方法,检查被调用的资源是否达到了设置的规则。
好了,既然资源默认是接口,已经有了,那么规则呢?
规则当然可以按照第一个demo的方式来做,比如在Controller接口中加载,代码如下。
@RestController
public class SentinelDemoController {static {List<FlowRule> rules = new ArrayList<>();//创建一个流控规则FlowRule rule = new FlowRule();//对/sayHello这个资源限流rule.setResource("/sayHello");//基于qps限流rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//qps最大为2,超过2就要被限流rule.setCount(2);rules.add(rule);//设置规则FlowRuleManager.loadRules(rules);}@GetMapping("/sayHello")public String sayHello() throws InterruptedException {return "hello";}}
此时启动项目,在浏览器输入以下链接
http://localhost:9527/sayHello
疯狂快速使劲地多点几次,就出现下面这种情况
可以看出规则生效了,接口被Sentinel限流了,至于为什么出现这个提示,是因为Sentinel有默认的处理BlockException
的机制,就在前面提到的进入资源的后面。
当然,你也可以自定义处理的逻辑,实现BlockExceptionHandler
接口就可以了。
虽然上面这种硬编码规则的方式可以使用,但是在实际的项目中,肯定希望能够基于系统当期那运行的状态来动态调整规则,所以Sentinel提供了一个叫Dashboard应用的控制台,可以通过控制台来动态修改规则。
控制台其实就是一个jar包,可以从Sentinel的github仓库上下载,或者是通过从下面这个地址获取。
链接:https://pan.baidu.com/s/1Lw8V5ab_FUq934nLWDjfaw 提取码:obr5
之后通过java -jar命令启动就可以了,端口默认8080,浏览器访问http://ip:8080/#/login
就可以登录控制台了,用户名和密码默认都是sentinel。
此时服务要接入控制台,只需要在配置文件上加上控制台的ip和端口即可
spring:cloud:sentinel:transport:# 指定控制台的ip和端口dashboard: localhost:8080
项目刚启动的时候控制台默认是没有数据的,需要访问一下接口,之后就有了。
之后就可以看到/sayHello
这个资源,后面就可以通过页面设置规则。
核心原理
讲完demo,接下来就来讲一讲Sentinel的核心原理,也就是前面提到暗流涌动的SphU.entry(..)
这行代码背后的逻辑。
Sentinel会为每个资源创建一个处理链条,就是一个责任链,第一次访问这个资源的时候创建,之后就一直复用,所以这个处理链条每个资源有且只有一个。
SphU.entry(..)
这行代码背后就会调用责任链来完成对资源的检查逻辑。
这个责任链条中每个处理节点被称为ProcessorSlot
,中文意思就是处理器槽
这个ProcessorSlot
有很多实现,但是Sentinel的核心就下面这8个:
-
NodeSelectorSlot
-
ClusterBuilderSlot
-
LogSlot
-
StatisticSlot
-
AuthoritySlot
-
SystemSlot
-
FlowSlot
-
DegradeSlot
这些实现会通过SPI机制加载,然后按照一定的顺序组成一个责任链。
默认情况下,节点是按照如下的顺序进行排序的
虽然默认就8个,但是如果你想扩展,只要实现ProcessorSlot
,按照SPI的规定配置一下就行。
下面就来按照上面节点的处理顺序来好好扒一扒这8个ProcessorSlot
。
1、NodeSelectorSlot
这个节点的作用是来设置当前资源对应的入口的统计Node。
首先什么是统计Node?
比如就拿上面的例子来说,当/sayHello
这个资源的qps超过2的时候,要触发限流。
但是有个疑问,Sentinel是怎么知道/sayHello
这个资源的qps是否达到2呢?
当然是需要进行数据统计的,只有通过统计,才知道qps是否达到2,这个进行数据统计的类在Sentinel中叫做Node。
通过Node这个统计的类就知道有多少请求,成功多少个,失败多少个,qps是多少之类的。底层其实是使用到了滑动窗口算法。
那么什么叫对应的入口?
在Sentinel中,支持同一个资源有不同的访问入口。
举个例子,这个例子后面会反复提到。
假设把杭州看做是服务,西湖看做是一个资源,到达西湖有两种方式,地铁和公交。
所以要想访问西湖这个资源,就可以通过公交和地铁两种方式,而公交和地铁就对应前面说的入口的意思。
只不过一般一个资源就一个入口,比如一个http接口一般只能通过http访问,但是Sentinel支持多入口,你可以不用,但是Sentinel有。
所以NodeSelectorSlot的作用就是选择资源在当前调用入口的统计Node,这样就实现了统计同一个资源在不同入口访问数据,用上面的例子解释,就可以实现分别统计通过公交和地铁访问西湖的人数。
资源的入口可以在进入资源之前通过ContextUtil.enter("入口名", origin)
来指定,如果不指定,那么入口名称默认就是sentinel_default_context
。
在SpringMVC环境底下,所有的http接口资源,默认的入口都是sentinel_spring_web_context
入口名称也可以通过控制台看到
那么为什么要搞一个入口的概念呢?这里咱先留个悬念,后面再说。
2、ClusterBuilderSlot
ClusterBuilderSlot的作用跟NodeSelectorSlot其实是差不多的,也是用来选择统计Node,但是选择的Node的统计维护跟NodeSelectorSlot不一样。
ClusterBuilderSlot会选择两个统计Node:
-
第一个统计Node是资源的所有入口的统计数据之和,就是资源访问的总数据
-
第二个统计Node就是统计资源调用者对资源访问数据
资源调用者很好理解,比如一个http接口资源肯定会被调用,那么调用这个接口的服务或者应用其实就是资源的调用者,但是一般资源的调用者就是指某个服务,后面调用者我可能会以服务来代替。
一个接口可以被很多服务调用,所以一个资源可以很多调用者,而不同调用者都会有单独的一个统计Node,用来分别统计不同调用者对资源的访问数据。
举个例子,现在访问西湖这个资源的大兄弟来自上海,那么就会为上海创建一个统计Node,用来统计所有来自上海的人数,如果是北京,那么就会为北京创建一个统计Node。
那么如何知道访问资源来自哪个服务(调用者)呢?
也是通过ContextUtil.enter("入口名", origin)
来指定,这个方法的第二个参数origin
就是代表服务名的意思,默认是空。
所以
ContextUtil.enter(..)
可以同时指定资源的入口和调用者,一个资源一定有入口,因为不指定入口默认就是sentinel_default_context
,但是调用者不指定就会没有。
对于一个http请求来说,Sentinel默认服务名需要放到S-user
这个请求头中,所以如果你想知道接口的调用服务,需要在调用方发送请求的时候将服务名设置到S-user
请求头中。
当资源所在的服务接收到请求时,Sentinel就会从S-user
请求头获取到服务名,之后再通过ContextUtil.enter("入口名", "调用者名")
来设置当前资源的调用者
这里我原以为Sentinel会适配比如OpenFeign之类的框架,会自动将服务名携带到请求头中,但是我翻了一下源码,发现并没有去适配,不知道是出于什么情况的考虑。
所以这一节加上上一节,我们知道了一个资源其实有三种维度的统计Node:
-
分别统计不同入口的访问数据
-
统计所有入口访问数据之和
-
分别统计来自某个服务的访问数据
为了方便区分,我来给这三个统计Node取个响亮的名字
不同入口的访问数据就叫他DefaultNode,统计所有入口访问数据之和就叫他ClusterNode,来自某个服务的访问数据就叫他OriginNode。
是不是够响亮!
那么他们的关系就可以用下面这个图来表示
3、LogSlot
这个Slot没什么好说的,通过名字可以看出来,其实就是用来打印日志的。
当发生异常,就会打印日志。
4、StatisticSlot
这个Slot就比较重要了,就是用来统计数据的。
前面说的NodeSelectorSlot和ClusterBuilderSlot,他们的作用就是根据资源当前的入口和调用来源来选择对应的统计Node。
而StatisticSlot就是对这些统计Node进行实际的统计,比如加一下资源的访问线程数,资源的请求数量等等。
前几个Slot其实都是准备、统计的作用,并没有涉及限流降级之类的,他们是为限流降级提供数据支持的。
5、AuthoritySlot
Authority是授权的意思,这个Slot的作用是对资源调用者进行授权,就是黑白名单控制。
可以通过控制台来添加授权规则。
在AuthoritySlot中会去获取资源的调用者,之后会跟授权规则中的资源应用这个选项进行匹配,之后就会出现有以下2种情况:
-
授权类型是黑名单,匹配上了,说明在黑名单内,那么这个服务就不能访问这个资源,没匹配上就可以访问
-
授权类型是白名单。匹配上了,说明在白名单内,那么这个服务就可以访问这个资源,没匹配上就不可以访问
6、SystemSlot
这个的作用是根据整个系统运行的统计数据来限流的,防止当前系统负载过高。
它支持入口qps、线程数、响应时间、cpu使用率、负载5个限流的维度。
对于系统的入口qps、线程数、平均响应时间这些指标,也会有一个统计Node专门去统计,所以这个统计Node的作用就好比会去统计所有访问西湖的人数,统计也在StatisticSlot代码中,前面说的时候我把代码隐藏了
至于cpu使用率、负载指标,Sentinel会启动一个定时任务,每隔1s会去读取一次当前系统的cpu和负载。
7、FlowSlot
这个Slot会根据预设的规则,结合前面的统计出来的实时信息进行流量控制。
在说FlowSlot之前,先来用之前画的那张图回顾一下一个资源的三种统计维度
这里默默地注视10s。。
限流规则配置项比较多
这里我们来好好扒一扒这些配置项的意思。
针对来源,来源就是前面说的调用方,这个配置表明,这个规则适用于哪个调用方,默认是default,就是指规则适用于所有调用方,如果指定了调用方,那么这个规则仅仅对指定的调用方生效。
举个例子来说,比如说现在想限制来自上海的访问的人数,那么针对来源可以填上海,之后当访问的大兄弟来自上海的时候,Sentinel就会根据上海对应的OriginNode数据来判断是否达到限流的条件。
阈值类型,就是限流条件,当资源的qps或者访问的线程数到达设置的单机阈值,就会触发限流。
是否集群,这个作用是用来对集群控制的,因为一个服务可能在很多台机器上,而这个的作用就是将整个集群看成一个整体来限流,这里就不做深入讨论。
流控模式,这个流控模式的选项仅仅对阈值类型为qps有效,当阈值类型线程数时无效。
这个配置就比较有意思了,分为直接、关联、链路三种模式。
直接模式的意思就是当资源的ClusterNode统计数据统计达到了阈值,就会触发限流。
比如,当通过地铁和公交访问西湖人数之和达到单机阈值之后就会触发限流。
关联模式下需要填写关联的资源名称
关联的意思就是当关联资源的ClusterNode统计的qps达到了设置的阈值时,就会触发当前资源的限流操作。
比如,假设现在西湖这个资源关联了雷峰塔这个资源,那么当访问雷峰塔的人数达到了指定的阈值之后,此时就触发西湖这个资源的限流,就是雷峰塔流量高了但是限流的是西湖。
链路模式也一样,它需要关联一个入口资源
关联入口的意思就是指,当访问资源的实际入口跟关联入口是一样的时候,就会根据这个入口对应的DefaultNode的统计数据来判断是否需要限流。
也就是可以单独限制通过公交和地铁的访问的人数的意思。
到这,其实前面说到的一个资源的三种统计维度的数据都用到了,现在应该明白了为什么需要这么多维度的数据,就是为不同维度限流准备的。
最后一个配置项,流控效果,这个就是如果是通过qps来限流,并且达到了限流的条件之后会做什么,如果是线程数,就直接抛出BlockException
异常
也有三种方式,快速失败、Warm Up、排队等待
快速失败的意思就是指一旦触发限流了,那么直接抛出BlockException
异常
Warm Up的作用就是为了防止系统流量突然增加时出现瞬间把系统压垮的情况。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限。
排队等待,很好理解,意思当出现限流了,不是抛异常,而是去排队等待一定时间,其实就是让请求均匀速度通过,内部使用的是传说中的漏桶算法。
DegradeSlot
这是整个责任链中最后一个slot,这个slot的作用是用来熔断降级的。
Sentinel支持三种熔断策略:慢调用比例、异常比例 、异常数,通过规则配置也可以看出来。
熔断器的工作流程大致如下
Sentinel会为每个设置的规则都创建一个熔断器,熔断器有三种状态,OPEN(打开)、HALF_OPEN(半开)、CLOSED(关闭)
-
当处于CLOSED状态时,可以访问资源,访问之后会进行慢调用比例、异常比例、异常数的统计,一旦达到了设置的阈值,就会将熔断器的状态设置为OPEN
-
当处于OPEN状态时,会去判断是否达到了熔断时间,如果没到,拒绝访问,如果到了,那么就将状态改成HALF_OPEN,然后访问资源,访问之后会对访问结果进行判断,符合规则设置的要求,直接将熔断器设置为CLOSED,关闭熔断器,不符合则还是改为OPEN状态
-
当处于HALF_OPEN状态时,直接拒绝访问资源
一般来说,熔断降级其实是对于服务的调用方来说的。
在项目中会经常调用其它服务或者是第三方接口,而对于这些接口,一旦它们出现不稳定,就有可能导致自身服务长时间等待,从而出现响应延迟等等问题。
此时服务调用方就可基于熔断降级方式解决。
一旦第三方接口响应时间过长,那么就可以使用慢调用比例规则,当出现大量长时间响应的情况,那么就直接熔断,不去请求。
虽然说熔断降级是针对服务的调用方来说,但是Sentinel本身并没有限制熔断降级一定是调用其它的服务。
总结
通过整篇文章的分析之后,再回头看看Sentinel的简介的内容,其实就能更好地理解Sentinel的定位和功能。
Sentinel核心就是一堆统计数据和基于这些统计数据实现的流控和熔断的功能,源码并不复杂,而且Sentinel的代码写得非常好。
相关文章:

Java小案例-Sentinel的实现原理
前言 Sentinel是阿里开源的一款面向分布式、多语言异构化服务架构的流量治理组件。 主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 核心概念 要想理解一个新的技…...

【Leetcode Sheet】Weekly Practice 21
Leetcode Test 1901 寻找峰值Ⅱ(12.19) 一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。 给你一个 从 0 开始编号 的 m x n 矩阵 mat ,其中任意两个相邻格子的值都 不相同 。找出 任意一个 峰值 mat[i][j] 并 返回其位置 [i,j] 。 …...

C语言使用qsort和bsearch实现二分查找
引言 在计算机科学领域,查找是一项基本操作,而二分查找是一种高效的查找算法。本博客将详细解释一个简单的C语言程序,演示如何使用标准库函数qsort和bsearch来对一个整数数组进行排序和二分查找。 代码解析 包含头文件 #include <stdi…...

MySQL的替换函数及补全函数的使用
前提: mysql的版本是8.0以下的。不支持树形结构递归查询的。但是,又想实现树形结构的一种思路 提示:如果使用的是MySQL8.0及其以上的,想要实现树形结构,请参考:MySQL数据库中,如何实现递归查询…...

2022第十二届PostgreSQL中国技术大会-核心PPT资料下载
一、峰会简介 本次大会以“突破•进化•共赢 —— 安全可靠,共建与机遇”为主题,助力中国数据库基础软件可掌控、可研究、可发展、可生产,并推动数据库生态的繁荣与发展。大会为数据库从业者、数据库相关企业、数据库行业及整个IT产业带来崭…...

2024 年 10大 AI 趋势
2025 年,全球人工智能市场预计将达到惊人的 1906.1 亿美元,年复合增长率高达 36.62%。 人工智能软件正在迅速改变我们的世界,而且这种趋势在未来几年只会加速。 我们分析了未来有望彻底改变 2024 年的 10 个AI趋势。从生成式人工智能的兴起到…...

Uboot
什么是Bootloader? Linux系统要启动就必须需要一个 bootloader程序,也就说芯片上电以后先运行一段bootloader程序。 这段 **bootloader程序会先初始化时钟,看门狗,中断,SDRAM,等外设,然后将 Linux内核从f…...

ECMAScript 的未来:预测 JavaScript 创新的下一个浪潮
以下是简单概括关于JavaScript知识点以及一些目前比较流行的比如:es6 想要系统学习: 大家有关于JavaScript知识点不知道可以去 🎉博客主页:阿猫的故乡 🎉系列专栏:JavaScript专题栏 🎉ajax专栏&…...

代码随想录算法训练营第十三天 | 239. 滑动窗口最大值、347.前 K 个高频元素
239. 滑动窗口最大值 题目链接:239. 滑动窗口最大值 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 文章讲解…...

推荐五个免费的网络安全工具
导读: 在一个完美的世界里,信息安全从业人员有无限的安全预算去做排除故障和修复安全漏洞的工作。但是,正如你将要学到的那样,你不需要无限的预算取得到高质量的产品。这里有SearchSecurity.com网站专家Michael Cobb推荐的五个免费…...

Cross-Drone Transformer Network for Robust Single Object Tracking论文阅读笔记
Cross-Drone Transformer Network for Robust Single Object Tracking论文阅读笔记 Abstract 无人机在各种应用中得到了广泛使用,例如航拍和军事安全,这得益于它们与固定摄像机相比的高机动性和广阔视野。多无人机追踪系统可以通过从不同视角收集互补的…...

【LeetCode刷题笔记】动态规划(二)
647. 回文子串 解题思路: 1. 暴力穷举 , i 遍历 [0, N) , j 遍历 [i+1, N] ,判断每一个子串 s[i, j) 是否是回文串,判断是否是回文串可以采用 对撞指针 的方法。如果是回文串就计数 +1...

(十七)Flask之大型项目目录结构示例【二扣蓝图】
大型项目目录结构: 问题引入: 在上篇文章讲蓝图的时候我给了一个demo项目,其中templates和static都各自只有一个,这就意味着所有app的模板和静态文件都放在了一起,如果项目比较大的话,这就非常乱…...

蓝牙技术在物联网中的应用
随着蓝牙技术的不断演进和发展,蓝牙已经从单一的传统蓝牙技术发展成集传统蓝牙。高速蓝牙和低耗能蓝牙于一体的综合技术,不同的应用标准更是超过40个越来越广的技术领域和越来越多的应用场景,使得目前的蓝牙技术成为包含传感器技术、识别技术…...

宝塔面板Linux服务器CentOS 7数据库mysql5.6升级至5.7版本教程
近段时间很多会员问系统更新较慢,也打算上几个好的系统,但几个系统系统只支持MYSQL5.7版本,服务器一直使用较低的MYSQL5.6版本,为了测试几个最新的系统打算让5.6和5.7并存使用,参考了多个文档感觉这种并存问题会很多。…...

掌握常用Docker命令,轻松管理容器化应用
Docker是一个开源的应用容器引擎,它可以让开发者将应用程序及其依赖打包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器或Windows机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。下面介…...

【数据结构1-2】P5076 普通二叉树(简化版)(c++,multiset做法)
文章目录 一、题目【深基16.例7】普通二叉树(简化版)题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1基本思路: 一、题目 【深基16.例7】普通二叉树(简化版) 题目描述 您需要写一种数据结构,来维…...

Linux系统安装及管理
目录 一、Linux应用程序基础 1.1应用程序与系统命令的关系 1.2典型应用程序的目录结构 1.3常见的软件包装类型 二、RPM软件包管理 1.RPM是什么? 2.RPM命令的格式 2,1查看已安装的软件包格式 2.2查看未安装的软件包 3.RPM安装包从哪里来? 4.挂…...

MySQL学生向笔记以及使用过程问题记录(内含8.0.34安装教程
MySQL 只会写代码 基本码农 要学好数据库,操作系统,数据结构与算法 不错的程序员 离散数学、数字电路、体系结构、编译原理。实战经验, 高级程序员 去IOE:去掉IBM的小型机、Oracle数据库、EMC存储设备,代之以自己在开源…...

obs video-io.c
video_frame_init 讲解 /* messy code alarm video_frame_init 函数用于初始化视频帧。它接受一个指向 struct video_frame 结构体的指针 frame, 视频格式 format,以及宽度 width 和高度 height。该函数根据视频格式的不同,计算出每个视频帧…...

简述 tcp 和 udp的区别?
简述 tcp 和 udp的区别? TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种不同的传输层协议,用于在计算机网络中进行数据传输。以下是它们的主要区别: 区别࿱…...

信息收集 - 谷歌hack
搜索引擎 FOFA网络空间测绘:https://fofa.info/ FOFA(FOcus on Assets)是一个网络空间搜索引擎,可以帮助用户快速定位和收集特定目标的信息。 ZoomEye:https://www.zoomeye.org ZoomEye 是一个网络空间搜索引擎,可以用于发现和收集特定目标的网络设备、Web应用程序、开放…...

英飞凌TC3xx之一起认识DSADC系列(七)应用实战项目二(实现旋变软解码)
英飞凌TC3xx之一起认识DSADC系列(七) 1 项目要求2 项目实现2.1 内部时钟配置2.2 输入信号配置2.3 调制器配置2.4 滤波器链路配置2.5 整流器配置3 总结本文写一篇关于DSADC的resover的载波信号生成的应用,刚刚接触DSADC的开发者很容易被手册中简短的文字描述弄的迷惑,它到底…...
【浏览器】同源策略和跨域
1. 什么是跨域 在说跨域之前,先说说同源策略,什么是同源策略呢?同源策略是浏览器的一种安全机制,减少跨站点脚本攻击(XSS,Cross Site Scripting)、跨站点请求伪造(CSRF,Cross Site Request Forgery)攻击等,因为非同源的请求会被浏览器拦截掉。 同源就是协议、域名(…...

云计算与大数据之间的羁绊(期末不挂科版):云计算 | 大数据 | Hadoop | HDFS | MapReduce | Hive | Spark
文章目录 前言:一、云计算1.1 云计算的基本思想1.2 云计算概述——什么是云计算?1.3 云计算的基本特征1.4 云计算的部署模式1.5 云服务1.6 云计算的关键技术——虚拟化技术1.6.1 虚拟化的好处1.6.2 虚拟化技术的应用——12306使用阿里云避免了高峰期的崩…...

基于jdk11和基于apache-httpclient的http请求工具类
1.基于apache-httpclient 需要引入依赖 <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.3.5</version></dependency> 工具类如下: package com.bw.e…...

Node.js(二)-模块化
1. 模块化的基本概念 1.1 什么是模块化 模块化是指解决一个复杂问题时,自顶向下逐层将系统拆分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。 1.2 编程领域中的模块化 编程领域中的模块化,就是遵守固定的规则&…...

ARM AArch64的TrustZone架构详解(上)
目录 一、概述 1.1 在开始之前 二、什么是TrustZone? 2.1 Armv8-M的TrustZone 2.2 Armv9-A Realm Management Extension(RME)...

从源PC上一次性p2v(qcow2)的构想
磁盘分区表,虚拟硬盘文件,操作系统引导 1. 基本概念和术语 源硬盘:一般就是客户的PC机的硬盘,硬盘里面包含了Windows分区。 源Windows:以源硬盘启动的Windows环境。 虚拟磁盘文件:文件格式有qcow2、vhd…...

数据结构:KMP算法
1.何为KMP算法 KMP算法是由Knuth、Morris和Pratt三位学者发明的,所以取了三位学者名字的首字母,叫作KMP算法。 2.KMP的用处 KMP主要用于字符串匹配的问题,主要思想是当出现字符串不匹配时,我们可以知道一部分之前已经匹配过的的文…...