mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-11-15 13:43:50 +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 class="current-tab" 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 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">
|
||||
@@ -537,9 +375,6 @@ function hide_canvas() {
|
||||
<p>模拟服务 B 接口的业务代码如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class Match {
|
||||
|
||||
|
||||
|
||||
static class Task implements Runnable {
|
||||
|
||||
private String value;
|
||||
@@ -587,9 +422,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
// 模拟业务场景,从缓存中获取到的字符串
|
||||
@@ -617,9 +449,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>这段代码很简单,就是模拟高并发,观察在 200 个业务线程全部耗尽的情况下,一个简单的判断元素是否存在的业务逻辑执行需要多长时间。把这段代码跑一遍,发现很多执行耗时超过 1500ms,如下图所示。</p>
|
||||
@@ -715,9 +544,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -725,9 +551,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -743,17 +566,11 @@ function hide_canvas() {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -779,9 +596,6 @@ function hide_canvas() {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -793,9 +607,6 @@ function hide_canvas() {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -813,12 +624,6 @@ function hide_canvas() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" 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 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">
|
||||
@@ -547,9 +385,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -557,9 +392,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -575,17 +407,11 @@ function hide_canvas() {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -611,9 +437,6 @@ function hide_canvas() {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -625,9 +448,6 @@ function hide_canvas() {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -645,12 +465,6 @@ function hide_canvas() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" 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 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">
|
||||
@@ -659,9 +497,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -669,9 +504,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -687,17 +519,11 @@ function hide_canvas() {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -723,9 +549,6 @@ function hide_canvas() {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -737,9 +560,6 @@ function hide_canvas() {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -757,12 +577,6 @@ function hide_canvas() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" 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 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">
|
||||
@@ -495,9 +333,6 @@ function hide_canvas() {
|
||||
private volatile long minRt;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如上面代码所示,Bucket 记录一段时间内的各项指标数据用的是一个 LongAdder 数组,LongAdder 保证了数据修改的原子性,并且性能比 AtomicInteger 表现更好。数组的每个元素分别记录一个时间窗口内的请求总数、异常数、总耗时,如下图所示。</p>
|
||||
@@ -517,9 +352,6 @@ public enum MetricEvent {
|
||||
RT // 耗时 对应数组下标为 2
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当需要获取 Bucket 记录总的成功请求数或者异常总数、总的请求处理耗时,可根据事件类型(MetricEvent)从 Bucket 的 LongAdder 数组中获取对应的 LongAdder,并调用 sum 方法获取总数,如下代码所示。</p>
|
||||
@@ -533,9 +365,6 @@ public long get(MetricEvent event) {
|
||||
return counters[event.ordinal()].sum();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当需要 Bucket 记录一个成功请求或者一个异常请求、处理请求的耗时,可根据事件类型(MetricEvent)从 LongAdder 数组中获取对应的 LongAdder,并调用其 add 方法,如下代码所示。</p>
|
||||
@@ -549,9 +378,6 @@ public void add(MetricEvent event, long n) {
|
||||
counters[event.ordinal()].add(n);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h3>滑动窗口</h3>
|
||||
@@ -593,9 +419,6 @@ public void add(MetricEvent event, long n) {
|
||||
return (int) (timeId % array.length());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>calculateTimeIdx 方法中,取余数就是实现循环利用数组。如果想要获取连续的一分钟的 Bucket 数据,就不能简单的从头开始遍历数组,而是指定一个开始时间和结束时间,从开始时间戳开始计算 Bucket 存放在数组中的下标,然后循环每次将开始时间戳加上 1 秒,直到开始时间等于结束时间。</p>
|
||||
@@ -623,9 +446,6 @@ public void add(MetricEvent event, long n) {
|
||||
return timeMillis - timeMillis % windowLengthInMs;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h3>WindowWrap</h3>
|
||||
@@ -669,17 +489,11 @@ public void add(MetricEvent event, long n) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如前面所说,假设 Bucket 以秒为单位统计指标数据,那么 Bucket 统计的就是一秒内的请求总数、异常总数这些指标数据。换算为毫秒为单位,比如时间窗口为 [1577017699000,1577017699999),那么 1577017699000 就被称为该时间窗口的开始时间(windowStart)。一秒转为毫秒是 1000,所以 1000 就称为窗口时间大小(windowLengthInMs)。</p>
|
||||
|
||||
<pre><code class="language-txt">windowStart + windowLengthInMs = 时间窗口的结束时间
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>只要知道时间窗口的开始时间和窗口时间大小,只需要给定一个时间戳,就能知道该时间戳是否在 Bucket 的窗口时间内,代码实现如下。</p>
|
||||
@@ -701,9 +515,6 @@ public void add(MetricEvent event, long n) {
|
||||
return windowStart <= timeMillis && timeMillis < windowStart + windowLengthInMs;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h3>通过时间戳定位 Bucket</h3>
|
||||
@@ -741,9 +552,6 @@ public void add(MetricEvent event, long n) {
|
||||
// 计算 bucket 时间窗口的开始时间
|
||||
|
||||
long windowStart = calculateWindowStart(timeMillis);
|
||||
|
||||
|
||||
|
||||
// 从数组中获取 bucket
|
||||
|
||||
while (true) {
|
||||
@@ -819,9 +627,6 @@ public void add(MetricEvent event, long n) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>上面代码实现的是,通过当前时间戳计算出当前时间窗口的 Bucket(New Buket)在数组中的索引(cidx),以及 Bucket 时间窗口的开始时间,通过索引从数组中取得 Bucket(Old Bucket)。</p>
|
||||
@@ -879,9 +684,6 @@ public void add(MetricEvent event, long n) {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -889,9 +691,6 @@ public void add(MetricEvent event, long n) {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -907,17 +706,11 @@ public void add(MetricEvent event, long n) {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -943,9 +736,6 @@ public void add(MetricEvent event, long n) {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -957,9 +747,6 @@ public void add(MetricEvent event, long n) {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -977,12 +764,6 @@ public void add(MetricEvent event, long n) {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" 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 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">
|
||||
@@ -497,9 +335,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ResourceWrapper 有三个字段:</p>
|
||||
@@ -523,9 +358,6 @@ function hide_canvas() {
|
||||
OUT("OUT");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>可以把 IN 和 OUT 简单理解为接收处理请求与发送请求。当接收到别的服务或者前端发来的请求,那么 entryType 为 IN;当向其他服务发起请求时,那么 entryType 就为 OUT。例如,在消费端向服务提供者发送请求,当请求失败率达到多少时触发熔断降级,那么服务消费端为实现熔断降级就需要统计资源的 OUT 类型流量。</p>
|
||||
@@ -545,9 +377,6 @@ function hide_canvas() {
|
||||
public static final int COMMON_DB_SQL = 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -621,9 +450,6 @@ function hide_canvas() {
|
||||
void reset(); // 重置滑动窗口
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>它的几个实现类:DefaultNode、ClusterNode、EntranceNode、StatisticNode 的关系如下图所示。</p>
|
||||
@@ -649,9 +475,6 @@ function hide_canvas() {
|
||||
private LongAdder curThreadNum = new LongAdder();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如代码所示,一个 StatisticNode 包含一个秒级和一个分钟级的滑动窗口,以及并行线程数计数器。秒级滑动窗口用于统计实时的 QPS,分钟级的滑动窗口用于保存最近一分钟内的历史指标数据,并行线程计数器用于统计当前并行占用的线程数。</p>
|
||||
@@ -675,9 +498,6 @@ function hide_canvas() {
|
||||
rollingCounterInMinute.addRT(rt);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>获取前一秒被 Sentinel 拒绝的请求总数从分钟级滑动窗口获取,代码如下:</p>
|
||||
@@ -689,9 +509,6 @@ public double previousBlockQps() {
|
||||
return this.rollingCounterInMinute.previousWindowBlock();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>而获取当前一秒内已经被 Sentinel 拒绝的请求总数则从秒级滑动窗口获取,代码如下:</p>
|
||||
@@ -703,9 +520,6 @@ public double blockQps() {
|
||||
return rollingCounterInSecond.block() / rollingCounterInSecond.getWindowIntervalInSec();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>获取最小耗时也是从秒级的滑动窗口取的,代码如下:</p>
|
||||
@@ -719,9 +533,6 @@ public double blockQps() {
|
||||
return rollingCounterInSecond.minRt();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>由于方法比较多,这里就不详细介绍每个方法的实现了。</p>
|
||||
@@ -741,9 +552,6 @@ public double blockQps() {
|
||||
private volatile Set<Node> childList = new HashSet<>();
|
||||
|
||||
private ClusterNode clusterNode;
|
||||
|
||||
|
||||
|
||||
public DefaultNode(ResourceWrapper id, ClusterNode clusterNode) {
|
||||
|
||||
this.id = id;
|
||||
@@ -753,9 +561,6 @@ public double blockQps() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如代码所示,DefaultNode 是 StatisticNode 的子类,构造方法要求传入资源 ID,表示该 Node 用于统计哪个资源的实时指标数据,指标数据统计则由父类 StatisticNode 完成。</p>
|
||||
@@ -807,9 +612,6 @@ try {
|
||||
ContextUtil.exit();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如上代码所示,doBusiness 业务方法被 Sentinel 保护,当 doBusiness 方法被多层保护时,就可能对同一个资源创建多个 DefaultNode。一个资源理论上可能有多个 DefaultNode,是否有多个 DefaultNode 取决于是否存在多个 Context,即当前调用链路上是否多次调用 ContextUtil#enter 方法,是否每次调用 ContextUtil#enter 方法都会创建一个 Context。</p>
|
||||
@@ -837,9 +639,6 @@ try {
|
||||
// 控制并发修改 originCountMap 用的锁
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
|
||||
|
||||
public ClusterNode(String name, int resourceType) {
|
||||
|
||||
this.name = name;
|
||||
@@ -849,9 +648,6 @@ try {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ClusterNode 字段说明:</p>
|
||||
@@ -871,21 +667,12 @@ try {
|
||||
<p>EntranceNode 是一个特殊的 Node,它继承 DefaultNode,用于维护一颗树,从根节点到每个叶子节点都是不同请求的调用链路,所经过的每个节点都对应着调用链路上被 Sentinel 保护的资源,一个请求调用链路上的节点顺序正是资源被访问的顺序。</p>
|
||||
|
||||
<pre><code class="language-java">public class EntranceNode extends DefaultNode {
|
||||
|
||||
|
||||
|
||||
public EntranceNode(ResourceWrapper id, ClusterNode clusterNode) {
|
||||
|
||||
super(id, clusterNode);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>在一个 Web MVC 应用中,每个接口就是一个资源,Sentinel 通过 Spring MVC 拦截器拦截每个接口的入口,统一创建名为“sentinel_spring_web_context”的 Context,名称相同的 Context 都使用同一个 EntranceNode。一个 Web 应用可能有多个接口,而 childList 就用于存储每个接口对应的 DefaultNode。</p>
|
||||
@@ -909,9 +696,6 @@ try {
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>EntranceNode、DefaultNode、ClusterNode 与滑动窗口的关系如下图所示:</p>
|
||||
@@ -961,9 +745,6 @@ try {
|
||||
// private final boolean async;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1003,9 +784,6 @@ try {
|
||||
protected ResourceWrapper resourceWrapper;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>CtEntry 是 Entry 的直接子类,后面分析源码时,我们所说 Entry 皆指 CtEntry。CtEntry 中声明的字段信息如下代码所示。</p>
|
||||
@@ -1029,9 +807,6 @@ try {
|
||||
protected Context context;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>CtEntry 用于维护父子 Entry,每一次调用 SphU#entry 方法都会创建一个 CtEntry。如果服务 B 在处理一个请求的路径上会多次调用 SphU#entry,那么这些 CtEntry 会构成一个双向链表。在每次创建 CtEntry,都会将 Context.curEntry 设置为这个新的 CtEntry,双向链表的作用就是在调用 CtEntry#exit 方法时,能够将 Context.curEntry 还原为上一个资源的 CtEntry。</p>
|
||||
@@ -1111,9 +886,6 @@ try {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1121,9 +893,6 @@ try {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1139,17 +908,11 @@ try {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1175,9 +938,6 @@ try {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1189,9 +949,6 @@ try {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1209,12 +966,6 @@ try {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" 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 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">
|
||||
@@ -505,9 +343,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如何去掉 ProcessorSlot 或者添加自定义的 ProcessorSlot,下一篇再作介绍。</p>
|
||||
@@ -533,9 +368,6 @@ function hide_canvas() {
|
||||
void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>例如实现熔断降级功能的 DegradeSlot,其在 entry 方法中检查资源当前统计的指标数据是否达到配置的熔断降级规则的阈值,如果是则触发熔断,抛出一个 DegradeException(必须是 BlockException 的子类),而 exit 方法什么也不做。</p>
|
||||
@@ -567,9 +399,6 @@ function hide_canvas() {
|
||||
// 当前节点的下一个节点
|
||||
|
||||
private AbstractLinkedProcessorSlot<?> next = null;
|
||||
|
||||
|
||||
|
||||
public void setNext(AbstractLinkedProcessorSlot<?> next) {
|
||||
|
||||
this.next = next;
|
||||
@@ -577,9 +406,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>实现责任链调用是由前一个 AbstractLinkedProcessorSlot 调用 fireEntry 方法或者 fireExit 方法,在 fireEntry 与 fireExit 方法中调用下一个 AbstractLinkedProcessorSlot(next)的 entry 方法或 exit 方法。AbstractLinkedProcessorSlot 的 fireEntry 与 fireExit 方法的实现源码如下:</p>
|
||||
@@ -589,17 +415,11 @@ function hide_canvas() {
|
||||
// 当前节点的下一个节点
|
||||
|
||||
private AbstractLinkedProcessorSlot<?> next = null;
|
||||
|
||||
|
||||
|
||||
public void setNext(AbstractLinkedProcessorSlot<?> next) {
|
||||
|
||||
this.next = next;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
|
||||
@@ -617,9 +437,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
|
||||
@@ -635,9 +452,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ProcessorSlotChain 也继承 AbstractLinkedProcessorSlot,只不过加了两个方法:提供将一个 ProcessorSlot 添加到链表的头节点的 addFirst 方法,以及提供将一个 ProcessorSlot 添加到链表末尾的 addLast 方法。</p>
|
||||
@@ -649,9 +463,6 @@ function hide_canvas() {
|
||||
// first,指向链表头节点
|
||||
|
||||
AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)
|
||||
@@ -661,9 +472,6 @@ function hide_canvas() {
|
||||
super.fireEntry(context, resourceWrapper, t, count, prioritized, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
|
||||
@@ -671,17 +479,11 @@ function hide_canvas() {
|
||||
super.fireExit(context, resourceWrapper, count, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
// end,指向链表尾节点
|
||||
|
||||
AbstractLinkedProcessorSlot<?> end = first;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor) {
|
||||
@@ -697,9 +499,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
|
||||
@@ -709,9 +508,6 @@ function hide_canvas() {
|
||||
end = protocolProcessor;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 调用头节点的 entry 方法
|
||||
|
||||
@Override
|
||||
@@ -735,13 +531,7 @@ function hide_canvas() {
|
||||
first.exit(context, resourceWrapper, count, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h3>Sentinel 中的责任链模式</h3>
|
||||
@@ -759,9 +549,6 @@ function hide_canvas() {
|
||||
private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap
|
||||
|
||||
= new HashMap<ResourceWrapper, ProcessorSlotChain>();
|
||||
|
||||
|
||||
|
||||
private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
|
||||
|
||||
throws BlockException {
|
||||
@@ -795,9 +582,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h3>Sentinel 的整体工作流程</h3>
|
||||
@@ -837,9 +621,6 @@ try {
|
||||
ContextUtil.exit();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>上面代码我们分为五步分析:</p>
|
||||
@@ -867,9 +648,6 @@ try {
|
||||
return trueEnter(name, origin);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected static Context trueEnter(String name, String origin) {
|
||||
|
||||
Context context = contextHolder.get();
|
||||
@@ -931,9 +709,6 @@ try {
|
||||
return context;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ContextUtil 使用 ThreadLocal 存储当前调用链路的 Context,例如 Web MVC 应用中使用 Sentinel 的 Spring MVC 适配器,在接收到请求时,调用 ContextUtil#enter 方法会创建一个名为“sentinel_spring_web_context”的 Context,并且如果是首次创建还会为所有名为“sentinel_spring_web_context”的 Context 创建一个 EntranceNode。</p>
|
||||
@@ -983,9 +758,6 @@ try {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如上代码所示,traceExceptionToNode 方法中首先获取当前资源的 ClusterNode,然后调用 ClusterNode#trace 方法记录异常。因为一个资源只创建一个 ProcessorSlotChain,一个 ProcessorSlotChain 只创建 ClusterBuilderSlot,一个 ClusterBuilderSlot 只创建一个 ClusterNode,所以一个资源对应一个 ClusterNode,这个 ClusterNode 就是用来统计一个资源的全局指标数据的,熔断降级与限流降级都有使用到这个 ClusterNode。</p>
|
||||
@@ -1009,9 +781,6 @@ try {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h4><strong>调用 Entry#exit 方法</strong></h4>
|
||||
@@ -1065,9 +834,6 @@ try {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>CtSph 在创建 CtEntry 时,将资源的 ProcessorSlotChain 赋值给了 CtEntry,所以在调用 CtEntry#exit 方法时,CtEntry 能够拿到当前资源的 ProcessorSlotChain,并调用 ProcessorSlotChain 的 exit 方法完成一次单向链表的 exit 方法调用。其过程与 ProcessorSlotChain 的一次 entry 方法的调用过程一样,因此不做分析。</p>
|
||||
@@ -1089,9 +855,6 @@ try {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果 Context.curEntry 为空,则说明所有 SphU#entry 都对应执行了一次 Entry#exit 方法,此时就可以将 Context 从 ThreadLocal 中移除。</p>
|
||||
@@ -1115,9 +878,6 @@ try {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1125,9 +885,6 @@ try {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1143,17 +900,11 @@ try {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1179,9 +930,6 @@ try {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1193,9 +941,6 @@ try {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1213,12 +958,6 @@ try {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" 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 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">
|
||||
@@ -477,9 +315,6 @@ function hide_canvas() {
|
||||
void login(String username,String password);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>第二步:编写接口实现类</strong></p>
|
||||
@@ -495,9 +330,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>现在我们不想搞那么麻烦,比如我们可以直接使用 Spring MVC 的拦截器实现用户鉴权,那么可以提供一个 SpringLoginService。</p>
|
||||
@@ -511,9 +343,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>第三步:通过配置使用 SpringLoginService 或 ShiroLoginService。</strong></p>
|
||||
@@ -527,9 +356,6 @@ function hide_canvas() {
|
||||
<p>文件:/resources/META-INF/services/接口名称,填写的内容为接口的实现类,多个实现类使用换行分开。</p>
|
||||
|
||||
<pre><code>com.wujiuye.spi.ShiroLoginService
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>第四步:编写 main 方法测试使用 Java SPI 加载 LoginService。</strong></p>
|
||||
@@ -549,9 +375,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ServiceLoader(服务加载器)是 Java 提供的 SPI 机制的实现,调用 load 方法传入接口名就能获取到一个 ServiceLoader 实例,此时配置文件中注册的实现类是还没有加载到 JVM 的,只有通过 Iterator 遍历获取的时候,才会去加载实现类与实例化实现类。</p>
|
||||
@@ -567,9 +390,6 @@ function hide_canvas() {
|
||||
<p>com.alibaba.csp.sentinel.init.InitFunc 文件的默认配置如下:</p>
|
||||
|
||||
<pre><code class="language-txt"> com.alibaba.csp.sentinel.metric.extension.MetricCallbackInit
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>com.alibaba.csp.sentinel.slotchain.SlotChainBuilder 文件的默认配置如下:</p>
|
||||
@@ -577,9 +397,6 @@ function hide_canvas() {
|
||||
<pre><code class="language-java"> # Default slot chain builder
|
||||
|
||||
com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ServiceLoader 可加载接口配置文件中配置的所有实现类并且使用反射创建对象,但是否全部加载以及实例化还是由使用者自己决定。Sentinel 的 core 模块使用 Java SPI 机制加载 InitFunc 与 SlotChainBuilder 的实现上稍有不同,如果 InitFunc 接口的配置文件注册了多个实现类,那么这些注册的 InitFunc 实现类都会被 Sentinel 加载、实例化,且都会被使用,但 SlotChainBuilder 不同,如果注册多个实现类,Sentinel 只会加载和使用第一个。</p>
|
||||
@@ -625,9 +442,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>Sentinel 加载 InitFunc 则不同,因为 Sentinel 允许存在多个初始化方法。InitFunc 可用于初始化配置限流、熔断规则,但在 Web 项目中我们基本不会使用它,更多的是通过监听 Spring 容器刷新完成事件再去初始化为 Sentinel 配置规则,如果使用动态数据源还可在监听到动态配置改变事件时重新加载规则,所以 InitFunc 我们基本使用不上。</p>
|
||||
@@ -635,9 +449,6 @@ function hide_canvas() {
|
||||
<p>Sentinel 使用 ServiceLoader 加载注册的 InitFunc 实现代码如下:</p>
|
||||
|
||||
<pre><code class="language-java">public final class InitExecutor {
|
||||
|
||||
|
||||
|
||||
public static void doInit() {
|
||||
|
||||
try {
|
||||
@@ -677,9 +488,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>虽然 InitFunc 接口与 SlotChainBuilder 接口的配置文件在 sentinel-core 模块下,但我们不需要去修改 Sentinel 的源码,不需要修改 sentinel-core 模块下的接口配置文件,而只需要在当前项目的 /resource/META-INF/services 目录下创建一个与接口全名相同名称的配置文件,并在配置文件中添加接口的实现类即可。项目编译后不会覆盖 sentinel-core 模块下的相同名称的配置文件,而是将两个配置文件合并成一个配置文件。</p>
|
||||
@@ -691,9 +499,6 @@ function hide_canvas() {
|
||||
<p>Sentinel 默认使用的 SlotChainBuilder 是 DefaultSlotChainBuilder,其源码如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class DefaultSlotChainBuilder implements SlotChainBuilder {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public ProcessorSlotChain build() {
|
||||
@@ -719,13 +524,7 @@ function hide_canvas() {
|
||||
return chain;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>DefaultSlotChainBuilder 构造的 ProcessorSlotChain 注册了 NodeSelectorSlot、ClusterBuilderSlot、LogSlot、StatisticSlot、AuthoritySlot、SystemSlot、FlowSlot、DegradeSlot,但这些 ProcessorSlot 并非都是必须的,如果注册的这些 ProcessorSlot 有些我们用不到,那么我们可以自己实现一个 SlotChainBuilder,自己构造 ProcessorSlotChain。例如,我们可以将 LogSlot、AuthoritySlot、SystemSlot 去掉。</p>
|
||||
@@ -733,9 +532,6 @@ function hide_canvas() {
|
||||
<p>第一步,编写 MySlotChainBuilder,实现 SlotChainBuilder 接口,代码如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class MySlotChainBuilder implements SlotChainBuilder {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public ProcessorSlotChain build() {
|
||||
@@ -755,21 +551,12 @@ function hide_canvas() {
|
||||
return chain;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>第二步,在当前项目的 /resources/META-INF/services 目录下添加名为 com.alibaba.csp.sentinel.slotchain.SlotChainBuilder 的接口配置文件,并在配置文件中注册 MySlotChainBuilder。</p>
|
||||
|
||||
<pre><code class="language-txt">com.wujiuye.sck.provider.config.MySlotChainBuilder
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>在构造 ProcessorSlotChain 时,需注意 ProcessorSlot 的注册顺序,例如,NodeSelectorSlot 需作为 ClusterBuilderSlot 的前驱节点,ClusterBuilderSlot 需作为 StatisticSlot 的前驱节点,否则 Sentinel 运行会出现 bug。但你可以将 DegradeSlot 放在 FlowSlot 的前面,这就是我们上一篇说到的 ProcessorSlot 的排序。</p>
|
||||
@@ -797,9 +584,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -807,9 +591,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -825,17 +606,11 @@ function hide_canvas() {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -861,9 +636,6 @@ function hide_canvas() {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -875,9 +647,6 @@ function hide_canvas() {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -895,12 +664,6 @@ function hide_canvas() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" 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 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">
|
||||
@@ -519,9 +357,6 @@ function hide_canvas() {
|
||||
fireEntry(context, resourceWrapper, node, count, prioritized, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 出口方法什么也不做
|
||||
|
||||
@Override
|
||||
@@ -533,9 +368,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如源码所示,map 字段是一个非静态字段,意味着每个 NodeSelectorSlot 都有一个 map。由于一个资源对应一个 ProcessorSlotChain,而一个 ProcessorSlotChain 只创建一个 NodeSelectorSlot,并且 map 缓存 DefaultNode 使用的 key 并非资源 ID,而是 Context.name,所以 map 的作用是缓存针对同一资源为不同调用链路入口创建的 DefaultNode。</p>
|
||||
@@ -549,9 +381,6 @@ function hide_canvas() {
|
||||
<p>NodeSelectorSlot#entry 方法最难以理解的就是实现绑定调用树这行代码:</p>
|
||||
|
||||
<pre><code class="language-java">((DefaultNode) context.getLastNode()).addChild(node);
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>这行代码分两种情况分析更容易理解,我们就以 Sentinel 提供的 Demo 为例进行分析。</p>
|
||||
@@ -563,9 +392,6 @@ function hide_canvas() {
|
||||
<pre><code class="language-java">@RestController
|
||||
|
||||
public class WebMvcTestController {
|
||||
|
||||
|
||||
|
||||
@GetMapping("/hello")
|
||||
|
||||
public String apiHello() throws BlockException {
|
||||
@@ -577,9 +403,6 @@ public class WebMvcTestController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>我们不需要添加任何规则,只是为了调试 Sentinel 的源码。将 demo 启动起来后,在浏览器访问“/hello”接口,在 NodeSelectorSlot#entry 方法的绑定调用树这一行代码下断点,观察此时 Context 的字段信息。正常情况下我们可以看到如下图所示的结果。</p>
|
||||
@@ -603,9 +426,6 @@ public class WebMvcTestController {
|
||||
/
|
||||
|
||||
DefaultNode (resource name: GET:/hello)
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果我们现在再访问 Demo 的其他接口,例如访问“/err”接口,那么生成的调用树就会变成如下:</p>
|
||||
@@ -619,9 +439,6 @@ DefaultNode (resource name: GET:/hello)
|
||||
/ \
|
||||
|
||||
DefaultNode (resource name: GET:/hello) DefaultNode (resource name: GET:/err)
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>Context.entranceNode 将会存储 Web 项目的所有资源(接口)的 DefaultNode。</p>
|
||||
@@ -637,9 +454,6 @@ DefaultNode (resource name: GET:/hello) DefaultNode (resource name: GE
|
||||
<pre><code class="language-java">@RestController
|
||||
|
||||
public class WebMvcTestController {
|
||||
|
||||
|
||||
|
||||
@GetMapping("/hello")
|
||||
|
||||
public String apiHello() throws BlockException {
|
||||
@@ -685,9 +499,6 @@ public class WebMvcTestController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>我们可将 doBusiness 方法看成是远程调用,例如调用第三方的接口,接口名称为“http://wujiuye.com/hello2”,使用 POST 方式调用,那么我们可以使用“POST:http://wujiuye.com/hello2”作为资源名称,并将流量类型设置为 OUT 类型。上下文名称取名为"my_context"。</p>
|
||||
@@ -713,9 +524,6 @@ public class WebMvcTestController {
|
||||
/
|
||||
|
||||
DefaultNode (POST:/hello2)
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>此时,当前调用链路上也已经存在两个 CtEntry,这两个 CtEntry 构造一个双向链表,如下图所示。</p>
|
||||
@@ -729,9 +537,6 @@ public class WebMvcTestController {
|
||||
<pre><code class="language-java">// 替换 Context.curNode 为当前 DefaultNode
|
||||
|
||||
context.setCurNode(node);
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>替换 Context.curNode 为当前资源 DefaultNode 这行代码就是将当前创建的 DefaultNode 赋值给当前 CtEntry.curNode。对着上图理解就是,将资源“GET:/hello”的 DefaultNode 赋值给第一个 CtEntry.curNode,将资源“POST:http://wujiuye.com/hello2”的 DefaultNode 赋值给第二个 CtEntry.curNode。</p>
|
||||
@@ -755,9 +560,6 @@ context.setCurNode(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>这个例子虽然简单,但也足以说明 Sentinel 构造 CtEntry 双向链表的目的。</p>
|
||||
@@ -781,15 +583,9 @@ context.setCurNode(node);
|
||||
private static volatile Map<ResourceWrapper, ClusterNode> clusterNodeMap = new HashMap<>();
|
||||
|
||||
private static final Object lock = new Object();
|
||||
|
||||
|
||||
|
||||
// 非静态,一个资源对应一个 ProcessorSlotChain,所以一个资源共用一个 ClusterNode
|
||||
|
||||
private volatile ClusterNode clusterNode = null;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
|
||||
@@ -841,9 +637,6 @@ context.setCurNode(node);
|
||||
fireEntry(context, resourceWrapper, node, count, prioritized, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
|
||||
@@ -853,9 +646,6 @@ context.setCurNode(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ClusterBuilderSlot 使用一个 Map 缓存资源的 ClusterNode,并且用一个非静态的字段维护当前资源的 ClusterNode。因为一个资源只会创建一个 ProcessorSlotChain,意味着 ClusterBuilderSlot 也只会创建一个,那么让 ClusterBuilderSlot 持有该资源的 ClusterNode 就可以省去每次都从 Map 中获取的步骤,这当然也是 Sentinel 为性能做出的努力。</p>
|
||||
@@ -875,9 +665,6 @@ context.setCurNode(node);
|
||||
private Map<String, StatisticNode> originCountMap = new HashMap<>();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果上游服务在调用当前服务的接口传递 origin 字段过来,例如可在 http 请求头添加“S-user”参数,或者 Dubbo rpc 调用在请求参数列表加上“application”参数,那么 ClusterBuilderSlot 就会为 ClusterNode 创建一个 StatisticNode,用来统计当前资源被远程服务调用的指标数据。</p>
|
||||
@@ -925,9 +712,6 @@ context.setCurNode(node);
|
||||
return statisticNode;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>为了便于使用,ClusterBuilderSlot 会将调用来源(origin)的 StatisticNode 赋值给 Context.curEntry.originNode,后续的 ProcessorSlot 可调用 Context#getCurEntry#getOriginNode 方法获取该 StatisticNode。这里我们可以得出一个结论,如果我们自定义的 ProcessorSlot 需要用到调用来源的 StatisticNode,那么在构建 ProcessorSlotChain 时,我们必须要将这个自定义 ProcessorSlot 放在 ClusterBuilderSlot 之后。</p>
|
||||
@@ -951,9 +735,6 @@ context.setCurNode(node);
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -961,9 +742,6 @@ context.setCurNode(node);
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -979,17 +757,11 @@ context.setCurNode(node);
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1015,9 +787,6 @@ context.setCurNode(node);
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1029,9 +798,6 @@ context.setCurNode(node);
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1049,12 +815,6 @@ context.setCurNode(node);
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" 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 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">
|
||||
@@ -473,9 +311,6 @@ function hide_canvas() {
|
||||
<p>StatisticSlot 源码框架如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class StatisticSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
|
||||
@@ -509,9 +344,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
|
||||
@@ -525,9 +357,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -549,9 +378,6 @@ function hide_canvas() {
|
||||
node.increaseThreadNum();
|
||||
|
||||
node.addPassRequest(count);
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果调用来源不为空,也将调用来源的 StatisticNode 的当前并行占用线程数加 1、当前时间窗口被放行的请求数加 1,代码如下:</p>
|
||||
@@ -565,9 +391,6 @@ function hide_canvas() {
|
||||
context.getCurEntry().getOriginNode().addPassRequest(count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果流量类型为 IN,则将资源全局唯一的 ClusterNode 的并行占用线程数、当前时间窗口被放行的请求数都增加 1,代码如下:</p>
|
||||
@@ -581,9 +404,6 @@ function hide_canvas() {
|
||||
Constants.ENTRY_NODE.addPassRequest(count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>回调所有 ProcessorSlotEntryCallback#onPass 方法,代码如下:</p>
|
||||
@@ -595,9 +415,6 @@ function hide_canvas() {
|
||||
handler.onPass(context, resourceWrapper, node, count, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>可调用 StatisticSlotCallbackRegistry#addEntryCallback 静态方法注册 ProcessorSlotEntryCallback,ProcessorSlotEntryCallback 接口的定义如下:</p>
|
||||
@@ -609,9 +426,6 @@ function hide_canvas() {
|
||||
void onBlocked(BlockException ex, Context context, ResourceWrapper resourceWrapper, T param, int count, Object... args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -653,9 +467,6 @@ function hide_canvas() {
|
||||
handler.onPass(context, resourceWrapper, node, count, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>第三种情况:捕获到 BlockException 异常</strong>,BlockException 异常只在需要拒绝请求时抛出。</p>
|
||||
@@ -665,9 +476,6 @@ function hide_canvas() {
|
||||
<pre><code class="language-java"> // Blocked, set block exception to current entry.
|
||||
|
||||
context.getCurEntry().setError(e);
|
||||
|
||||
|
||||
|
||||
// Add block count.
|
||||
|
||||
node.increaseBlockQps(count);
|
||||
@@ -677,9 +485,6 @@ function hide_canvas() {
|
||||
context.getCurEntry().getOriginNode().increaseBlockQps(count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (resourceWrapper.getEntryType() == EntryType.IN) {
|
||||
|
||||
// Add count for global inbound entry node for global statistics.
|
||||
@@ -687,9 +492,6 @@ function hide_canvas() {
|
||||
Constants.ENTRY_NODE.increaseBlockQps(count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Handle block event with registered entry callback handlers.
|
||||
|
||||
for (ProcessorSlotEntryCallback<DefaultNode> handler : StatisticSlotCallbackRegistry.getEntryCallbacks()) {
|
||||
@@ -697,13 +499,7 @@ function hide_canvas() {
|
||||
handler.onBlocked(e, context, resourceWrapper, node, count, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
throw e;
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>StatisticSlot 捕获 BlockException 异常只是为了收集被拒绝的请求,BlockException 异常还是会往上抛出。抛出异常的目的是为了拦住请求,让入口处能够执行到 catch 代码块完成请求被拒绝后的服务降级处理。</p>
|
||||
@@ -717,9 +513,6 @@ function hide_canvas() {
|
||||
<pre><code class="language-java"> // Unexpected error, set error to current entry.
|
||||
|
||||
context.getCurEntry().setError(e);
|
||||
|
||||
|
||||
|
||||
// This should not happen.
|
||||
|
||||
node.increaseExceptionQps(count);
|
||||
@@ -729,9 +522,6 @@ function hide_canvas() {
|
||||
context.getCurEntry().getOriginNode().increaseExceptionQps(count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (resourceWrapper.getEntryType() == EntryType.IN) {
|
||||
|
||||
Constants.ENTRY_NODE.increaseExceptionQps(count);
|
||||
@@ -739,9 +529,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
throw e;
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h4><strong>exit 方法</strong></h4>
|
||||
@@ -809,9 +596,6 @@ function hide_canvas() {
|
||||
fireExit(context, resourceWrapper, count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>exit 方法中通过 Context 可获取当前资源的 DefaultNode,如果 entry 方法中未出现异常,那么说明请求是正常完成的,在请求正常完成情况下需要记录请求的执行耗时以及响应是否成功,可将当前时间减去调用链路上当前 Entry 的创建时间作为请求的执行耗时。</p>
|
||||
@@ -825,9 +609,6 @@ function hide_canvas() {
|
||||
......
|
||||
|
||||
private ClusterNode clusterNode;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void addPassRequest(int count) {
|
||||
@@ -839,9 +620,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>记录某项指标数据指的是:针对当前请求,记录当前请求的某项指标数据,例如请求被放行、请求被拒绝、请求的执行耗时等。</p>
|
||||
@@ -865,9 +643,6 @@ function hide_canvas() {
|
||||
rollingCounterInMinute.addRT(rt);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>rollingCounterInSecond 是一个秒级的滑动窗口,rollingCounterInMinute 是一个分钟级的滑动窗口,类型为 ArrayMetric。分钟级的滑动窗口一共有 60 个 MetricBucket,每个 MetricBucket 都被 WindowWrap 包装,每个 MetricBucket 统计一秒钟内的各项指标数据,如下图所示:</p>
|
||||
@@ -893,9 +668,6 @@ function hide_canvas() {
|
||||
OCCUPIED_PASS
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -957,9 +729,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -967,9 +736,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -985,17 +751,11 @@ function hide_canvas() {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1021,9 +781,6 @@ function hide_canvas() {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1035,9 +792,6 @@ function hide_canvas() {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1055,12 +809,6 @@ function hide_canvas() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" href="/专栏/深入理解 Sentinel(完)/10 限流降级与流量效果控制器(上).md.html">10 限流降级与流量效果控制器(上).md.html</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/11 限流降级与流量效果控制器(中).md.html">11 限流降级与流量效果控制器(中).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a 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">
|
||||
@@ -485,9 +323,6 @@ function hide_canvas() {
|
||||
boolean passCheck(Context context, DefaultNode node, int count, Object... args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -513,9 +348,6 @@ function hide_canvas() {
|
||||
// ....
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -577,9 +409,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -619,9 +448,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -647,9 +473,6 @@ function hide_canvas() {
|
||||
this(new FlowRuleChecker());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 规则生产者,一个 Function
|
||||
|
||||
private final Function<String, Collection<FlowRule>> ruleProvider = new Function<String, Collection<FlowRule>>() {
|
||||
@@ -667,9 +490,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
|
||||
@@ -691,9 +511,6 @@ function hide_canvas() {
|
||||
checker.checkFlow(ruleProvider, resource, context, node, count, prioritized);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
|
||||
@@ -703,9 +520,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>FlowSlot 在构造方法中创建 FlowRuleChecker,并在 entry 方法中调用 FlowRuleChecker#checkFlow 方法判断是否需要拦截当前请求。在调用 FlowRuleChecker#checkFlow 方法时传入了一个 Function 接口实例,FlowRuleChecker 可调用该 Function 的 apply 方法从 FlowRuleManager 获取资源的所有规则配置,当然,最终还是调用 FlowRuleManager#getFlowRuleMap 方法从 FlowRuleManager 获取。</p>
|
||||
@@ -749,9 +563,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>checkFlow 方法我们分三步分析:</p>
|
||||
@@ -793,9 +604,6 @@ function hide_canvas() {
|
||||
return passLocalCheck(rule, context, node, acquireCount, prioritized);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -833,9 +641,6 @@ function hide_canvas() {
|
||||
.canPass(selectedNode, acquireCount, prioritized);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -917,9 +722,6 @@ function hide_canvas() {
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果当前限流规则的 limitApp 为 default,则说明该限流规则对任何调用来源都生效,针对所有调用来源限流,否则只针对指定调用来源限流。</p>
|
||||
@@ -989,9 +791,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -999,9 +798,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1017,17 +813,11 @@ function hide_canvas() {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1053,9 +843,6 @@ function hide_canvas() {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1067,9 +854,6 @@ function hide_canvas() {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1087,12 +871,6 @@ function hide_canvas() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 class="current-tab" href="/专栏/深入理解 Sentinel(完)/11 限流降级与流量效果控制器(中).md.html">11 限流降级与流量效果控制器(中).md.html</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a 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() {
|
||||
boolean canPass(Node node, int acquireCount);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -619,9 +454,6 @@ function hide_canvas() {
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ol>
|
||||
@@ -661,9 +493,6 @@ flowRule.setMaxQueueingTimeMs(1000);
|
||||
flowRule.setResource("GET:/hello");
|
||||
|
||||
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>RateLimiterController 的字段和构造方法源码如下:</p>
|
||||
@@ -675,9 +504,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
private final double count;
|
||||
|
||||
private final AtomicLong latestPassedTime = new AtomicLong(-1);
|
||||
|
||||
|
||||
|
||||
public RateLimiterController(int timeOut, double count) {
|
||||
|
||||
this.maxQueueingTimeMs = timeOut;
|
||||
@@ -687,9 +513,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -779,9 +602,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>1. 计算队列中连续的两个请求的通过时间的间隔时长</strong></p>
|
||||
@@ -821,9 +641,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
<p>计算请求通过的时间间隔算法如下:</p>
|
||||
|
||||
<pre><code class="language-java">long costTime = Math.round(1.0 * (acquireCount) / count * 1000);
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>假设限流 QPS 阈值为 1200,当 acquireCount 等于 1 时,costTime=1/1200*1000,这个结果是少于 1 毫秒的,使用 Math.round 取整后值为 1,而当 QPS 阈值越大,计算结果小于 0.5 时,Math.round 取整后值就变为 0。Sentinel 支持的最小等待时间单位是毫秒,这可能是出于性能的考虑。当限流阈值超过 1000 后,如果 costTime 计算结果不少于 0.5,则间隔时间都是 1 毫秒,这相当于还是限流 1000QPS;而当 costTime 计算结果小于 0.5 时,经过 Math.round 取整后值为 0,即请求间隔时间为 0 毫秒,也就是不排队等待,此时限流规则就完全无效了,配置等于没有配置。</p>
|
||||
@@ -847,9 +664,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -857,9 +671,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -875,17 +686,11 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -911,9 +716,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -925,9 +727,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -945,12 +744,6 @@ FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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 href="/专栏/深入理解 Sentinel(完)/12 限流降级与流量效果控制器(下).md.html">12 限流降级与流量效果控制器(下).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
<a class="current-tab" 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">
|
||||
@@ -491,9 +329,6 @@ function hide_canvas() {
|
||||
private final AtomicBoolean cut = new AtomicBoolean(false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -549,9 +384,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>DegradeRuleManager 首先根据资源名称获取配置的熔断降级规则,然后遍历熔断降级规则,调用 DegradeRule#passCheck 方法将检查是否需要触发熔断的逻辑交给 DegradeRule 完成。如果对一个资源配置多个熔断降级规则,那么只要有一个熔断降级规则满足条件,就会触发熔断。</p>
|
||||
@@ -661,9 +493,6 @@ function hide_canvas() {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ol>
|
||||
@@ -693,9 +522,6 @@ function hide_canvas() {
|
||||
<pre><code class="language-java">// 数组大小为 60,窗口时间长度为 1000 毫秒
|
||||
|
||||
private transient Metric rollingCounterInMinute = new ArrayMetric(60, 60 * 1000, false);
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public long totalException() {
|
||||
@@ -705,9 +531,6 @@ public long totalException() {
|
||||
return rollingCounterInMinute.exception();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>也因如此,DEGRADE_GRADE_EXCEPTION_COUNT 这个熔断降级策略似乎使用场景不多,笔者也未曾使用过。</p>
|
||||
@@ -737,9 +560,6 @@ public long totalException() {
|
||||
private long maxThread = -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -847,9 +667,6 @@ public long totalException() {
|
||||
checkSystemStatus.set(checkStatus);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h4><strong>系统自适应限流判断流程</strong></h4>
|
||||
@@ -937,9 +754,6 @@ public long totalException() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -999,9 +813,6 @@ public long totalException() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1029,9 +840,6 @@ public long totalException() {
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1095,9 +903,6 @@ public long totalException() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1105,9 +910,6 @@ public long totalException() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1123,17 +925,11 @@ public long totalException() {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1159,9 +955,6 @@ public long totalException() {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1173,9 +966,6 @@ public long totalException() {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1193,12 +983,6 @@ public long totalException() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 href="/专栏/深入理解 Sentinel(完)/12 限流降级与流量效果控制器(下).md.html">12 限流降级与流量效果控制器(下).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/深入理解 Sentinel(完)/13 熔断降级与系统自适应限流.md.html">13 熔断降级与系统自适应限流.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
<a class="current-tab" 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">
|
||||
@@ -491,9 +329,6 @@ function hide_canvas() {
|
||||
private int strategy = RuleConstant.AUTHORITY_WHITE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -523,9 +358,6 @@ rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
|
||||
rule.setLimitApp("serviceA,serviceC");
|
||||
|
||||
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>上述规则用于限制资源 "GET:/hello" 只允许服务 A 和服务 C 访问。</p>
|
||||
@@ -539,9 +371,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
<p>AuthoritySlot 的实现源码如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class AuthoritySlot extends AbstractLinkedProcessorSlot<DefaultNode> {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)
|
||||
@@ -553,9 +382,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
fireEntry(context, resourceWrapper, node, count, prioritized, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
|
||||
@@ -563,9 +389,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
fireExit(context, resourceWrapper, count, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void checkBlackWhiteAuthority(ResourceWrapper resource, Context context) throws AuthorityException {
|
||||
|
||||
// (1)
|
||||
@@ -603,9 +426,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -693,9 +513,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>整个方法都比较简单,首先是从当前 Context 获取调用来源的名称,只有在调用来源不为空且规则配置了黑名单或者白名单的情况下,才会走黑白名单的过滤逻辑,这也说明,要实现黑白名单限流的前提是,每个服务消费端在发起请求时都必须要携带自身服务的名称,这取决于 Sentinel 主流框架适配器;其次,Sentinel 通过使用 indexOf 先简单匹配一次黑名单或白名单,再切割黑名单或白名单数组实现精确匹配,这有助于提升性能;如果当前请求来源存在名单中,则根据策略判断这份名称是黑名单还是白名单,再决定是否需要拒绝请求。</p>
|
||||
@@ -727,23 +544,14 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
<p>ParamMapBucket 的源码如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class ParamMapBucket {
|
||||
|
||||
|
||||
|
||||
// 数组类型为 CacheMap<Object, AtomicInteger>
|
||||
|
||||
private final CacheMap<Object, AtomicInteger>[] data;
|
||||
|
||||
|
||||
|
||||
public ParamMapBucket() {
|
||||
|
||||
this(DEFAULT_MAX_CAPACITY);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ParamMapBucket(int capacity) {
|
||||
|
||||
RollingParamEvent[] events = RollingParamEvent.values();
|
||||
@@ -761,13 +569,7 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -793,25 +595,16 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
// ....
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Map<Object, Double> getTopValues(RollingParamEvent event, int number) {
|
||||
|
||||
// .....
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public long getRollingSum(RollingParamEvent event, Object value) {
|
||||
|
||||
// .....
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public double getRollingAvg(RollingParamEvent event, Object value) {
|
||||
|
||||
// ....
|
||||
@@ -819,9 +612,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -853,21 +643,12 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
<p>ParameterMetric 有三个静态字段,源码如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class ParameterMetric {
|
||||
|
||||
|
||||
|
||||
private final Map<ParamFlowRule, CacheMap<Object, AtomicLong>> ruleTimeCounters = new HashMap<>();
|
||||
|
||||
private final Map<ParamFlowRule, CacheMap<Object, AtomicLong>> ruleTokenCounter = new HashMap<>();
|
||||
|
||||
private final Map<Integer, CacheMap<Object, AtomicInteger>> threadCountMap = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -887,9 +668,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
private static final Map<String, ParameterMetric> metricsMap = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
|
||||
|
||||
|
||||
public static void initParamMetricsFor(ResourceWrapper resourceWrapper,ParamFlowRule rule) {
|
||||
|
||||
if (resourceWrapper == null || resourceWrapper.getName() == null) {
|
||||
@@ -927,9 +705,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>initParamMetricsFor 方法用于为资源创建 ParameterMetric 并初始化,该方法在资源被访问时由 ParamFlowSlot 调用,并且该方法只在为资源配置了参数限流规则的情况下被调用。</p>
|
||||
@@ -939,9 +714,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
<p>sentinel-parameter-flow-control 模块通过 Java SPI 注册自定义的 SlotChainBuilder,即注册 HotParamSlotChainBuilder,将 ParamFlowSlot 放置在 StatisticSlot 的后面,这个 ParamFlowSlot 就是实现热点参数限流功能的切入点。</p>
|
||||
|
||||
<pre><code class="language-java">public class ParamFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
|
||||
@@ -961,9 +733,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
fireEntry(context, resourceWrapper, node, count, prioritized, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
|
||||
@@ -973,9 +742,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>既然是参数限流,那么肯定是需要能够拿到参数了,而 ProcessorSlot#entry 方法的最后一个参数就是请求传递过来的参数,通过 SphU#entry 方法一层层往下传递。例如:</p>
|
||||
@@ -1019,9 +785,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当 SphU#entry 调用到 ParamFlowSlot#entry 方法时,ParamFlowSlot 调用 checkFlow 方法判断是否需要限流。checkFlow 方法的实现如下:</p>
|
||||
@@ -1049,15 +812,9 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
for (ParamFlowRule rule : rules) {
|
||||
|
||||
applyRealParamIdx(rule, args.length);
|
||||
|
||||
|
||||
|
||||
// Initialize the parameter metrics.
|
||||
|
||||
ParameterMetricStorage.initParamMetricsFor(resourceWrapper, rule);
|
||||
|
||||
|
||||
|
||||
if (!ParamFlowChecker.passCheck(resourceWrapper, rule, count, args)) {
|
||||
|
||||
String triggeredParam = "";
|
||||
@@ -1077,9 +834,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1113,9 +867,6 @@ AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
private int burstCount = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1157,9 +908,6 @@ rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
rule.setCount(5);
|
||||
|
||||
ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>以此为例,我们分析 ParamFlowChecker#passCheck 方法源码,passCheck 返回 true 表示放行,返回 false 表示拒绝。</p>
|
||||
@@ -1209,9 +957,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
return passLocalCheck(resourceWrapper, rule, count, value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1281,9 +1026,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>由于参数可能是基本数据类型,也可能是数组类型,或者引用类型,所以 passLocalCheck 方法分三种情况处理。我们只讨论其中一种情况,其它情况的实现类似。</p>
|
||||
@@ -1329,15 +1071,9 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
return ++threadCount <= threshold;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1421,9 +1157,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//(5)
|
||||
|
||||
long passTime = currentTime - lastAddTokenTime.get();
|
||||
@@ -1455,9 +1188,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
long newQps = toAddCount + restQps > maxCount ? (maxCount - acquireCount)
|
||||
|
||||
: (restQps + toAddCount - acquireCount);
|
||||
|
||||
|
||||
|
||||
if (newQps < 0) {
|
||||
|
||||
return false;
|
||||
@@ -1513,9 +1243,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ol>
|
||||
@@ -1643,9 +1370,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ol>
|
||||
@@ -1687,9 +1411,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1697,9 +1418,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1715,17 +1433,11 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1751,9 +1463,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1765,9 +1474,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1785,12 +1491,6 @@ ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 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 class="current-tab" 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">
|
||||
@@ -481,9 +319,6 @@ public @interface SwitchDegrade {
|
||||
String key() default "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>提示:如果是应用在实际项目中,建议为 @SwitchDegrade 注解添加一个前缀属性,限制同一个应用下的开关 key 都是有同一个前缀,避免多个应用之间的缓存 key 冲突。</p>
|
||||
@@ -501,9 +336,6 @@ public class SwitchDegradeAspect {
|
||||
public void degradePointCut() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
* 拦截请求判断是否开启开关降级
|
||||
@@ -531,9 +363,6 @@ public class SwitchDegradeAspect {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如代码所示,SwitchDegradeAspect 拦截目标方法的执行,先从方法上的 @SwitchDegrade 注解获取开关的缓存 key,根据 key 从 redis 读取当前开关的状态,如果 key 存在且 value 为 true,则抛出一个开关降级异常。</p>
|
||||
@@ -549,9 +378,6 @@ public class SwitchDegradeAspect {
|
||||
return new BaseResponse(ResultCode.SERVICE_DEGRADE, ex.getMessage());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>提示:如果是整合 OpenFeign 使用,且配置了 Fallback,则全局异常可以不配置。</p>
|
||||
@@ -575,9 +401,6 @@ public class DemoController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>这种方式虽然能满足需求,但也有一个缺点,就是必须要在方法上添加 @SwitchDegrade 注解,配置不够灵活,但也不失为一个好方法。</p>
|
||||
@@ -627,9 +450,6 @@ public class SwitchRule {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>灵活,不仅仅只是去掉注解的使用,更需要可以灵活指定开关控制某些资源,因此,配置开关控制的资源应支持这几种情况:指定该开关只控制哪些资源、除了某些资源外其它都受控制、控制全部。所以,SwitchRule 的资源配置与 Sentinel 的熔断降级、限流降级规则配置不一样,SwitchRule 支持三种资源配置方式:</p>
|
||||
@@ -663,9 +483,6 @@ public class SwitchRule {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>SwitchRuleManager 提供两个接口:</p>
|
||||
@@ -681,9 +498,6 @@ public class SwitchRule {
|
||||
<p>同样地,在 Sentinel 中,一般会将检查规则是否达到触发降级的阈值由 XxxRuleChecker 完成,即 Xxx 规则检查员,所以我们定义的开关降级规则检查员命名为 SwitchRuleChecker,由 SwitchRuleChecker 检查开关是否打开,如果开关打开则触发开关降级。SwitchRuleChecker 的代码实现如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class SwitchRuleChecker {
|
||||
|
||||
|
||||
|
||||
public static void checkSwitch(ResourceWrapper resource, Context context) throws SwitchException {
|
||||
|
||||
Set<SwitchRule> switchRuleSet = SwitchRuleManager.getRules();
|
||||
@@ -733,13 +547,7 @@ public class SwitchRule {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如代码所示,SwitchRuleChecker 从 SwitchRuleManager 获取配置的开关降级规则,遍历开关降级规则,如果开关打开,且匹配到当前资源名称被该开关控制,则抛出 SwitchException。</p>
|
||||
@@ -753,9 +561,6 @@ public class SwitchRule {
|
||||
<p>最后,还需要自定义实现开关降级功能的切入点 SwitchSlot。SwitchSlot 继承 AbstractLinkedProcessorSlot,在 entry 方法中调用 SwitchRuleChecker#checkSwitch 方法检查当前资源是否已经降级。SwitchSlot 的代码实现如下:</p>
|
||||
|
||||
<pre><code class="language-java">public class SwitchSlot extends AbstractLinkedProcessorSlot<Object> {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void entry(Context context, ResourceWrapper resourceWrapper, Object param, int count, boolean prioritized, Object... args) throws Throwable {
|
||||
@@ -765,9 +570,6 @@ public class SwitchRule {
|
||||
fireEntry(context, resourceWrapper, param, count, prioritized, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
|
||||
@@ -775,13 +577,7 @@ public class SwitchRule {
|
||||
fireExit(context, resourceWrapper, count, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>自定义 ProcessorSlotChain 构建器 MySlotChainBuilder,将自定义的 SwitchSlot 添加到 ProcessorSlot 链表的末尾。当然,可以添加到任何位置,因为 SwitchSlot 没有用到指标数据,SwitchSlot 放置何处都不会影响到 Sentinel 的正常工作。</p>
|
||||
@@ -803,9 +599,6 @@ public class SwitchRule {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>MySlotChainBuilder 继承 DefaultSlotChainBuilder 只是为了使用 DefaultSlotChainBuilder#build 方法,简化 ProcessorSlotChain 的构造步骤,只需要在 DefaultSlotChainBuilder 构造的链表尾部添加一个 SwitchSlot 即可。</p>
|
||||
@@ -815,9 +608,6 @@ public class SwitchRule {
|
||||
<p>在当前项目的 resources 资源目录的 META-INF/service 目录下创建一个名为“com.alibaba.csp.sentinel.slotchain.SlotChainBuilder”的文件,在该文件中配置 MySlotChainBuilder 类的全名,例如:</p>
|
||||
|
||||
<pre><code class="language-txt">com.wujiuye.demo.common.sentinel.MySlotChainBuilder
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>现在,您可以在 MySlotChainBuilder#build 方法中添加断点,然后启动项目,正常情况下程序会在该断点停下。但由于我们并未配置开关降级规则,所以还看不到效果。</p>
|
||||
@@ -827,9 +617,6 @@ public class SwitchRule {
|
||||
<pre><code class="language-java">@Configuration
|
||||
|
||||
public class SentinelRuleConfiguration{
|
||||
|
||||
|
||||
|
||||
static {
|
||||
|
||||
Set<SwitchRule> rules = new HashSet<>();
|
||||
@@ -857,9 +644,6 @@ public class SentinelRuleConfiguration{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>上面代码配置了一个开关降级规则,该降级规则只控制接口(资源)<code>"/v1/test/demo"</code>,SwitchRule.status 控制开关是否打开,测试这里就不演示了。当然,这种配置方式只适用于本地测试,实际项目中我们可通过动态配置实现,这将在后面介绍 Sentinel 动态数据源时再介绍如何实现。</p>
|
||||
@@ -885,9 +669,6 @@ public class SentinelRuleConfiguration{
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -895,9 +676,6 @@ public class SentinelRuleConfiguration{
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -913,17 +691,11 @@ public class SentinelRuleConfiguration{
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -949,9 +721,6 @@ public class SentinelRuleConfiguration{
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -963,9 +732,6 @@ public class SentinelRuleConfiguration{
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -983,12 +749,6 @@ public class SentinelRuleConfiguration{
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 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 class="current-tab" 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">
|
||||
@@ -493,9 +331,6 @@ function hide_canvas() {
|
||||
boolean updateValue(T newValue);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -549,9 +384,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>可见,DynamicSentinelProperty 使用 Set 存储已注册的监听器,updateValue 负责通知所有监听器,调用监听器的 configUpdate 方法。</p>
|
||||
@@ -589,9 +421,6 @@ function hide_canvas() {
|
||||
// 提供默认的 SentinelProperty
|
||||
|
||||
= new DynamicSentinelProperty<List<FlowRule>>();
|
||||
|
||||
|
||||
|
||||
static {
|
||||
|
||||
// 给默认的 SentinelProperty 注册监听器(FlowPropertyListener)
|
||||
@@ -599,9 +428,6 @@ function hide_canvas() {
|
||||
currentProperty.addListener(LISTENER);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 注册 SentinelProperty
|
||||
|
||||
public static void register2Property(SentinelProperty<List<FlowRule>> property) {
|
||||
@@ -621,9 +447,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>实现更新限流规则缓存的 FlowPropertyListener 是 FlowRuleManager 的一个内部类,其源码如下:</p>
|
||||
@@ -665,9 +488,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>PropertyListener 接口定义的两个方法:</p>
|
||||
@@ -705,9 +525,6 @@ function hide_canvas() {
|
||||
void close() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ReadableDataSource 是一个泛型接口,参数化类型 S 代表用于装载从数据源读取的配置的类型,参数化类型 T 代表对应 Sentinel 中的规则类型。例如,我们可以定义一个 FlowRuleProps 类,用于装载从 yml 配置文件中读取的限流规则配置,然后再将 FlowRuleProps 转为 FlowRule,所以 S 可以替换为 FlowRuleProps,T 可以替换为 <code>List<FlowRule></code>。</p>
|
||||
@@ -735,9 +552,6 @@ function hide_canvas() {
|
||||
protected final Converter<S, T> parser;
|
||||
|
||||
protected final SentinelProperty<T> property;
|
||||
|
||||
|
||||
|
||||
public AbstractDataSource(Converter<S, T> parser) {
|
||||
|
||||
if (parser == null) {
|
||||
@@ -751,9 +565,6 @@ function hide_canvas() {
|
||||
this.property = new DynamicSentinelProperty<T>();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public T loadConfig() throws Exception {
|
||||
@@ -761,9 +572,6 @@ function hide_canvas() {
|
||||
return loadConfig(readSource());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public T loadConfig(S conf) throws Exception {
|
||||
|
||||
T value = parser.convert(conf);
|
||||
@@ -771,9 +579,6 @@ function hide_canvas() {
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public SentinelProperty<T> getProperty() {
|
||||
@@ -783,9 +588,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>从源码可以看出:</p>
|
||||
@@ -807,9 +609,6 @@ function hide_canvas() {
|
||||
T convert(S source);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -837,17 +636,11 @@ public class FlowRuleProps{
|
||||
//....省略
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>第二步:创建数据转换器,实现将 FlowRuleProps 转为 <code>List<FlowRule></code>,如 FlowRuleConverter 所示。</p>
|
||||
|
||||
<pre><code class="language-java">public class FlowRuleConverter implements Converter<FlowRuleProps, List<FlowRule>>{
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public List<FlowRule> convert(FlowRuleProps source){
|
||||
@@ -857,9 +650,6 @@ public class FlowRuleProps{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>第三步:创建 FlowRuleDataSource,继承 AbstractDataSource,实现 readSource 方法。readSource 方法只需要获取 FlowRuleProps 返回即可,代码如下。</p>
|
||||
@@ -871,9 +661,6 @@ public class FlowRuleDataSource extends AbstractDataSource<FlowRuleProps, Lis
|
||||
@Autowired
|
||||
|
||||
private FlowRuleProps flowRuleProps;
|
||||
|
||||
|
||||
|
||||
public FlowRuleDataSource() {
|
||||
|
||||
super(new FlowRuleConverter());
|
||||
@@ -895,9 +682,6 @@ public class FlowRuleDataSource extends AbstractDataSource<FlowRuleProps, Lis
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>第四步:增强 FlowRuleDataSource,让 FlowRuleDataSource 能够监听到 FlowRuleProps 配置改变。</p>
|
||||
@@ -919,9 +703,6 @@ public class FlowRuleDataSource extends AbstractDataSource<FlowRuleProps, Lis
|
||||
getProperty().updateValue(loadConfig());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
@@ -931,9 +712,6 @@ public class FlowRuleDataSource extends AbstractDataSource<FlowRuleProps, Lis
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -953,9 +731,6 @@ public class FlowRuleDataSourceConfiguration implements ApplicationRunner{
|
||||
@Autowired
|
||||
|
||||
private FlowRuleDataSource flowRuleDataSource;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
@@ -967,9 +742,6 @@ public class FlowRuleDataSourceConfiguration implements ApplicationRunner{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>在调用 FlowRuleManager#register2Property 方法将 FlowRuleDataSource 动态数据源的 SentinelProperty 注册给 FlowRuleManager 时,FlowRuleManager 会自动给该 SentinelProperty 注册一个监听器(FlowPropertyListener)。</p>
|
||||
@@ -1017,9 +789,6 @@ public class FlowRuleDataSourceConfiguration implements ApplicationRunner{
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1027,9 +796,6 @@ public class FlowRuleDataSourceConfiguration implements ApplicationRunner{
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1045,17 +811,11 @@ public class FlowRuleDataSourceConfiguration implements ApplicationRunner{
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1081,9 +841,6 @@ public class FlowRuleDataSourceConfiguration implements ApplicationRunner{
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1095,9 +852,6 @@ public class FlowRuleDataSourceConfiguration implements ApplicationRunner{
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1115,12 +869,6 @@ public class FlowRuleDataSourceConfiguration implements ApplicationRunner{
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 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 class="current-tab" 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">
|
||||
@@ -483,9 +321,6 @@ function hide_canvas() {
|
||||
<version>${version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>第二步:编写 WebMvcConfigurer,在 addInterceptors 方法中注入 SentinelWebInterceptor。</p>
|
||||
@@ -513,9 +348,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>在创建 SentinelWebInterceptor 时,可为 SentinelWebInterceptor 添加配置,使用 SentinelWebMvcConfig 封装这些配置:</p>
|
||||
@@ -551,9 +383,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>HandlerInterceptor 在 DispatcherServlet#doDispatch 方法中被调用,每个方法的调用时机如下:</p>
|
||||
@@ -609,9 +438,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
return resourceName;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>资源名称生成过程如下。</p>
|
||||
@@ -677,9 +503,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ol>
|
||||
@@ -715,9 +538,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果我们给 SentinelWebMvcConfig 配置了 BlockExceptionHandler,则调用 BlockExceptionHandler#handle 方法处理 BlockException 异常,否则将异常抛出,由全局处理器处理。</p>
|
||||
@@ -749,9 +569,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
ContextUtil.exit();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ol>
|
||||
@@ -781,9 +598,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当方法执行抛出异常时,调用 Tracer#traceEntry 方法记录异常,更新异常指标数据。</p>
|
||||
@@ -807,9 +621,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
<version>2.2.1.RELEASE</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>2. 启用 OpenFeign 整合 Sentinel 的自动配置</strong></p>
|
||||
@@ -821,9 +632,6 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
sentinel:
|
||||
|
||||
enabled: true
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>3. 熔断降级规则配置</strong></p>
|
||||
@@ -843,19 +651,10 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||
fallback = ServiceDegradeFallback.class)
|
||||
|
||||
public interface DemoService {
|
||||
|
||||
|
||||
|
||||
@PostMapping("/services")
|
||||
|
||||
ListGenericResponse<DemoDto> getServices();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>fallback 属性要求配置一个类,该类必须实现相同的接口,所以 ServiceDegradeFallback 必须实现 DemoService 接口。</p>
|
||||
@@ -877,9 +676,6 @@ public interface DemoService {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ServiceDegradeFallback 类中处理接口降级逻辑,例如,响应一个状态码告知消费端由于服务降级本次接口调用失败。</p>
|
||||
@@ -899,9 +695,6 @@ public interface DemoService {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>将 SentinelFeignConfig 配置类添加到 @FeignClient 注解的 configuration 属性,如下:</p>
|
||||
@@ -923,19 +716,10 @@ public interface DemoService {
|
||||
fallback = ServiceDegradeFallback.class)
|
||||
|
||||
public interface DemoService {
|
||||
|
||||
|
||||
|
||||
@PostMapping("/services")
|
||||
|
||||
ListGenericResponse<DemoDto> getServices();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当满足熔断条件时,Sentinel 会抛出一个 DegradeException 异常,如果配置了 fallback,那么 Sentinel 会从 Bean 工厂中根据 fallback 属性配置的类型取一个 Bean 并调用接口方法。</p>
|
||||
@@ -977,9 +761,6 @@ public interface DemoService {
|
||||
@ConditionalOnClass({ SphU.class, Feign.class })
|
||||
|
||||
public class SentinelFeignAutoConfiguration {
|
||||
|
||||
|
||||
|
||||
@Bean
|
||||
|
||||
@Scope("prototype")
|
||||
@@ -993,39 +774,21 @@ public class SentinelFeignAutoConfiguration {
|
||||
return SentinelFeign.builder();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>SentinelFeign.Builder 继承 Feign.Builder 并重写 build 方法,SentinelFeign.Builder#build 方法源码如下:</p>
|
||||
|
||||
<pre><code class="language-java">public final class SentinelFeign {
|
||||
|
||||
|
||||
|
||||
public static Builder builder() {
|
||||
|
||||
return new Builder();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static final class Builder extends Feign.Builder
|
||||
|
||||
implements ApplicationContextAware {
|
||||
|
||||
|
||||
|
||||
// .....
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public Feign build() {
|
||||
@@ -1053,13 +816,7 @@ public class SentinelFeignAutoConfiguration {
|
||||
// .....
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>SentinelFeign.Builder#build 偷天换日,替换了 InvocationHandlerFactory,所以 OpenFeign 调用 InvocationHandlerFactory#create 方法创建的 InvocationHandler 就变成了 SentinelInvocationHandler。</p>
|
||||
@@ -1077,9 +834,6 @@ Object fallbackInstance = getFromContext(beanName, "fallback", fallbac
|
||||
return new SentinelInvocationHandler(target, dispatch,
|
||||
|
||||
new FallbackFactory.Default(fallbackInstance));
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>在创建 SentinelInvocationHandler 之前,通过反射从 FeignClientFactoryBean 拿到 @FeignClient 注解的 fallback 属性值,然后根据 fallback 类型从 Bean 工厂取得 fallback 实例,将 fallback 实例传递给 SentinelInvocationHandler。当触发熔断时,SentinelInvocationHandler 就能取得 fallback 实例并调用。</p>
|
||||
@@ -1107,9 +861,6 @@ return new SentinelInvocationHandler(target, dispatch,
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1117,9 +868,6 @@ return new SentinelInvocationHandler(target, dispatch,
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1135,17 +883,11 @@ return new SentinelInvocationHandler(target, dispatch,
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1171,9 +913,6 @@ return new SentinelInvocationHandler(target, dispatch,
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1185,9 +924,6 @@ return new SentinelInvocationHandler(target, dispatch,
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1205,12 +941,6 @@ return new SentinelInvocationHandler(target, dispatch,
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 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 class="current-tab" 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">
|
||||
@@ -561,9 +399,6 @@ function hide_canvas() {
|
||||
private int windowIntervalMs = RuleConstant.DEFAULT_WINDOW_INTERVAL_MS;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -605,9 +440,6 @@ function hide_canvas() {
|
||||
extends AbstractDataSource<String, List<FlowRule>>
|
||||
|
||||
implements Runnable{
|
||||
|
||||
|
||||
|
||||
public SimpleLocalDataSource(String namespace) {
|
||||
|
||||
super(new SimpleConverter<String, List<FlowRule>>() {});
|
||||
@@ -617,9 +449,6 @@ function hide_canvas() {
|
||||
new Thread(this).start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public String readSource() throws Exception {
|
||||
@@ -629,17 +458,11 @@ function hide_canvas() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void close() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public void run() {
|
||||
@@ -661,9 +484,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>SimpleLocalDataSource 构造方法中启动一个线程,用于实现等待动态数据源对象注册到 ClusterFlowRuleManager 之后再模拟加载一次规则。由于是测试,所以 readSource 方法并未实现,我们直接在 SimpleConverter 这个转换器中虚构一个集群限流规则,代码如下。</p>
|
||||
@@ -699,9 +519,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>接下来,我们将使用这个动态数据源实现集群限流客户端和服务端的配置。</p>
|
||||
@@ -719,9 +536,6 @@ function hide_canvas() {
|
||||
<version>${version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>将身份设置为集群限流客户端(CLUSTER_CLIENT),并且注册客户端配置(ClusterClientConfig),代码如下。</p>
|
||||
@@ -747,9 +561,6 @@ public class WebMvcDemoApplication {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>在 Spring 项目中,可通过监听 ContextRefreshedEvent 事件,在 Spring 容器启动完成后再初始化创建动态数据源、为 FlowRuleManager 注册动态数据源的 SentinelProperty,代码如下。</p>
|
||||
@@ -771,9 +582,6 @@ public class WebMvcDemoApplication implements ApplicationListener<ContextRefr
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>最后注册用于连接到集群限流服务端的配置(ClusterClientAssignConfig),指定集群限流服务端的 IP 和端口,代码如下。</p>
|
||||
@@ -799,9 +607,6 @@ public class WebMvcDemoApplication {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当 ClusterClientConfigManager#applyNewAssignConfig 方法被调用时,会触发 Sentinel 初始化或重新连接到集群限流服务端,所以我们看不到启动集群限流客户端的代码。Sentinel 还支持当客户端与服务端意外断开连接时,让客户端不断的重试重连。</p>
|
||||
@@ -823,17 +628,11 @@ public class WebMvcDemoApplication {
|
||||
<version>${version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>在独立模式下,需要我们自己手动创建 ClusterTokenServer 并启动,在启动之前需指定服务监听的端口和连接最大空闲等待时间等配置,代码如下。</p>
|
||||
|
||||
<pre><code class="language-java">public class ClusterServerDemo {
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
ClusterTokenServer tokenServer = new SentinelDefaultTokenServer();
|
||||
@@ -853,9 +652,6 @@ public class WebMvcDemoApplication {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>接着我们需要为服务端创建用于加载集群限流规则的动态数据源,在创建动态数据源时,需指定数据源只加载哪个名称空间下的限流规则配置,如下代码所示。</p>
|
||||
@@ -879,9 +675,6 @@ public class WebMvcDemoApplication {
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>从代码中可以看出,我们注册的是一个 Java8 的 Function,这个 Function 的 apply 方法将在我们注册名称空间时触发调用。</p>
|
||||
@@ -891,9 +684,6 @@ public class WebMvcDemoApplication {
|
||||
<pre><code class="language-java">// 多个应用应该对应多个名称空间,应用之间通过名称空间互相隔离
|
||||
|
||||
ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("serviceA"));
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>名称空间可以有多个,如果存在多个名称空间,则会多次调用 ClusterFlowRuleManager#setPropertySupplier 注册的 Function 对象的 apply 方法创建多个动态数据源。多个应用应该对应多个名称空间,应用之间通过名称空间互相隔离。</p>
|
||||
@@ -907,9 +697,6 @@ ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("se
|
||||
<p>如果是嵌入模式启动,除非一开始我们就清楚的知道应用会部署多少个节点,这些节点的 IP 是什么,并且不会改变,否则我们无法使用静态配置的方式去指定某个节点的角色。Sentinel 为此提供了支持动态改变某个节点角色的 API,使用方式如下:</p>
|
||||
|
||||
<pre><code class="language-java">http://<节点 ip>:<节点 port>/setClusterMode?mode={state}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>其中 <code>{state}</code> 为 0 代表集群限流客户端,为 1 代表集群限流服务端。当一个新的节点被选为集群限流服务端后,旧的集群限流服务端节点也应该变为集群限流客户端,并且其它的节点都需要作出改变以连接到这个新的集群限流服务端。</p>
|
||||
@@ -917,9 +704,6 @@ ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("se
|
||||
<p>Sentinel 提供动态修改 ClusterClientAssignConfig、ClusterClientConfig 的 API,使用方式如下:</p>
|
||||
|
||||
<pre><code class="language-java">http://<节点 ip>:<节点 port>/cluster/client/modifyConfig?data={body}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>其中 <code>{body}</code> 要求是 JSON 格式的字符串,支持的参数配置如下:</p>
|
||||
@@ -969,9 +753,6 @@ ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("se
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -979,9 +760,6 @@ ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("se
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -997,17 +775,11 @@ ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("se
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1033,9 +805,6 @@ ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("se
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1047,9 +816,6 @@ ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("se
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1067,12 +833,6 @@ ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("se
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 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 class="current-tab" 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">
|
||||
@@ -491,9 +329,6 @@ function hide_canvas() {
|
||||
TokenResult requestParamToken(Long ruleId, int acquireCount, Collection<Object> params);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -517,9 +352,6 @@ function hide_canvas() {
|
||||
private Map<String, String> attachments;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -543,9 +375,6 @@ function hide_canvas() {
|
||||
void stop() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ClusterTokenClient 接口定义启动和停止集群限流客户端的方法,负责维护客户端与服务端的连接。该接口还继承了 TokenService,要求实现类必须要实现 requestToken、requestParamToken 方法,向远程服务端请求获取令牌。</p>
|
||||
@@ -559,9 +388,6 @@ function hide_canvas() {
|
||||
void stop() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ClusterTokenServer 接口定义启动和停止集群限流客户端的方法,启动能够接收和响应客户端请求的网络通信服务端,根据接收的消费类型处理客户端的请求。</p>
|
||||
@@ -573,9 +399,6 @@ function hide_canvas() {
|
||||
extends ClusterTokenServer, TokenService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>EmbeddedClusterTokenServer 接口继承 ClusterTokenServer,并继承 TokenService 接口,即整合客户端和服务端的功能,为嵌入式模式提供支持。在嵌入式模式下,如果当前节点是集群限流服务端,那就没有必要发起网络请求。</p>
|
||||
@@ -627,9 +450,6 @@ function hide_canvas() {
|
||||
return fallbackToLocalOrPass(rule, context, node, acquireCount, prioritized);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>整体流程分为:</p>
|
||||
@@ -669,9 +489,6 @@ function hide_canvas() {
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>ClusterTokenClient 和 EmbeddedClusterTokenServer 都继承 TokenService,区别在于,ClusterTokenClient 实现类实现 requestToken 方法是向服务端发起请求,而 EmbeddedClusterTokenServer 实现类实现 requestToken 方法不需要发起远程调用,因为自身就是服务端。</p>
|
||||
@@ -723,9 +540,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>applyTokenResult 方法根据响应状态码决定是否拒绝当前请求:</p>
|
||||
@@ -759,9 +573,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>fallbackToLocalOrPass 方法根据规则配置的 fallbackToLocalWhenFail 决定是否回退为本地限流,如果 fallbackToLocalWhenFail 配置为 false,将会导致客户端在与服务端失联的情况下拒绝所有流量。fallbackToLocalWhenFail 默认值为 true,建议不要修改为 false,我们应当确保服务的可用性,再确保集群限流的准确性。</p>
|
||||
@@ -799,9 +610,6 @@ function hide_canvas() {
|
||||
return ClusterFlowChecker.acquireClusterToken(rule, acquireCount, prioritized);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -863,9 +671,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>全局 QPS 阈值限流,按名称空间统计 QPS,如果需要使用按名称空间 QPS 限流,则可通过如下方式配置阈值。</p>
|
||||
@@ -875,9 +680,6 @@ function hide_canvas() {
|
||||
serverFlowConfig.setMaxAllowedQps(1000);
|
||||
|
||||
ClusterServerConfigManager.loadFlowConfig("serviceA",serverFlowConfig);
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -911,9 +713,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -941,9 +740,6 @@ if (prioritized) {
|
||||
}
|
||||
|
||||
return new TokenResult(TokenResultStatus.OK).setRemaining((int) nextRemaining).setWaitInMs(0);
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当 nextRemaining 计算结果大于等于 0 时,执行这部分代码,先记录当前请求被放行,而后响应状态码 OK 给客户端。</p>
|
||||
@@ -965,9 +761,6 @@ if (occupyAvg <= ClusterServerConfigManager.getMaxOccupyRatio() * globalThres
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当 nextRemaining 计算结果小于 0 时,如果当前请求具有优先级,则执行这部分逻辑。计算是否可占用下个时间窗口的 pass 指标,如果允许,则告诉客户端,当前请求可放行,但需要等待 waitInMs(一个窗口时间大小)毫秒之后才可放行。</p>
|
||||
@@ -987,9 +780,6 @@ if (prioritized) {
|
||||
}
|
||||
|
||||
return blockedResult();
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>当 nextRemaining 大于 0,且无优先级权限时,直接拒绝请求,记录当前请求被 Block。</p>
|
||||
@@ -1047,9 +837,6 @@ return blockedResult();
|
||||
NAMESPACE_FLOW_ID_MAP.put(namespace, flowIdSet);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>实现集群限流需要收集的指标数据有以下几种:</p>
|
||||
@@ -1071,9 +858,6 @@ return blockedResult();
|
||||
WAITING
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1129,9 +913,6 @@ return blockedResult();
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1139,9 +920,6 @@ return blockedResult();
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1157,17 +935,11 @@ return blockedResult();
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1193,9 +965,6 @@ return blockedResult();
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1207,9 +976,6 @@ return blockedResult();
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1227,12 +993,6 @@ return blockedResult();
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 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 class="current-tab" 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">
|
||||
@@ -511,9 +349,6 @@ function hide_canvas() {
|
||||
}
|
||||
|
||||
return chain;
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>Sentinel 使用 Map 而非 ConcurrentMap 是为了尽量避免加锁,大多数场景都是读多写少,以上面代码为例,ProcessorSlotChain 的新增只在资源第一次被访问时,例如接口第一次被调用,而后续都不会再写。假设有 10 个接口,这 10 个接口在应用启动起来就都被访问过了,那么这个 Map 后续就不会再出现写的情况,既然不会再有写操作,就没有必须加锁了,所以使用 Map 而不是使用 ConcurrentMap。</p>
|
||||
@@ -557,9 +392,6 @@ function hide_canvas() {
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>注:1.23 版本是 JMH 目前最新的版本。</p>
|
||||
@@ -573,9 +405,6 @@ function hide_canvas() {
|
||||
<p>@Benchmark 注解用于声明一个 public 方法为基准测试方法,如下代码所示。</p>
|
||||
|
||||
<pre><code class="language-java">public class MyTestBenchmark {
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -585,13 +414,7 @@ function hide_canvas() {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>@BenchmarkMode</strong></p>
|
||||
@@ -599,9 +422,6 @@ function hide_canvas() {
|
||||
<p>通过 JMH 我们可以轻松的测试出某个接口的吞吐量、平均执行时间等指标的数据。假设我们想测试某个方法的平均耗时,那么可以使用 @BenchmarkMode 注解指定测试维度为 Mode.AverageTime,代码如下。</p>
|
||||
|
||||
<pre><code class="language-java">public class MyTestBenchmark {
|
||||
|
||||
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
|
||||
@Benchmark
|
||||
@@ -613,13 +433,7 @@ function hide_canvas() {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>@Measurement</strong></p>
|
||||
@@ -627,9 +441,6 @@ function hide_canvas() {
|
||||
<p>假设我们需要测量五次,那么可以使用 @Measurement 注解,代码如下。</p>
|
||||
|
||||
<pre><code class="language-java">public class MyTestBenchmark {
|
||||
|
||||
|
||||
|
||||
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@@ -643,13 +454,7 @@ function hide_canvas() {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>@Measurement 注解有三个配置项:</p>
|
||||
@@ -667,9 +472,6 @@ function hide_canvas() {
|
||||
<p>为了数据准确,我们可能需要让被测试的方法做下热身运动,一定的预热次数可提升测试结果的准备度。可使用 @Warmup 注解声明需要预热的次数、每次预热的持续时间,代码如下。</p>
|
||||
|
||||
<pre><code class="language-java">public class MyTestBenchmark {
|
||||
|
||||
|
||||
|
||||
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
|
||||
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@@ -685,13 +487,7 @@ function hide_canvas() {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>@Warmup 注解有三个配置项:</p>
|
||||
@@ -713,9 +509,6 @@ function hide_canvas() {
|
||||
<p>如果方法执行耗时为毫秒级别,为了便于观察结果,我们可以使用 @OutputTimeUnit 指定输出的耗时时间单位为毫秒,否则使用默认的秒做单位,会输出 10 的负几次方这样的数字,不太直观。</p>
|
||||
|
||||
<pre><code class="language-java">public class MyTestBenchmark {
|
||||
|
||||
|
||||
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
|
||||
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@@ -733,13 +526,7 @@ function hide_canvas() {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>@Fork</strong></p>
|
||||
@@ -749,9 +536,6 @@ function hide_canvas() {
|
||||
<p>假设我们不需要多个进程,那么可以使用 @Fork 指定进程数为 1,如下代码所示。</p>
|
||||
|
||||
<pre><code class="language-java">public class MyTestBenchmark {
|
||||
|
||||
|
||||
|
||||
@Fork(1)
|
||||
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@@ -771,13 +555,7 @@ function hide_canvas() {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>@Threads</strong></p>
|
||||
@@ -785,9 +563,6 @@ function hide_canvas() {
|
||||
<p>@Threads 注解用于指定使用多少个线程来执行基准测试方法,如果使用 @Threads 指定线程数为 2,那么每次测量都会创建两个线程来执行基准测试方法。</p>
|
||||
|
||||
<pre><code class="language-java">public class MyTestBenchmark {
|
||||
|
||||
|
||||
|
||||
@Threads(2)
|
||||
|
||||
@Fork(1)
|
||||
@@ -807,13 +582,7 @@ function hide_canvas() {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>如果 @Measurement 注解指定 time 为 1s,基准测试方法的执行耗时为 1s,那么如果只使用单个线程,一次测量只会执行一次基准测试方法,如果使用 10 个线程,一次测量就能执行 10 次基准测试方法。</p>
|
||||
@@ -835,9 +604,6 @@ function hide_canvas() {
|
||||
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
|
||||
public class MyTestBenchmark {
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -847,9 +613,6 @@ public class MyTestBenchmark {
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -861,9 +624,6 @@ public class MyTestBenchmark {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>下面我们以测试 Gson、Jackson 两个 JSON 解析框架的性能对比为例。</p>
|
||||
@@ -883,15 +643,9 @@ public class MyTestBenchmark {
|
||||
@State(Scope.Benchmark)
|
||||
|
||||
public class JsonBenchmark {
|
||||
|
||||
|
||||
|
||||
private GsonParser gsonParser = new GsonParser();
|
||||
|
||||
private JacksonParser jacksonParser = new JacksonParser();
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -901,9 +655,6 @@ public class JsonBenchmark {
|
||||
gsonParser.fromJson("{\"startDate\":\"2020-04-01 16:00:00\",\"endDate\":\"2020-05-20 13:00:00\",\"flag\":true,\"threads\":5,\"shardingIndex\":0}", JsonTestModel.class);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -915,9 +666,6 @@ public class JsonBenchmark {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>我们可以使用 @State 注解指定 gsonParser、jacksonParser 这两个字段的共享域。</p>
|
||||
@@ -941,15 +689,9 @@ public class JsonBenchmark {
|
||||
@State(Scope.Thread)
|
||||
|
||||
public class JsonBenchmark {
|
||||
|
||||
|
||||
|
||||
private GsonParser gsonParser = new GsonParser();
|
||||
|
||||
private JacksonParser jacksonParser = new JacksonParser();
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -961,9 +703,6 @@ public class JsonBenchmark {
|
||||
gsonParser.fromJson("{\"startDate\":\"2020-04-01 16:00:00\",\"endDate\":\"2020-05-20 13:00:00\",\"flag\":true,\"threads\":5,\"shardingIndex\":0}", JsonTestModel.class);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -975,9 +714,6 @@ public class JsonBenchmark {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>执行 testGson 方法输出的结果如下:</p>
|
||||
@@ -999,9 +735,6 @@ current Thread:com.msyc.common.JsonBenchmark.testGson-jmh-worker-1==>20636847
|
||||
current Thread:com.msyc.common.JsonBenchmark.testGson-jmh-worker-2==>1629232880
|
||||
|
||||
......
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p><strong>@Param</strong></p>
|
||||
@@ -1025,15 +758,9 @@ current Thread:com.msyc.common.JsonBenchmark.testGson-jmh-worker-2==>16292328
|
||||
@State(Scope.Thread)
|
||||
|
||||
public class JsonBenchmark {
|
||||
|
||||
|
||||
|
||||
private GsonParser gsonParser = new GsonParser();
|
||||
|
||||
private JacksonParser jacksonParser = new JacksonParser();
|
||||
|
||||
|
||||
|
||||
// 指定参数有三个值
|
||||
|
||||
@Param(value =
|
||||
@@ -1045,9 +772,6 @@ public class JsonBenchmark {
|
||||
"{\"flag\":true,\"threads\":5,\"shardingIndex\":0}"})
|
||||
|
||||
private String jsonStr;
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -1057,9 +781,6 @@ public class JsonBenchmark {
|
||||
gsonParser.fromJson(jsonStr, JsonTestModel.class);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Test
|
||||
@@ -1069,13 +790,7 @@ public class JsonBenchmark {
|
||||
jacksonParser.fromJson(jsonStr, JsonTestModel.class);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>测试结果如下:</p>
|
||||
@@ -1083,29 +798,11 @@ public class JsonBenchmark {
|
||||
<pre><code class="language-text">Benchmark (jsonStr) Mode Cnt Score Error Units
|
||||
|
||||
JsonBenchmark.testGson {"startDate":"2020-04-01 16:00:00","endDate":"2020-05-20 13:00:00","flag":true,"threads":5,"shardingIndex":0} avgt 5 12180.763 ± 2481.973 ns/op
|
||||
|
||||
|
||||
|
||||
JsonBenchmark.testGson {"startDate":"2020-04-01 16:00:00","endDate":"2020-05-20 14:00:00"} avgt 5 8154.709 ± 3393.881 ns/op
|
||||
|
||||
|
||||
|
||||
JsonBenchmark.testGson {"flag":true,"threads":5,"shardingIndex":0} avgt 5 9994.171 ± 5737.958 ns/op
|
||||
|
||||
|
||||
|
||||
JsonBenchmark.testJackson {"startDate":"2020-04-01 16:00:00","endDate":"2020-05-20 13:00:00","flag":true,"threads":5,"shardingIndex":0} avgt 5 15663.060 ± 9042.672 ns/op
|
||||
|
||||
|
||||
|
||||
JsonBenchmark.testJackson {"startDate":"2020-04-01 16:00:00","endDate":"2020-05-20 14:00:00"} avgt 5 13776.828 ± 11006.412 ns/op
|
||||
|
||||
|
||||
|
||||
JsonBenchmark.testJackson {"flag":true,"threads":5,"shardingIndex":0} avgt 5 9824.283 ± 311.555 ns/op
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h4><strong>非注解方式使用</strong></h4>
|
||||
@@ -1115,9 +812,6 @@ JsonBenchmark.testJackson
|
||||
<p>使用非注解方式实现上面的例子,代码如下。</p>
|
||||
|
||||
<pre><code class="language-java">public class BenchmarkTest{
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
|
||||
public void test() throws RunnerException {
|
||||
@@ -1149,13 +843,7 @@ JsonBenchmark.testJackson
|
||||
new Runner(options).run();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
@@ -1175,9 +863,6 @@ JsonBenchmark.testJackson
|
||||
<p>使用 Java 命令即可运行一个基准测试应用:</p>
|
||||
|
||||
<pre><code class="language-shell">java -jar my-benchmarks.jar
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h4>在 IDEA 中执行</h4>
|
||||
@@ -1185,9 +870,6 @@ JsonBenchmark.testJackson
|
||||
<p>在 IDEA 中,我们可以编写一个单元测试方法,在单元测试方法中创建一个 org.openjdk.jmh.runner.Runner,调用 Runner 的 run 方法执行基准测试。但 JMH 不会去扫描包,不会执行每个基准测试方法,这需要我们通过配置项来告知 JMH 需要执行哪些基准测试方法。</p>
|
||||
|
||||
<pre><code class="language-java">public class BenchmarkTest{
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
|
||||
public void test() throws RunnerException {
|
||||
@@ -1197,13 +879,7 @@ JsonBenchmark.testJackson
|
||||
new Runner(options).run();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>完整例子如下:</p>
|
||||
@@ -1227,9 +903,6 @@ JsonBenchmark.testJackson
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>Options 在前面已经介绍过了,由于本例中 JsonBenchmark 这个类已经使用了注解,因此 Options 只需要配置需要执行基准测试的类。如果需要执行多个基准测试类,include 方法可以多次调用。如果需要将测试结果输出到文件,可调用 output 方法配置文件路径,不配置则输出到控制台。</p>
|
||||
@@ -1271,17 +944,11 @@ JsonBenchmark.testJackson
|
||||
@State(Scope.Thread)
|
||||
|
||||
public class SentinelEntryBenchmark {
|
||||
|
||||
|
||||
|
||||
@Param({"25", "50", "100", "200", "500", "1000"})
|
||||
|
||||
private int length;
|
||||
|
||||
private List<Integer> numbers;
|
||||
|
||||
|
||||
|
||||
@Setup
|
||||
|
||||
public void prepare() {
|
||||
@@ -1295,9 +962,6 @@ public class SentinelEntryBenchmark {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Threads(8)
|
||||
@@ -1309,9 +973,6 @@ public class SentinelEntryBenchmark {
|
||||
Collections.sort(numbers);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Benchmark
|
||||
|
||||
@Threads(8)
|
||||
@@ -1339,13 +1000,7 @@ public class SentinelEntryBenchmark {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>该基准测试类使用 @State 指定每个线程使用不同的 numbers 字段的实例,所以 @Setup 注解的方法也会执行 8 次,分别是在每个线程开始执行基准测试方法之前执行,用于完成初始化工作,与 Junit 中的 @Before 注解功能相似。</p>
|
||||
@@ -1361,9 +1016,6 @@ public class SentinelEntryBenchmark {
|
||||
(min, avg, max) = (295869.456, 300948.682, 316089.624), stdev = 8631.655
|
||||
|
||||
CI (99.9%): [267711.254, 334186.110] (assumes normal distribution)
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>最小 ops/s 为 295869.456,平均 ops/s 为 300948.682,最大 ops/s 为 316089.624。</p>
|
||||
@@ -1377,9 +1029,6 @@ public class SentinelEntryBenchmark {
|
||||
(min, avg, max) = (280835.799, 309934.827, 337712.803), stdev = 25686.753
|
||||
|
||||
CI (99.9%): [211024.287, 408845.366] (assumes normal distribution)
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>最小 ops/s 为 280835.799,平均 ops/s 为 309934.827,最大 ops/s 为 337712.803。</p>
|
||||
@@ -1419,9 +1068,6 @@ public class SentinelEntryBenchmark {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1429,9 +1075,6 @@ public class SentinelEntryBenchmark {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1447,17 +1090,11 @@ public class SentinelEntryBenchmark {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1483,9 +1120,6 @@ public class SentinelEntryBenchmark {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1497,9 +1131,6 @@ public class SentinelEntryBenchmark {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1517,12 +1148,6 @@ public class SentinelEntryBenchmark {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
@@ -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 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 class="current-tab" 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">
|
||||
@@ -535,9 +373,6 @@ function hide_canvas() {
|
||||
private int statIntervalMs = 1000;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>与旧版本的不同:</p>
|
||||
@@ -667,9 +502,6 @@ function hide_canvas() {
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -677,9 +509,6 @@ function hide_canvas() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -695,17 +524,11 @@ function hide_canvas() {
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -731,9 +554,6 @@ function hide_canvas() {
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -745,9 +565,6 @@ function hide_canvas() {
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -765,12 +582,6 @@ function hide_canvas() {
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user