diff --git a/ch6-cloud/ch6-03-delay-job.md b/ch6-cloud/ch6-03-delay-job.md index 63901b3..8059b7b 100644 --- a/ch6-cloud/ch6-03-delay-job.md +++ b/ch6-cloud/ch6-03-delay-job.md @@ -19,38 +19,7 @@ timer 的实现在工业界已经是有解的问题了。常见的就是时间 最常见的时间堆一般用小顶堆实现,小顶堆其实就是一种特殊的二叉树: -``` - ┌─────┐ - │ │ - │ 5 │ - └─────┘ - │ - │ - ┌──────────┴──────────┐ - │ │ - ▼ ▼ - ┌─────┐ ┌─────┐ - │ │ │ │ - │ 6 │ │ 10 │ - └─────┘ └─────┘ - │ │ - ┌────┴─────┐ ┌────┴─────┐ - │ │ │ │ - ▼ ▼ ▼ ▼ - ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ - │ │ │ │ │ │ │ │ - │ 7 │ │ 6 │ │ 11 │ │ 20 │ - └─────┘ └─────┘ └─────┘ └─────┘ - │ │ - │ │ - ┌───────┴────┐ └───────┐ - │ │ │ - ▼ ▼ ▼ -┌─────┐ ┌─────┐ ┌─────┐ -│ │ │ │ ............... │ │ -│ 15 │ │ 8 │ │ 30 │ -└─────┘ └─────┘ └─────┘ -``` +![二叉堆](../images/ch6-binary_tree.png) 小顶堆的好处是什么呢?实际上对于定时器来说,如果堆顶元素比当前的时间还要大,那么说明堆内所有元素都比当前时间大。进而说明这个时刻我们还没有必要对时间堆进行任何处理。所以对于定时 check 来说,时间复杂度是 O(1) 的。 @@ -58,34 +27,7 @@ timer 的实现在工业界已经是有解的问题了。常见的就是时间 Go 自身的 timer 就是用时间堆来实现的,不过并没有使用二叉堆,而是使用了扁平一些的四叉堆。在最近的版本中,还加了一些优化,我们先不说优化,先来看看四叉的小顶堆长什么样: -``` - +-----+ - | | - | 0 | - +-----+ - | - | - | - v - +-----+-----+-----+-----+ - | | | | | - | 3 | 2 | 2 | 10 | - +-----+-----+-----+-----+ - | | | | - | | | | - +----------+ | | | | - +----------------+ 4*i+1 +-----------------------+ | | +-----------------------------+ - | +----------+ +-------------------+ +---+ | - | | | | - | | | | - v | | v -+-----+-----+-----+-----+ | | +-----+-----+-----+-----+ -| | | | | v v | | | | | -| 20 | 4 | 5 | 13 | +-----+-----+-----+-----+ +-----+-----+-----+-----+ | 99 | 13 | 11 | 12 | -+-----+-----+-----+-----+ | | | | | | | | | | +-----+-----+-----+-----+ - | 12 | 14 | 15 | 16 | | 3 | 10 | 3 | 3 | - +-----+-----+-----+-----+ +-----+-----+-----+-----+ -``` +![四叉堆](../images/ch6-four-branch-tree.png) 小顶堆的性质,父节点比其 4 个子节点都小,子节点之间没有特别的大小关系要求。 @@ -126,29 +68,7 @@ Go 自身的 timer 就是用时间堆来实现的,不过并没有使用二叉 我们可以参考 elasticsearch 的设计,每份任务数据都有多个副本,这里假设两副本: -``` -┌──────────┐ -│ node 1 │ -├──────────┴────────────────────────┐ -│ ┏━━━┓ ┌───┐ ┌───┐ ┏━━━┓ │ -│ ┃ 0 ┃ │ 1 │ │ 3 │ ┃ 4 ┃ │ -│ ┗━━━┛ └───┘ └───┘ ┗━━━┛ │ -└───────────────────────────────────┘ -┌──────────┐ -│ node 2 │ -├──────────┴────────────────────────┐ -│ ┌───┐ ┏━━━┓ ┏━━━┓ │ -│ │ 0 │ ┃ 2 ┃ ┃ 3 ┃ │ -│ └───┘ ┗━━━┛ ┗━━━┛ │ -└───────────────────────────────────┘ -┌──────────┐ -│ node 3 │ -├──────────┴────────────────────────┐ -│ ┏━━━┓ ┌───┐ ┌───┐ │ -│ ┃ 1 ┃ │ 2 │ │ 4 │ │ -│ ┗━━━┛ └───┘ └───┘ │ -└───────────────────────────────────┘ -``` +![数据分布](../images/ch6-data-dist1.png) 一份数据虽然有两个持有者,但持有者持有的副本会进行区分,比如持有的是主副本还是非主副本,主副本在图中为摸黑部分,非主副本为正常线条。 @@ -156,29 +76,7 @@ Go 自身的 timer 就是用时间堆来实现的,不过并没有使用二叉 当有机器故障时,任务数据需要进行 rebalance 工作,比如 node 1 挂了: -``` -┌──────────┐ -│ node 1 │ -├──────────┴────────────────────────┐ -│ │ -│ X X X │ -│ │ -└───────────────────────────────────┘ -┌──────────┐ -│ node 2 │ -├──────────┴────────────────────────┐ -│ ┌───┐ ┌───┐ ┏━━━┓ ┏━━━┓ ┏━━━┓ │ -│ │ 0 │ │ 1 │ ┃ 2 ┃ ┃ 3 ┃ ┃ 4 ┃ │ -│ └───┘ └───┘ ┗━━━┛ ┗━━━┛ ┗━━━┛ │ -└───────────────────────────────────┘ -┌──────────┐ -│ node 3 │ -├──────────┴────────────────────────┐ -│ ┏━━━┓ ┏━━━┓ ┌───┐ ┌───┐ ┌───┐ │ -│ ┃ 0 ┃ ┃ 1 ┃ │ 2 │ │ 3 │ │ 4 │ │ -│ ┗━━━┛ ┗━━━┛ └───┘ └───┘ └───┘ │ -└───────────────────────────────────┘ -``` +![数据分布2](../images/ch6-data-dist2.png) node 1 的数据会被迁移到 node 2 和 node 3 上。 diff --git a/images/ch6-binary_tree.png b/images/ch6-binary_tree.png new file mode 100644 index 0000000..6d9b3c3 Binary files /dev/null and b/images/ch6-binary_tree.png differ diff --git a/images/ch6-data-dist1.png b/images/ch6-data-dist1.png new file mode 100644 index 0000000..d4eac17 Binary files /dev/null and b/images/ch6-data-dist1.png differ diff --git a/images/ch6-data-dist2.png b/images/ch6-data-dist2.png new file mode 100644 index 0000000..eee8460 Binary files /dev/null and b/images/ch6-data-dist2.png differ diff --git a/images/ch6-four-branch-tree.png b/images/ch6-four-branch-tree.png new file mode 100644 index 0000000..360914a Binary files /dev/null and b/images/ch6-four-branch-tree.png differ