This commit is contained in:
周伟
2022-05-11 19:04:14 +08:00
parent 9440ac7291
commit d9c5ffd627
826 changed files with 0 additions and 481675 deletions

View File

@@ -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 为什么选择 SentinelSentinel 与 Hystrix 的对比.md.html">03 为什么选择 SentinelSentinel 与 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(&quot;OUT&quot;);
}
</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&lt;Node&gt; childList = new HashSet&lt;&gt;();
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>