mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-10-16 23:13:45 +08:00
u
This commit is contained in:
@@ -25,13 +25,7 @@
|
||||
<meta name="generator" content="Hexo 4.2.0">
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
|
||||
<div class="book-container">
|
||||
|
||||
<div class="book-sidebar">
|
||||
@@ -55,289 +49,148 @@
|
||||
<li><a href="/" class="current-tab">首页</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<ul class="uncollapsible">
|
||||
|
||||
<li><a href="../">上一级</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<ul class="uncollapsible">
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/01 开篇词:一次服务雪崩问题排查经历.md.html">01 开篇词:一次服务雪崩问题排查经历.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/02 为什么需要服务降级以及常见的几种降级方式.md.html">02 为什么需要服务降级以及常见的几种降级方式.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/03 为什么选择 Sentinel,Sentinel 与 Hystrix 的对比.md.html">03 为什么选择 Sentinel,Sentinel 与 Hystrix 的对比.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/04 Sentinel 基于滑动窗口的实时指标数据统计.md.html">04 Sentinel 基于滑动窗口的实时指标数据统计.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/05 Sentinel 的一些概念与核心类介绍.md.html">05 Sentinel 的一些概念与核心类介绍.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/06 Sentinel 中的责任链模式与 Sentinel 的整体工作流程.md.html">06 Sentinel 中的责任链模式与 Sentinel 的整体工作流程.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/07 Java SPI 及 SPI 在 Sentinel 中的应用.md.html">07 Java SPI 及 SPI 在 Sentinel 中的应用.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/08 资源指标数据统计的实现全解析(上).md.html">08 资源指标数据统计的实现全解析(上).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/09 资源指标数据统计的实现全解析(下).md.html">09 资源指标数据统计的实现全解析(下).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/10 限流降级与流量效果控制器(上).md.html">10 限流降级与流量效果控制器(上).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/11 限流降级与流量效果控制器(中).md.html">11 限流降级与流量效果控制器(中).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
<a class="current-tab" href="/专栏/深入理解 Sentinel(完)/12 限流降级与流量效果控制器(下).md.html">12 限流降级与流量效果控制器(下).md.html</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/13 熔断降级与系统自适应限流.md.html">13 熔断降级与系统自适应限流.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/14 黑白名单限流与热点参数限流.md.html">14 黑白名单限流与热点参数限流.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/15 自定义 ProcessorSlot 实现开关降级.md.html">15 自定义 ProcessorSlot 实现开关降级.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/16 Sentinel 动态数据源:规则动态配置.md.html">16 Sentinel 动态数据源:规则动态配置.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/17 Sentinel 主流框架适配.md.html">17 Sentinel 主流框架适配.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/18 Sentinel 集群限流的实现(上).md.html">18 Sentinel 集群限流的实现(上).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/19 Sentinel 集群限流的实现(下).md.html">19 Sentinel 集群限流的实现(下).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/20 结束语:Sentinel 对应用的性能影响如何?.md.html">20 结束语:Sentinel 对应用的性能影响如何?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/21 番外篇:Sentinel 1.8.0 熔断降级新特性解读.md.html">21 番外篇:Sentinel 1.8.0 熔断降级新特性解读.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||||
|
||||
<div class="sidebar-toggle-inner"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
function add_inner() {
|
||||
@@ -347,9 +200,6 @@
|
||||
inner.classList.add('show')
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function remove_inner() {
|
||||
|
||||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||||
@@ -357,9 +207,6 @@
|
||||
inner.classList.remove('show')
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function sidebar_toggle() {
|
||||
|
||||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||||
@@ -389,9 +236,6 @@
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function open_sidebar() {
|
||||
|
||||
let sidebar = document.querySelector('.book-sidebar')
|
||||
@@ -415,13 +259,7 @@ function hide_canvas() {
|
||||
overlay.classList.remove('show')
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<div class="off-canvas-content">
|
||||
|
||||
<div class="columns">
|
||||
@@ -487,9 +325,6 @@ function hide_canvas() {
|
||||
flowRule.setResource("GET:/hello");
|
||||
|
||||
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>Sentinel 冷启动限流算法参考了 Guava 的 SmoothRateLimiter 实现的冷启动限流算法,但实现上有很大的区别,Sentinel 主要用于控制每秒的 QPS,不会控制每个请求的间隔时间,只要满足每秒通过的 QPS 即可。正因为与 Guava 的不同,官方文档目前也没有很详细的介绍具体实现,单看源码很难揣摩作者的思路,加上笔者水平有限,没能切底理解 Sentinel 冷启动限流算法实现的细节,因此我们也不过深的去分析 WarmUpController 的源码,只是结合 Guava 的实现算法作个简单介绍。</p>
|
||||
@@ -525,9 +360,6 @@ function hide_canvas() {
|
||||
// permitsPerSecond: 每秒钟生成的令牌数上限为 200
|
||||
|
||||
double stableIntervalMicros = SECONDS.toMicros(1L) / permitsPerSecond;
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>由于 coldFactor 等于 3,且 coldInterval 等于 stableInterval 乘以 coldFactor,所以(coldInterval-stableInterval)是 stableInterval 的两倍,所以从 thresholdPermits 到 0 的时间是从 maxPermits 到 thresholdPermits 时间的一半,也就是 warmupPeriod 的一半。因为梯形的面积等于 warmupPeriod,所以长方形面积是梯形面积的一半,长方形的面积是 warmupPeriod/2。</p>
|
||||
@@ -561,9 +393,6 @@ double stableIntervalMicros = SECONDS.toMicros(1L) / permitsPerSecond;
|
||||
// stableIntervalMicros:stableInterval 转为微秒
|
||||
|
||||
thresholdPermits = 0.5 * warmupPeriodMicros / stableIntervalMicros;
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>所以:</p>
|
||||
@@ -605,9 +434,6 @@ thresholdPermits = 0.5 * warmupPeriodMicros / stableIntervalMicros;
|
||||
// coldIntervalMicros: coldInterval 转为微秒
|
||||
|
||||
maxPermits = thresholdPermits + 2.0 * warmupPeriodMicros / (stableIntervalMicros + coldIntervalMicros);
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>所以:</p>
|
||||
@@ -675,17 +501,11 @@ void resync(long nowMicros) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>了解了 Guava 的 SmoothRateLimiter 实现后,我们再来看下 Sentinel 的 WarmUpController。</p>
|
||||
|
||||
<pre><code class="language-java">public class WarmUpController implements TrafficShapingController {
|
||||
|
||||
|
||||
|
||||
protected double count;
|
||||
|
||||
private int coldFactor;
|
||||
@@ -695,17 +515,11 @@ void resync(long nowMicros) {
|
||||
private int maxToken;
|
||||
|
||||
protected double slope;
|
||||
|
||||
|
||||
|
||||
protected AtomicLong storedTokens = new AtomicLong(0);
|
||||
|
||||
protected AtomicLong lastFilledTime = new AtomicLong(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -745,9 +559,6 @@ void resync(long nowMicros) {
|
||||
// resync
|
||||
|
||||
syncToken(previousQps);
|
||||
|
||||
|
||||
|
||||
long restToken = storedTokens.get();
|
||||
|
||||
// 如果令牌桶中存放的令牌数超过警戒线,则进入冷启动阶段,调整 QPS。
|
||||
@@ -785,9 +596,6 @@ void resync(long nowMicros) {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>canPass 方法中,首先获取当前存储桶的令牌数,如果大于 warningToken,则控制 QPS。根据当前令牌桶中存储的令牌数量超出 warningToken 的令牌数计算当前秒需要控制的 QPS 的阈值,这两行代码是关键。</p>
|
||||
@@ -799,9 +607,6 @@ long aboveToken = restToken - warningToken;
|
||||
// 1.0 表示 1 秒
|
||||
|
||||
double warningQps = Math.nextUp(1.0 / (aboveToken * slope + 1.0 / count));
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>我们看图理解这个公式。</p>
|
||||
@@ -835,9 +640,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + 1.0 / count));
|
||||
// 1.0 / 生产令牌间隔时间 = 当前 1 秒所能生产的令牌数量
|
||||
|
||||
double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当前生产令牌的间隔时间为:</p>
|
||||
@@ -873,9 +675,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
long oldValue = storedTokens.get();
|
||||
|
||||
// 计算新的存储桶存储的令牌数
|
||||
@@ -899,9 +698,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>Sentinel 并不是在每个请求通过时从桶中移除 Token,而是每秒在更新存储桶的令牌数时,再扣除上一秒消耗的令牌数量,上一秒消耗的令牌数量等于上一秒通过的请求数,这就是官方文档所写的每秒会自动掉落令牌。减少每一次请求都使用 CAS 更新令牌桶的令牌数可以降低 Sentinel 对应用性能的影响,这是非常巧妙的做法。</p>
|
||||
@@ -945,9 +741,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
return Math.min(newValue, maxToken);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>其中 (currentTime - lastFilledTime.get()) 为当前时间与上一次生产令牌时间的间隔时间,虽然单位为毫秒,但是已经去掉了毫秒的部分(毫秒部分全为 0)。如果 currentTime - lastFilledTime.get() 等于 1 秒,根据 1 秒等于 1000 毫秒,那么新生成的令牌数(newValue)等于限流阈值(count)。</p>
|
||||
@@ -955,9 +748,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
<pre><code class="language-java">newValue = oldValue + 1000 * count / 1000
|
||||
|
||||
= oldValue + count
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果是很久没有访问的情况下,lastFilledTime 远小于 currentTime,那么第一次生产的令牌数量将等于 maxToken。</p>
|
||||
@@ -993,9 +783,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1003,9 +790,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1021,17 +805,11 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1057,9 +835,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1071,9 +846,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1091,12 +863,6 @@ double warningQps = Math.nextUp(1.0 / (aboveToken * slope + stableInterval));
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
Reference in New Issue
Block a user