diff --git a/notes/Java 容器.md b/notes/Java 容器.md
index b7068ad9..600f36e2 100644
--- a/notes/Java 容器.md
+++ b/notes/Java 容器.md
@@ -754,6 +754,8 @@ new capacity : 00100000
- 为 0,那么 hash%00010000 = hash%00100000,桶位置和原来一致;
- 为 1,hash%00100000 = hash%00010000 + 16,桶位置是原位置 + 16。
+
+
#### 7. 计算数组容量
HashMap 构造函数允许用户传入的容量不是 2 的 n 次方,因为它可以自动地将传入的容量转换为 2 的 n 次方。
diff --git a/notes/Socket.md b/notes/Socket.md
index 48d65ed3..56cbad75 100644
--- a/notes/Socket.md
+++ b/notes/Socket.md
@@ -234,6 +234,8 @@ epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描
从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得事件完成的描述符。
+
+
epoll 仅适用于 Linux OS。
epoll 比 select 和 poll 更加灵活而且没有描述符数量限制。
diff --git a/notes/pics/bloom-filter.png b/notes/pics/bloom-filter.png
new file mode 100644
index 00000000..6937dad6
Binary files /dev/null and b/notes/pics/bloom-filter.png differ
diff --git a/notes/pics/consumer-group.png b/notes/pics/consumer-group.png
new file mode 100644
index 00000000..2041c12c
Binary files /dev/null and b/notes/pics/consumer-group.png differ
diff --git a/notes/pics/csrf.png b/notes/pics/csrf.png
new file mode 100644
index 00000000..8ff486a2
Binary files /dev/null and b/notes/pics/csrf.png differ
diff --git a/notes/pics/epoll.png b/notes/pics/epoll.png
new file mode 100644
index 00000000..2f01bd30
Binary files /dev/null and b/notes/pics/epoll.png differ
diff --git a/notes/pics/hashmap-resize.png b/notes/pics/hashmap-resize.png
new file mode 100644
index 00000000..6288b753
Binary files /dev/null and b/notes/pics/hashmap-resize.png differ
diff --git a/notes/pics/lru.png b/notes/pics/lru.png
new file mode 100644
index 00000000..38da77b8
Binary files /dev/null and b/notes/pics/lru.png differ
diff --git a/notes/pics/next-key-locks.png b/notes/pics/next-key-locks.png
new file mode 100644
index 00000000..94cf0dee
Binary files /dev/null and b/notes/pics/next-key-locks.png differ
diff --git a/notes/pics/rate-limit.png b/notes/pics/rate-limit.png
new file mode 100644
index 00000000..f79e7b14
Binary files /dev/null and b/notes/pics/rate-limit.png differ
diff --git a/notes/pics/rocketmq-transaction.png b/notes/pics/rocketmq-transaction.png
new file mode 100644
index 00000000..431ac11f
Binary files /dev/null and b/notes/pics/rocketmq-transaction.png differ
diff --git a/notes/pics/saga.png b/notes/pics/saga.png
new file mode 100644
index 00000000..9232b074
Binary files /dev/null and b/notes/pics/saga.png differ
diff --git a/notes/分布式.md b/notes/分布式.md
index 7cd66180..7b3373fc 100644
--- a/notes/分布式.md
+++ b/notes/分布式.md
@@ -210,6 +210,8 @@ TCC(Try-Confirm-Cancel)是在业务层面实现的两阶段提交,每个
Saga 将一个分布式事务拆分为多个本地事务,每个本地事务直接提交,并且都有一个对应的补偿操作。依次执行各个本地事务,如果某一个失败,就逆序执行前面已经提交的本地事务的补偿操作。
+
+
Saga 没有预留资源的 Try 阶段,中间状态对其它事务可见,因此没有隔离性。它适合流程长、无法长时间锁定资源的业务,正向操作和补偿操作同样需要实现幂等。
### 本地消息表
@@ -226,6 +228,8 @@ Saga 没有预留资源的 Try 阶段,中间状态对其它事务可见,因
RocketMQ 的事务消息把本地消息表的工作交给了消息队列:生产者先发送一条对消费者不可见的半消息,再执行本地事务,然后根据执行结果通知 Broker 提交或者回滚这条消息。如果 Broker 长时间没有收到通知,会主动回查生产者的本地事务状态。
+
+
## 三、CAP
分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)和分区容忍性(P:Partition Tolerance)。常见的“三选二”说法有误导性,因为网络分区是无法避免的故障,不是可以选择的选项。
diff --git a/notes/攻击技术.md b/notes/攻击技术.md
index b92735f6..9c56e27c 100644
--- a/notes/攻击技术.md
+++ b/notes/攻击技术.md
@@ -122,6 +122,8 @@ http://www.examplebank.com/withdraw?account=AccountName&amount=1000&for=PayeeNam
如果有账户名为 Alice 的用户访问了恶意站点,而之前刚访问过银行不久,登录信息尚未过期,那么就会损失 1000 美元。
+
+
这种恶意的网址可以有很多种形式,藏身于网页中的许多地方。此外,攻击者也不需要控制放置恶意网址的网站。例如他可以将这种地址藏在论坛,博客等任何用户生成内容的网站中。这意味着如果服务器端没有合适的防御措施的话,用户即使访问熟悉的可信网站也有受攻击的危险。改为 POST 请求也不能解决问题,攻击者可以使用自动提交的表单。
通过例子能够看出,攻击者并不能通过 CSRF 攻击来直接获取用户的账户控制权,也不能直接窃取用户的任何信息。他们能做到的,是欺骗用户浏览器,让其以用户的名义执行操作。
diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md
index ec7b72c6..59006f30 100644
--- a/notes/数据库系统原理.md
+++ b/notes/数据库系统原理.md
@@ -362,6 +362,8 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
(20, +∞)
```
+
+
## 七、关系数据库设计理论
### 函数依赖
diff --git a/notes/消息队列.md b/notes/消息队列.md
index 5e5779d0..1e082281 100644
--- a/notes/消息队列.md
+++ b/notes/消息队列.md
@@ -34,6 +34,8 @@
Kafka、RocketMQ 等通过消费者组把两种模型结合起来:一条消息会发送给每个订阅它的消费者组,但在一个消费者组内只会被一个消费者消费。
+
+
发布与订阅模式和观察者模式有以下不同:
- 观察者模式中,观察者和主题都知道对方的存在;而在发布与订阅模式中,生产者与消费者不知道对方的存在,它们之间通过频道进行通信。
diff --git a/notes/系统设计基础.md b/notes/系统设计基础.md
index fa9c0e97..84e0dc5a 100644
--- a/notes/系统设计基础.md
+++ b/notes/系统设计基础.md
@@ -111,6 +111,10 @@
- 降级:主动关闭部分非核心功能,从而保证核心功能可用;
- 熔断:某个依赖的服务持续出错时,暂时不再调用它而是直接返回默认结果,避免故障沿着调用链扩散。
+漏桶以固定速率处理请求,桶满时丢弃新的请求;令牌桶以固定速率放入令牌,请求拿到令牌才能被处理,桶中积累的令牌允许一定的突发流量。
+
+
+
熔断器有关闭、打开和半开三种状态:失败率超过阈值时打开;打开一段时间后进入半开状态,放行少量请求试探,成功则关闭,失败则重新打开。
diff --git a/notes/缓存.md b/notes/缓存.md
index 1a6cffa1..08831347 100644
--- a/notes/缓存.md
+++ b/notes/缓存.md
@@ -97,6 +97,10 @@ CDN 主要有以下优点:
- 对这些不存在的数据缓存一个空数据,并设置较短的过期时间;
- 使用布隆过滤器保存所有存在的 Key,对不存在的 Key 的请求直接拒绝。
+布隆过滤器用多个哈希函数把 Key 映射到位数组的多个位置并置为 1。查询时只要有一个位置为 0,Key 就一定不存在;全部为 1 时 Key 可能存在,存在一定的误判率。
+
+
+
### 缓存击穿
指的是某个热点数据的缓存过期时,大量对它的请求同时到达数据库。
@@ -200,6 +204,8 @@ Redis Cluster 使用的不是一致性哈希,而是把 Key 映射到固定的
- 访问某个节点时,将其从原来的位置删除,并重新插入到链表头部。这样就能保证链表尾部存储的就是最近最久未使用的节点,当节点数量大于缓存最大空间时就淘汰链表尾部的节点。
- 为了使删除操作时间复杂度为 O(1),就不能采用遍历的方式找到某个节点。HashMap 存储着 Key 到节点的映射,通过 Key 就能以 O(1) 的时间得到节点,然后再以 O(1) 的时间将其从双向队列中删除。
+
+
Java 的 LinkedHashMap 内部就是这种结构,把 accessOrder 设为 true 并重写 removeEldestEntry 方法,就可以直接得到一个 LRU 缓存。
```java
diff --git a/tools/diagram/src/bloom-filter.svg b/tools/diagram/src/bloom-filter.svg
new file mode 100644
index 00000000..8d3a077d
--- /dev/null
+++ b/tools/diagram/src/bloom-filter.svg
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 布隆过滤器
+
+ 0
+ 0
+
+ 1
+ 1
+
+ 0
+ 2
+
+ 0
+ 3
+
+ 1
+ 4
+
+ 0
+ 5
+
+ 1
+ 6
+
+ 0
+ 7
+
+ 0
+ 8
+
+ 0
+ 9
+
+ 1
+ 10
+
+ 0
+ 11
+
+ 0
+ 12
+
+ 1
+ 13
+
+ 0
+ 14
+
+ 0
+ 15
+
+
+ key1
+
+
+ key2
+
+
+
+
+
+
+ 插入
+
+
+ key3
+
+
+ key4
+
+
+
+
+
+
+ 查询
+ 位 3 为 0
+ 一定不存在
+ 全为 1:可能存在
+ 实际未插入过,属于误判
+
diff --git a/tools/diagram/src/consumer-group.svg b/tools/diagram/src/consumer-group.svg
new file mode 100644
index 00000000..75d75b7c
--- /dev/null
+++ b/tools/diagram/src/consumer-group.svg
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 消费者组
+
+ Topic
+
+
+ 分区 0
+
+
+ 分区 1
+
+
+ 分区 2
+
+ 消费者组 A
+
+
+ A1
+
+
+ A2
+
+
+
+
+ 消费者组 B
+
+
+ B1
+
+
+ B2
+
+
+ B3
+
+
+ B4
+ 空闲
+
+
+
+ 同一个组内,每个分区只分配给一个消费者
+ 每个组都会收到 Topic 的全部消息
+
diff --git a/tools/diagram/src/csrf.svg b/tools/diagram/src/csrf.svg
new file mode 100644
index 00000000..2c61dbdb
--- /dev/null
+++ b/tools/diagram/src/csrf.svg
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+ CSRF 攻击过程
+
+
+
+
+
+ 用户浏览器
+
+
+ 银行网站
+
+
+ 恶意网站
+
+ ① 登录
+
+ Set-Cookie:会话 ID
+
+ ② 访问恶意网站
+
+ 返回含 <img src="转账 URL"> 的页面
+
+ ③ 自动请求转账 URL,携带 Cookie
+ Cookie 有效,执行转账
+
diff --git a/tools/diagram/src/epoll.svg b/tools/diagram/src/epoll.svg
new file mode 100644
index 00000000..b2f5a904
--- /dev/null
+++ b/tools/diagram/src/epoll.svg
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select / poll 与 epoll
+
+ select / poll
+
+
+ 用户进程
+
+ 用户态
+ 内核态
+
+ epoll
+
+
+ 用户进程
+
+ 用户态
+ 内核态
+
+ 每次调用复制
+ 全部描述符
+
+
+ 遍历全部描述符
+ 检查是否就绪
+
+ 返回后进程
+ 再遍历一次
+ 每次调用都是 O(N)
+
+ epoll_ctl()
+ 注册一次
+
+
+
+
+
+
+
+
+
+
+
+ 红黑树:已注册描述符
+
+
+
+
+
+ 就绪链表
+
+ 就绪时回调
+
+ epoll_wait()
+ 只取就绪的
+
diff --git a/tools/diagram/src/hashmap-resize.svg b/tools/diagram/src/hashmap-resize.svg
new file mode 100644
index 00000000..cbdaf2eb
--- /dev/null
+++ b/tools/diagram/src/hashmap-resize.svg
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HashMap 扩容时的桶下标
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ capacity = 16
+ 0
+ 5
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ capacity = 32
+ 0
+ 5
+ 21
+ 31
+
+
+ hash 低 5 位 0 0101
+ 第 5 位为 0:仍在 5
+ hash 低 5 位 1 0101
+ 第 5 位为 1:移到 5 + 16 = 21
+ 桶 5 中的键值对扩容后只会落在 5 或 21
+
diff --git a/tools/diagram/src/lru.svg b/tools/diagram/src/lru.svg
new file mode 100644
index 00000000..cd1643d6
--- /dev/null
+++ b/tools/diagram/src/lru.svg
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LRU:HashMap + 双向链表
+
+
+ head
+
+
+ k2
+
+
+ k3
+
+
+ k1
+
+
+ tail
+
+
+
+
+
+
+
+
+
+ HashMap
+
+ k2
+
+
+ k3
+
+
+ k1
+
+ 哨兵
+ 哨兵
+ 最近访问
+ 最久未访问,最先淘汰
+ 访问或插入时把节点移到 head 之后,超出容量时删除 tail 之前的节点
+
diff --git a/tools/diagram/src/next-key-locks.svg b/tools/diagram/src/next-key-locks.svg
new file mode 100644
index 00000000..857ec22f
--- /dev/null
+++ b/tools/diagram/src/next-key-locks.svg
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Next-Key Locks
+
+ (-∞, 10]
+
+ (10, 11]
+
+ (11, 13]
+
+ (13, 20]
+
+ (20, +∞)
+
+
+ 10
+
+ 11
+
+ 13
+
+ 20
+ -∞
+ +∞
+ Gap Lock (10, 11)
+ + Record Lock 11 = Next-Key Lock (10, 11]
+
+ 索引值 10、11、13、20,每个区间前开后闭
+
diff --git a/tools/diagram/src/rate-limit.svg b/tools/diagram/src/rate-limit.svg
new file mode 100644
index 00000000..70f3d027
--- /dev/null
+++ b/tools/diagram/src/rate-limit.svg
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 漏桶与令牌桶
+
+ 漏桶
+
+
+
+
+ 请求
+
+
+
+
+
+ 排队
+
+ 桶满丢弃
+
+ 固定速率处理
+
+ 令牌桶
+
+ 固定速率放入令牌
+
+
+
+
+
+
+ 桶满后不再放入
+
+
+ 请求
+
+ 取走令牌
+
+ 有令牌:处理
+ 没有令牌:拒绝
+ 积累的令牌允许突发流量
+
diff --git a/tools/diagram/src/rocketmq-transaction.svg b/tools/diagram/src/rocketmq-transaction.svg
new file mode 100644
index 00000000..49507e99
--- /dev/null
+++ b/tools/diagram/src/rocketmq-transaction.svg
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+ RocketMQ 事务消息
+
+
+
+
+
+ 生产者
+
+
+ Broker
+
+
+ 消费者
+
+ ① 发送半消息
+
+ ② 写入成功,消费者不可见
+ ③ 执行本地事务
+
+ ④ 根据事务结果提交或回滚
+ 长时间没有收到 ④ 时:
+
+ ⑤ 回查本地事务状态
+
+ ⑥ 提交或回滚
+
+ ⑦ 提交后投递消息
+
diff --git a/tools/diagram/src/saga.svg b/tools/diagram/src/saga.svg
new file mode 100644
index 00000000..b67d36aa
--- /dev/null
+++ b/tools/diagram/src/saga.svg
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Saga
+
+
+ T1
+ 本地事务提交
+
+
+ T2
+ 本地事务提交
+
+
+ T3
+ 失败
+
+
+
+
+ C1
+ 补偿 T1
+
+
+ C2
+ 补偿 T2
+
+
+ 正向依次执行
+ 失败后逆序补偿
+