sentinel
2024-05-03 15:53:53 0 举报
源码分析
作者其他创作
大纲/内容
EntranceNode1
创建ClusterNode
ClusterNode3
DefaultNode3
整个责任链
NodeSelectorSlot
LogSlot
null
retryTimeoutArrived()当前时间>=重试时间
end
statisticSlot
DegradeSlot
next
&&
当前资源没有chain并且操作缓存中的超过阈值
ClusterBuilderSlot
ThrottlingController排队等待(漏桶)
@SentinelResource切入点
正常情况不会进入该分支(机器时钟回拨等异常情况)
获取资源中chain链
(int)(node.passQps())
logSlot
//获取当前窗口 WindowWrap<T> old = array.get(idx);
SystemSlot
DefaultController直接拒绝
this.clusterNode.addPassRequest(count);
currentState.get() == State.CLOSED
super.addPassRequest(count);
EntranceNode2
old == null没有当前窗口
FlowSlot
创建操作对象
context1
wrap.value().addPass(count);
node.curThreadNum()
slotChainBuilder为空
AuthoritySlot
ruleProvider.apply(resource.getName())获取资源设置的所有规则
ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);
创建context
avgUsedTokens(node); 根据流控类型在时间窗口获取当前数量
root
开始执行责任链
rollingCounterInSecond.getWindowIntervalInSec()单位时间窗长度
end开始指向abstractLinkedProcessorSlot将end的next指向新节点也就是abstractLinkedProcessorSlot指向NodeSelectorSlot节点将end节点指向NodeSelectorSlot节点
获取资源设置的熔断降级规则 为空直接通过List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());
SPI的方式加载processorSlotList<ProcessorSlot> 反射创建出来的Slot排序之后放入集合中
DefaultCircuitBreakerSlot
DegradeSLot
DefaultNode2
authoritySlot
当前窗口启动时间 > 数组中窗口启动时间 证明这个数组中的样本窗口已经过期
AbstractLinkedProcessorSlot
StatisticSlot
first
ClusterNode1
SentinelResourceAspect切面
WindowWrap<MetricBucket> wrap = data.currentWindow();根据当前时间获取样本窗口
获取请求来源
node.increaseThreadNum();
return old
当前窗口启动时间=窗口的启动时间
DefaultNode1
windowStart < old.windowStart()
WarmUpController预热(令牌桶)
InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME)默认没有 当前线程context并且没有超出阈值
熔断器处于关闭状态
/** * idx = (currentTime / windowLengthInMs) % sampleCount = (100 / 200) % 5 = 0 * ( 当前时间 / 窗口时间 ) % 样本数量 */ int idx = calculateTimeIdx(timeMillis); /** * Calculate current bucket start time. * currentTime - (currentTime % windowLengthInMs)= 110 - (100 % 200) = 0ms * 当前样本窗口的启动时间 = 当前时间 - (当前时间 % 当前样本窗口大小) */ long windowStart = calculateWindowStart(timeMillis);
node.addPassRequest(count);
指向
rollingCounterInSecond.pass()
.build()
currentState.get() == State.OPEN
// 一个线程对应一个请求 一个请求对应一个context Context context = ContextUtil.getContext();
grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int)(node.passQps());
rollingCounterInSecond.pass() / rollingCounterInSecond.getWindowIntervalInSec()
创建DefaultNode
rollingCounterInSecond.addPass(count);
每一个应用程序是一个root
当前数量+本次请求 > 阈值 返回false直接限流 否则 true表示通过curCount + acquireCount > count return false 有一个优先级判断 来进行等待 默认为不优先
close
//当前窗口大小 data.currentWindow();//遍历每一个样本窗口 for (MetricBucket window : list) { //计算出样本窗口累计通过数量 pass += window.pass(); }
时间轴坐标为相当时间,以第一次滚动开始时间为 0ms。 下面以图中的 3 个请求来分析数据是如何记录下来的:100ms 时收到第 1 个请求我们的目的是从数组中找一个合适的窗口来存放统计数据。那么先计算出数组下标 idx = (currentTime / l) % n = (100 / 200) % 5 = 0同时还要计算出本次请求对应的窗口开始时间:curWindowStart = currentTime - (currentTime % l)= 110 - (100 % 200) = 0ms现在我们取 window0,因为这是第一次使用 window0,所以先要实例化一下,window0.windowStart 直接取前面计算出的 curWindowStart,即 0ms500ms 时收到第 2 个请求req 落在 400~600ms 之间,同样先计算数组下标 idx = (500 / 200) % 5 = 2,本次请求对应的窗口开始时间:curWindowsStart = 500 - (500 % 200) = 400ms同样 window2 也是第一次使用,也是先实例化一下,window2.windowStart 也是直接取 curWindowsStart,即 400ms1100ms 时收到第 3 个请求此时环形数组转完了 1 圈,同样先找数组下标 idx = (1100 / 200) % 5 = 0,本次请求对应的窗口开始时间:curWindowsStart = 1100 - (1100 % 200) = 1000ms对应的就是 window0,由于在第 1 个请求中已经实例化过了,这里就不需要在初始化了。 此时 curWindowsStart(1000ms) > window0.windowStart(0ms),说明 window0 是一个过期的窗口,需要更新。因为在 1000~1200ms 之间,可能会有多个请求到达,存在并发更新 window0 的情况,那么 updateLock 派上用场了。更新操作其实就是将 windows0.windowsStart 置为本次的 curWindowsStart,即 1000ms,同时将底层 MetricBucket 中所有计数器的值重置为 0。接下来,记录统计数据就好了。
ClusterNode2
fromOpenToHalfOpen(context)通过CAS方式将打开状态变为半开
end.setNext(protocolProcessor); end = protocolProcessor;
// context超出2000 返回一个不需要规则检测的资源 if (context instanceof NullContext)
SPI的方式加载DefaultSlotChainBuilder
创建一系列的chain链chain = SlotChainProvider.newSlotChain();
context2
将所有slot组成一个链表结构chain.addLast((AbstractLinkedProcessorSlot<?>) slot)
cb.tryPass(context)
收藏
0 条评论
回复 删除
下一页