docs: improve sentinel articles

pull/95/head
yanglbme 4 years ago
parent fa1aadc88f
commit a16b3236f0

@ -337,6 +337,27 @@ GitHub 技术社区 [Doocs](https://github.com/doocs),致力于打造一个内
<!-- ALL-CONTRIBUTORS-LIST: END -->
## 请小码农喝杯 coffee 吧
![在这里插入图片描述](./images/appreciateCode.JPG)
## 公众号
[Doocs](https://github.com/doocs) 技术社区旗下唯一公众号「**Doocs 开源社区**」​,欢迎扫码关注,**专注分享技术领域相关知识及行业最新资讯**。当然也可以加我个人微信备注GitHub拉你进技术交流群。
<table>
<tr>
<td align="center" style="width: 200px;">
<a href="https://github.com/doocs">
<img src="./images/qrcode-for-doocs.jpg" style="width: 400px;"><br>
<sub>公众平台</sub>
</a><br>
</td>
<td align="center" style="width: 200px;">
<a href="https://github.com/yanglbme">
<img src="./images/qrcode-for-yanglbme.jpg" style="width: 400px;"><br>
<sub>个人微信</sub>
</a><br>
</td>
</tr>
</table>
关注「**Doocs 开源社区**」公众号,回复 **PDF**,即可获取 [doocs/advanced-java](https://github.com/doocs/advanced-java) 项目离线 PDF 文档283 页精华),学习更加方便!
![](./images/pdf.png)

@ -11,14 +11,14 @@
4. 当前进入的时间已经远远落后当前的时间,目标时间窗口已经被 reset 更新成更新的时间窗口,那么将不会返回目标时间窗口,而是返回一个新的空的时间窗口进行统计,这个时间窗口不会再被重复利用。
其中的第四个情况表明sentinel 的滑动时间窗口是有时间范围的,这也是为了尽量减少 sentinel 的所占用的内存,默认情况下 sentinel 的采取的时间长度为 1 分钟和 1 秒钟。这里的实现与 LeapArray 类的结构非常有关系。
```Java
protected final AtomicReferenceArray<WindowWrap<T>> array;
```java
protected final AtomicReferenceArray<WindowWrap<T>> array;
```
在 LeapArray 中,时间窗口的存放通过一个由 AtomicReferenceArray 实现的 array 来实现。AtomicReferenceArray 支持原子读取和写入,并支持通过 cas 来为指定位置的成员进行更新。在时间窗口的创建并放回 array 的过程中,也就是上文的第一步,就是通过 AtomicReferenceArray 的 compareAndSet()方法来实现,保证并发下的线程安全。并发情况下,通过 cas 更新失败的线程将会回到就绪态,在下一次婚欢得到已经初始化完成的时间窗口。
```Java
private final ReentrantLock updateLock = new ReentrantLock();
```java
private final ReentrantLock updateLock = new ReentrantLock();
```
此处的 updateLock 是专门在上述的第三个情况来进行加锁的,只有成功得到锁的线程才会对过期的时间窗口进行 reset 操作,其他没有成功获取的线程将不会挂起等待,而是通过 yield()方法回到就绪态在下一次的循环尝试重新获取该位置的时间窗口。在下一次获取该锁的线程可能已经完成了,那么将会执行上述第二步,否则继续回到就绪态等待下一次循环中再次获取该时间窗口。

@ -2,9 +2,9 @@
Sentinel 中漏桶算法通过 RateLimiterController 来实现,在漏桶算法中,会记录上一个请求的到达时间,如果新到达的请求与上一次到达的请求之间的时间差小于限流配置所规定的最小时间,新到达的请求将会排队等待规定的最小间隔到达,或是直接失败。
```Java
```java
@Override
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
if (acquireCount <= 0) {
return true;
}
@ -48,7 +48,7 @@ Sentinel 中漏桶算法通过 RateLimiterController 来实现,在漏桶算法
}
}
return false;
}
}
```
## Sentinel 中令牌桶算法的实现
@ -56,24 +56,24 @@ Sentinel 中漏桶算法通过 RateLimiterController 来实现,在漏桶算法
在 Sentinel 中,令牌桶算法通过 WarmUpController 类实现。在这个情况下,当配置每秒能通过多少请求后,那么在这里 sentinel 也会每秒往桶内添加多少的令牌。当一个请求进入的时候,将会从中移除一个令牌。由此可以得出,桶内的令牌越多,也说明当前的系统利用率越低。因此,当桶内的令牌数量超过某个阈值后,那么当前的系统可以称之为处于`饱和`状态。
当系统处于 `饱和`状态的时候,当前允许的最大 qps 将会随着剩余的令牌数量减少而缓慢增加,达到为系统预热热身的目的。
```Java
this.count = count;
```java
this.count = count;
this.coldFactor = coldFactor;
this.coldFactor = coldFactor;
warningToken = (int)(warmUpPeriodInSec * count) / (coldFactor - 1);
warningToken = (int)(warmUpPeriodInSec * count) / (coldFactor - 1);
maxToken = warningToken + (int)(2 * warmUpPeriodInSec * count / (1.0 + coldFactor));
maxToken = warningToken + (int)(2 * warmUpPeriodInSec * count / (1.0 + coldFactor));
slope = (coldFactor - 1.0) / count / (maxToken - warningToken);
slope = (coldFactor - 1.0) / count / (maxToken - warningToken);
```
其中 count 是当前 qps 的阈值。coldFactor 则为冷却因子warningToken 则为警戒的令牌数量warningToken 的值为(热身时间长度 _ 每秒令牌的数量) / (冷却因子 - 1)。maxToken 则是最大令牌数量,具体的值为 warningToken 的值加上 (2 _ 热身时间长度 _ 每秒令牌数量) / (冷却因子 + 1)。当当前系统处于热身时间内,其允许通过的最大 qps 为 1 / (超过警戒数的令牌数 _ 斜率 slope + 1 / count),而斜率的值为(冷却因子 - 1) / count / (最大令牌数 - 警戒令牌数)。
举个例子: count = 3 coldFactor = 3热身时间为 4 的时候,警戒令牌数为 6最大令牌数为 12当剩余令牌处于 6 和 12 之间的时候,其 slope 斜率为 1 / 9。 那么当剩余令牌数为 9 的时候的允许 qps 为 1.5。其 qps 将会随着剩余令牌数的不断减少而直到增加到 count 的值。
```Java
@Override
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
```java
@Override
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
long passQps = (long) node.passQps();
long previousQps = (long) node.previousPassQps();
@ -97,9 +97,9 @@ Sentinel 中漏桶算法通过 RateLimiterController 来实现,在漏桶算法
}
return false;
}
}
protected void syncToken(long passQps) {
protected void syncToken(long passQps) {
long currentTime = TimeUtil.currentTimeMillis();
currentTime = currentTime - currentTime % 1000;
long oldLastFillTime = lastFilledTime.get();
@ -119,9 +119,9 @@ Sentinel 中漏桶算法通过 RateLimiterController 来实现,在漏桶算法
lastFilledTime.set(currentTime);
}
}
}
private long coolDownTokens(long currentTime, long passQps) {
private long coolDownTokens(long currentTime, long passQps) {
long oldValue = storedTokens.get();
long newValue = oldValue;
@ -135,5 +135,5 @@ Sentinel 中漏桶算法通过 RateLimiterController 来实现,在漏桶算法
}
}
return Math.min(newValue, maxToken);
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Loading…
Cancel
Save