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 + + + 正向依次执行 + 失败后逆序补偿 +