|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 154 KiB |
@@ -89,6 +89,8 @@ Redis 8.4 新增了 `DELEX lock_key IFEQ unique_value` 指令,可以直接原
|
||||
|
||||
RedLock 依赖各个节点的时钟基本同步,并且无法应对进程暂停(例如 GC)导致锁过期后客户端仍然认为自己持有锁的情况,因此存在争议。更可靠的做法是让锁服务每次加锁时返回一个单调递增的栅栏令牌(Fencing Token),客户端访问资源时带上令牌,资源拒绝令牌比已处理过的更小的请求。
|
||||
|
||||
<div align="center"> <img src="pics/fencing-token.png" width="560px"/> </div><br>
|
||||
|
||||
### Zookeeper 的有序节点
|
||||
|
||||
#### 1. Zookeeper 抽象模型
|
||||
@@ -332,6 +334,8 @@ Acceptor 接受一个提议之后,会将该提议发送给所有的 Learner。
|
||||
- A 发送 Prepare(2),X 和 Y 做出承诺并响应。A 得到大多数响应之后发送 Accept(2, 8),X 和 Y 接受该提议,此时值 8 已经被选定;
|
||||
- 之后 B 发送 Prepare(4),它收到的大多数响应中至少有一个来自 X 或 Y,响应中包含已经接受过的提议 [2, 8],因此 B 只能发送 Accept(4, 8),而不能使用自己的提议值,从而保证了选定的值不会改变。
|
||||
|
||||
<div align="center"> <img src="pics/paxos-example.png" width="600px"/> </div><br>
|
||||
|
||||
### 约束条件
|
||||
|
||||
#### 1\. 正确性
|
||||
|
||||
@@ -111,6 +111,10 @@
|
||||
- 降级:主动关闭部分非核心功能,从而保证核心功能可用;
|
||||
- 熔断:某个依赖的服务持续出错时,暂时不再调用它而是直接返回默认结果,避免故障沿着调用链扩散。
|
||||
|
||||
熔断器有关闭、打开和半开三种状态:失败率超过阈值时打开;打开一段时间后进入半开状态,放行少量请求试探,成功则关闭,失败则重新打开。
|
||||
|
||||
<div align="center"> <img src="pics/circuit-breaker.png" width="500px"/> </div><br>
|
||||
|
||||
## 五、安全性
|
||||
|
||||
要求系统在应对各种攻击手段时能够有可靠的应对措施,常见的攻击手段和防范方法见 [攻击技术](攻击技术.md)。
|
||||
|
||||
@@ -128,6 +128,8 @@ CDN 主要有以下优点:
|
||||
|
||||
删除缓存而不是更新缓存,是因为两个并发的写操作到达缓存的顺序可能和到达数据库的顺序不同,导致缓存中是旧值。先更新数据库再删除缓存,是因为反过来的话,删除缓存之后、更新数据库之前的读请求会把旧值重新写入缓存。
|
||||
|
||||
<div align="center"> <img src="pics/cache-aside-race.png" width="500px"/> </div><br>
|
||||
|
||||
这种模式仍然存在小概率的不一致,例如删除缓存失败。常用的补救措施:
|
||||
|
||||
- 为缓存设置过期时间作为兜底;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="520" height="322" viewBox="0 0 520 322">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #666; font-size: 13px; }
|
||||
.head { font-weight: bold; text-anchor: middle; }
|
||||
.msg { text-anchor: middle; font-size: 12px; }
|
||||
.note { font-size: 12px; fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #777; text-anchor: middle; }
|
||||
.life { stroke: #BBB; stroke-width: 1; stroke-dasharray: 4 4; }
|
||||
.arrow { stroke: #666; stroke-width: 1.3; fill: none; marker-end: url(#a); }
|
||||
.reply { stroke-dasharray: 5 4; }
|
||||
.lost { stroke: #C0605A; marker-end: url(#x); }
|
||||
.shadow { fill: #C0C0C0; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#666" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="x" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#C0605A" stroke-width="1.6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
<text x="260" y="28" class="title">先删除缓存再更新数据库</text>
|
||||
<line x1="65" y1="76" x2="65" y2="302" class="life"/>
|
||||
<line x1="195" y1="76" x2="195" y2="302" class="life"/>
|
||||
<line x1="325" y1="76" x2="325" y2="302" class="life"/>
|
||||
<line x1="455" y1="76" x2="455" y2="302" class="life"/>
|
||||
<rect x="32" y="48" width="72" height="30" rx="6" class="shadow"/>
|
||||
<rect x="29" y="45" width="72" height="30" rx="6" fill="#B0E3E6"/>
|
||||
<text x="65" y="64.5" class="head">写请求</text>
|
||||
<rect x="162" y="48" width="72" height="30" rx="6" class="shadow"/>
|
||||
<rect x="159" y="45" width="72" height="30" rx="6" fill="#B1DDF0"/>
|
||||
<text x="195" y="64.5" class="head">缓存</text>
|
||||
<rect x="292" y="48" width="72" height="30" rx="6" class="shadow"/>
|
||||
<rect x="289" y="45" width="72" height="30" rx="6" fill="#B1DDF0"/>
|
||||
<text x="325" y="64.5" class="head">数据库</text>
|
||||
<rect x="422" y="48" width="72" height="30" rx="6" class="shadow"/>
|
||||
<rect x="419" y="45" width="72" height="30" rx="6" fill="#B0E3E6"/>
|
||||
<text x="455" y="64.5" class="head">读请求</text>
|
||||
<line x1="69" y1="100" x2="191" y2="100" class="arrow"/>
|
||||
<text x="130" y="94" class="msg">① 删除缓存</text>
|
||||
<line x1="451" y1="136" x2="199" y2="136" class="arrow"/>
|
||||
<text x="380" y="130" class="msg">② 读缓存未命中</text>
|
||||
<line x1="451" y1="172" x2="329" y2="172" class="arrow"/>
|
||||
<text x="390" y="166" class="msg">③ 读到旧值</text>
|
||||
<line x1="69" y1="208" x2="321" y2="208" class="arrow"/>
|
||||
<text x="120" y="202" class="msg">④ 更新为新值</text>
|
||||
<line x1="451" y1="244" x2="199" y2="244" class="arrow"/>
|
||||
<text x="380" y="238" class="msg">⑤ 把旧值写入缓存</text>
|
||||
<text x="260" y="284" class="note" text-anchor="middle">缓存中一直是旧值,直到被删除或过期</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="520" height="270" viewBox="0 0 520 270">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #666; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #777; text-anchor: middle; }
|
||||
.state { font-weight: bold; font-size: 14px; text-anchor: middle; }
|
||||
.en { font-size: 10px; fill: #888; text-anchor: middle; }
|
||||
.arrow { stroke: #666; stroke-width: 1.3; fill: none; marker-end: url(#a); }
|
||||
.shadow { fill: #C0C0C0; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#666" stroke-width="1.6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
<text x="260" y="28" class="title">熔断器状态</text>
|
||||
|
||||
<!-- 关闭:正常调用 -->
|
||||
<rect x="58" y="81" width="110" height="44" rx="6" class="shadow"/>
|
||||
<rect x="55" y="78" width="110" height="44" rx="6" fill="#B0E3E6"/>
|
||||
<text x="110" y="98" class="state">关闭</text>
|
||||
<text x="110" y="114" class="en">Closed,正常调用</text>
|
||||
|
||||
<!-- 打开:直接返回默认结果 -->
|
||||
<rect x="358" y="81" width="110" height="44" rx="6" class="shadow"/>
|
||||
<rect x="355" y="78" width="110" height="44" rx="6" fill="#F3C6C2"/>
|
||||
<text x="410" y="98" class="state">打开</text>
|
||||
<text x="410" y="114" class="en">Open,直接返回</text>
|
||||
|
||||
<!-- 半开:放行少量试探请求 -->
|
||||
<rect x="208" y="193" width="110" height="44" rx="6" class="shadow"/>
|
||||
<rect x="205" y="190" width="110" height="44" rx="6" fill="#B1DDF0"/>
|
||||
<text x="260" y="210" class="state">半开</text>
|
||||
<text x="260" y="226" class="en">Half-Open,少量试探</text>
|
||||
|
||||
<line x1="169" y1="100" x2="351" y2="100" class="arrow"/>
|
||||
<text x="260" y="92" text-anchor="middle">失败率超过阈值</text>
|
||||
|
||||
<line x1="378" y1="125" x2="297" y2="187" class="arrow"/>
|
||||
<text x="318" y="145" text-anchor="end">等待一段时间</text>
|
||||
|
||||
<line x1="310" y1="190" x2="391" y2="128" class="arrow"/>
|
||||
<text x="362" y="176">试探请求失败</text>
|
||||
|
||||
<line x1="218" y1="190" x2="137" y2="128" class="arrow"/>
|
||||
<text x="160" y="176" text-anchor="end">试探请求成功</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,59 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="448" viewBox="0 0 600 448">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #666; font-size: 13px; }
|
||||
.head { font-weight: bold; text-anchor: middle; }
|
||||
.msg { text-anchor: middle; font-size: 12px; }
|
||||
.note { font-size: 12px; fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #777; text-anchor: middle; }
|
||||
.life { stroke: #BBB; stroke-width: 1; stroke-dasharray: 4 4; }
|
||||
.arrow { stroke: #666; stroke-width: 1.3; fill: none; marker-end: url(#a); }
|
||||
.reply { stroke-dasharray: 5 4; }
|
||||
.lost { stroke: #C0605A; marker-end: url(#x); }
|
||||
.shadow { fill: #C0C0C0; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#666" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="x" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#C0605A" stroke-width="1.6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
<text x="300" y="28" class="title">栅栏令牌</text>
|
||||
<line x1="90" y1="76" x2="90" y2="428" class="life"/>
|
||||
<line x1="230" y1="76" x2="230" y2="428" class="life"/>
|
||||
<line x1="370" y1="76" x2="370" y2="428" class="life"/>
|
||||
<line x1="510" y1="76" x2="510" y2="428" class="life"/>
|
||||
<rect x="52" y="48" width="82" height="30" rx="6" class="shadow"/>
|
||||
<rect x="49" y="45" width="82" height="30" rx="6" fill="#B0E3E6"/>
|
||||
<text x="90" y="64.5" class="head">客户端 1</text>
|
||||
<rect x="197" y="48" width="72" height="30" rx="6" class="shadow"/>
|
||||
<rect x="194" y="45" width="72" height="30" rx="6" fill="#B1DDF0"/>
|
||||
<text x="230" y="64.5" class="head">锁服务</text>
|
||||
<rect x="332" y="48" width="82" height="30" rx="6" class="shadow"/>
|
||||
<rect x="329" y="45" width="82" height="30" rx="6" fill="#B0E3E6"/>
|
||||
<text x="370" y="64.5" class="head">客户端 2</text>
|
||||
<rect x="477" y="48" width="72" height="30" rx="6" class="shadow"/>
|
||||
<rect x="474" y="45" width="72" height="30" rx="6" fill="#B1DDF0"/>
|
||||
<text x="510" y="64.5" class="head">存储</text>
|
||||
<line x1="94" y1="100" x2="226" y2="100" class="arrow"/>
|
||||
<text x="160" y="94" class="msg">获取锁</text>
|
||||
<line x1="226" y1="134" x2="94" y2="134" class="arrow reply"/>
|
||||
<text x="160" y="128" class="msg">成功,令牌 33</text>
|
||||
<rect x="85" y="158" width="10" height="150" fill="#F3D9A4" stroke="#D9B44A"/>
|
||||
<text x="102" y="237" class="note"></text>
|
||||
<text x="78" y="172" class="note" text-anchor="end">GC 停顿</text>
|
||||
<text x="240" y="206" class="note" text-anchor="start">锁过期</text>
|
||||
<line x1="366" y1="236" x2="234" y2="236" class="arrow"/>
|
||||
<text x="300" y="230" class="msg">获取锁</text>
|
||||
<line x1="234" y1="270" x2="366" y2="270" class="arrow reply"/>
|
||||
<text x="300" y="264" class="msg">成功,令牌 34</text>
|
||||
<line x1="374" y1="304" x2="506" y2="304" class="arrow"/>
|
||||
<text x="440" y="298" class="msg">写入,令牌 34</text>
|
||||
<text x="500" y="342" class="note ok" text-anchor="end">接受,记录 34</text>
|
||||
<line x1="94" y1="372" x2="506" y2="372" class="arrow"/>
|
||||
<text x="140" y="366" class="msg">写入,令牌 33</text>
|
||||
<text x="500" y="410" class="note" text-anchor="end">拒绝,33 < 34</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,75 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="592" viewBox="0 0 640 592">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #666; font-size: 13px; }
|
||||
.head { font-weight: bold; text-anchor: middle; }
|
||||
.msg { text-anchor: middle; font-size: 12px; }
|
||||
.note { font-size: 12px; fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #777; text-anchor: middle; }
|
||||
.life { stroke: #BBB; stroke-width: 1; stroke-dasharray: 4 4; }
|
||||
.arrow { stroke: #666; stroke-width: 1.3; fill: none; marker-end: url(#a); }
|
||||
.reply { stroke-dasharray: 5 4; }
|
||||
.lost { stroke: #C0605A; marker-end: url(#x); }
|
||||
.shadow { fill: #C0C0C0; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#666" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="x" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#C0605A" stroke-width="1.6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
<text x="320" y="28" class="title">Paxos 示例</text>
|
||||
<line x1="64" y1="76" x2="64" y2="572" class="life"/>
|
||||
<line x1="192" y1="76" x2="192" y2="572" class="life"/>
|
||||
<line x1="320" y1="76" x2="320" y2="572" class="life"/>
|
||||
<line x1="448" y1="76" x2="448" y2="572" class="life"/>
|
||||
<line x1="576" y1="76" x2="576" y2="572" class="life"/>
|
||||
<rect x="15" y="48" width="104" height="30" rx="6" class="shadow"/>
|
||||
<rect x="12" y="45" width="104" height="30" rx="6" fill="#B0E3E6"/>
|
||||
<text x="64" y="64.5" class="head">Proposer A</text>
|
||||
<rect x="143" y="48" width="104" height="30" rx="6" class="shadow"/>
|
||||
<rect x="140" y="45" width="104" height="30" rx="6" fill="#B1DDF0"/>
|
||||
<text x="192" y="64.5" class="head">Acceptor X</text>
|
||||
<rect x="271" y="48" width="104" height="30" rx="6" class="shadow"/>
|
||||
<rect x="268" y="45" width="104" height="30" rx="6" fill="#B1DDF0"/>
|
||||
<text x="320" y="64.5" class="head">Acceptor Y</text>
|
||||
<rect x="399" y="48" width="104" height="30" rx="6" class="shadow"/>
|
||||
<rect x="396" y="45" width="104" height="30" rx="6" fill="#B1DDF0"/>
|
||||
<text x="448" y="64.5" class="head">Acceptor Z</text>
|
||||
<rect x="527" y="48" width="104" height="30" rx="6" class="shadow"/>
|
||||
<rect x="524" y="45" width="104" height="30" rx="6" fill="#B0E3E6"/>
|
||||
<text x="576" y="64.5" class="head">Proposer B</text>
|
||||
<line x1="68" y1="100" x2="188" y2="100" class="arrow"/>
|
||||
<text x="128" y="94" class="msg">Prepare(2)</text>
|
||||
<line x1="68" y1="130" x2="316" y2="130" class="arrow"/>
|
||||
<text x="240" y="124" class="msg">Prepare(2)</text>
|
||||
<line x1="188" y1="160" x2="68" y2="160" class="arrow reply"/>
|
||||
<text x="128" y="154" class="msg">承诺</text>
|
||||
<line x1="316" y1="190" x2="68" y2="190" class="arrow reply"/>
|
||||
<text x="240" y="184" class="msg">承诺</text>
|
||||
<line x1="68" y1="220" x2="188" y2="220" class="arrow"/>
|
||||
<text x="128" y="214" class="msg">Accept(2, 8)</text>
|
||||
<line x1="68" y1="250" x2="316" y2="250" class="arrow"/>
|
||||
<text x="240" y="244" class="msg">Accept(2, 8)</text>
|
||||
<line x1="188" y1="280" x2="68" y2="280" class="arrow reply"/>
|
||||
<text x="128" y="274" class="msg">接受</text>
|
||||
<line x1="316" y1="310" x2="68" y2="310" class="arrow reply"/>
|
||||
<text x="240" y="304" class="msg">接受</text>
|
||||
<text x="320" y="344" class="note ok" text-anchor="middle">X、Y 构成多数派,值 8 已被选定</text>
|
||||
<line x1="572" y1="370" x2="452" y2="370" class="arrow"/>
|
||||
<text x="512" y="364" class="msg">Prepare(4)</text>
|
||||
<line x1="572" y1="400" x2="324" y2="400" class="arrow"/>
|
||||
<text x="400" y="394" class="msg">Prepare(4)</text>
|
||||
<line x1="452" y1="430" x2="572" y2="430" class="arrow reply"/>
|
||||
<text x="512" y="424" class="msg">承诺</text>
|
||||
<line x1="324" y1="460" x2="572" y2="460" class="arrow reply"/>
|
||||
<text x="400" y="454" class="msg">承诺,已接受 [2, 8]</text>
|
||||
<line x1="572" y1="490" x2="452" y2="490" class="arrow"/>
|
||||
<text x="512" y="484" class="msg">Accept(4, 8)</text>
|
||||
<line x1="572" y1="520" x2="324" y2="520" class="arrow"/>
|
||||
<text x="400" y="514" class="msg">Accept(4, 8)</text>
|
||||
<text x="320" y="554" class="note" text-anchor="middle">B 只能沿用值 8,不能使用自己的提议值</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |