复制#
分片#
key range,
hash mod,
hash range,
fixed sharding,
hash ring
rebalance
事务#
读未提交,读已提交,可重复读,可串行化
问题#
节点 / 网络不可靠#
- 请求丢失
- 响应丢失
- 请求 / 响应超时
- 节点宕机
因为网络不可靠,因此要检查故障是否存在,将故障节点的任务转移到其他节点上 - 负载均衡器需要停止向已死亡的节点转发请求
- 主节点丢失需要重新选立主节点
网络的不确定性使得很难判断节点是否正常工作,所以只能通过心跳机制来确认节点是否可用。
长超时意味着在节点被宣布死亡之前需要长时间等待。
短超时可以更快地检测故障,但错误地宣布节点死亡的风险更高(因为网络拥堵而超时)。
过早地宣布节点死亡是有问题的:如果节点实际上是活着的并且正在执行某些操作(例如,发送电子邮件),而另一个节点接管,该操作可能最终被执行两次。
假设有一个虚构的系统,其网络保证数据包的最大延迟 —— 每个数据包要么在某个时间 d 内交付,要么丢失,但交付从不会超过 d。此外,假设你可以保证未失效的节点总是在某个时间 r 内处理请求。在这种情况下,你可以保证每个成功的请求在时间 2_d_ + r 内收到响应 —— 如果你在该时间内没有收到响应,你就知道网络或远程节点不工作。如果这是真的,2_d_ + r 将是一个合理的超时时间。
不幸的是,我们使用的大多数系统都没有这些保证:异步网络具有 无界延迟(即,它们尝试尽快交付数据包,但数据包到达所需的时间没有上限),大多数服务器实现无法保证它们可以在某个最大时间内处理请求。对于故障检测,系统大部分时间快速运行是不够的:如果你的超时很低,往返时间的瞬时峰值就足以使系统失去平衡。
当节点被宣布死亡时,其职责需要转移到其他节点,这会给其他节点和网络带来额外的负载。如果系统已经在高负载下挣扎,过早地宣布节点死亡可能会使问题变得更糟。特别是,可能发生的情况是,节点实际上并没有死亡,只是由于过载而响应缓慢;将其负载转移到其他节点可能会导致级联故障(在极端情况下,所有节点互相宣布对方死亡,一切都停止工作
同步与异步网络#
同步网络:数据在通过路由器时,需要的带宽和空间已经在网络的下一跳中预留了,无需排队,网络的最大端到端延迟是固定的,称为 有界延迟。典型的如电话网络。(带宽稳定)
异步网络:数据在通过路由器时,需要进行排队。排队延迟不固定,属于无界延迟。互联网就是如此。(带宽不稳定,多数时间处于低谷,有突发峰值)
部分混合网络试图同时支持分组交换 / 电路交换,如_异步传输模式_(ATM),但它在与以太网的竞争中失败。
时钟不可靠#
共识#
一致性
强一致性
最终一致性
线性一致性
一致性是一个业务概念
ID 生成器与时钟
id 和时钟就是唯一表示一个实体,时钟则在逻辑上有序。
但在分布式环境下,id 生成器不可靠,传统意义上的时钟也不可靠 (时间不同步)
所以需要引入逻辑时钟
Lamport 时间戳(计数器,节点 ID),与时间时间无关,依赖于节点频繁通信
进一步改造为混合逻辑时钟
单独仍然依赖于节点通信
线性一致的 id 生成器,需要一个单点 id 服务。或者运用类似于 Google spanner 那样的时间戳 + 置信区间 (需要软硬件支持),等待不确定性间隔的持续时间过去后再返回,这样保证有序。
共识
分布式中状态不可靠,需要一个共识机制让节点就事实达成一致。比如主节点。
FLP 结果,在节点会失败的环境中,可靠的容错不可行,
单值共识
CAS 共识
日志共识
GAI 共识
原子提交共识