Skip to content

Lec 15 分布式数据库

总览

IMPORTANT

  • 并行数据库: 研究如何让多个处理器/机器来执行一个SQL查询的不同部分。
    • 特别适用于大规模、运行缓慢的查询
  • 分布式数据库:当这些机器物理上分离并独立故障时会发生什么
    • 特别适用于事务处理
  • 并行架构
  • 并行查询处理
  • 并行操作
  • Join策略
  • 并行策略

并行处理数据库

  • 目标:在多个处理器上加快SQL的查询

  • 怎么判断是否执行更快? 或者说评价指标是什么

    • 加速比 在同个问题上的 speed up(加速比) = 原耗时时间/新耗时时间
    • 放大比 scale up(放大) = 在一倍机器上的一倍的问题 / N倍的机器上的N倍问题
    • 两者不一定相同,小问题的可能意味着很难并行化
  • 数据库特别指标

    • 事务加速比(Transaction speedup): 固定的一组事务,用1 vs N 个机器做比较

    • 批量加速比(Batch speedup): 固定大小DB,用1 vs N个机器

    • 事务放大比(Transaction scaleup): 用N个机器来执行N 倍的事务来与单个机器和单个事务做比较

    • 批量放大比(Batch scaleup): 用N个机器来执行用N倍的一个事务来与单个机器和单个事务做比较

  • 加速比目标

    • 截屏2024-04-01 15.08.31
    • 线性增长的阻碍
      • 启动时间。启动并行执行器需要花费一点时间
      • 干扰竞争(interference contention): 受限于一些共享资源;比如输入输出队列,等等
      • 工作倾斜: 每个处理器分配的工作量并不相同
      • 几乎所有的工作量的增长都会某个点停止
    • 可并行工作量的性质
      • 提供线性的加速比
      • 通常能够被分解成若干小的单元独立执行
      • 我们将会看到,关系模型通常会提供这个性质

并行架构

有几种方法来并行化数据库

  • Shared Everything——共享所有

    • 截屏2024-04-01 15.28.27
    • 优点
      • 容易构建多核计算机就是如此,易于编程
      • 多线程执行
      • 每个核都能访问任何记录
    • 缺点
      • 没有容错;如果内存/甚至一个处理器崩了,那么这个模型也就崩了
      • 难以在一些核上扩展
  • Shared-Disk——共享磁盘

    • 截屏2024-04-01 15.28.43
    • 多机器;每个机器都能访问磁盘的任何记录
    • 需要协调机制保证写入磁盘是安全的(缓存一致性)
    • 磁盘会抽象成服务
    • 容错机制取决于可靠磁盘阵列,成本较高
    • Oracle用的很多
  • Shared-Nothing——分布式

    • 截屏2024-04-01 15.48.22
    • 多机器
    • 数据分区;每个机器各自负责处理&修改其负责的数据;意味着需要新的并发控制/恢复机制
    • 扩展性非常好: 添加机器或者分区都非常容易
    • 通过复制技术来容错
  • Shared-Nothing——基于分布式文件系统的分布式

    截屏2024-04-02 12.05.23

    • 将存储扩展与计算扩展分离
    • 存储层实现了容错机制
    • 数据进行了逻辑分区且被不同的处理器操作
    • 在云计算已经很普遍了,比如SnowFlake、MapReduce

小结

优点缺点
共享内存容易构建
并发控制和恢复无需更改
性能、扩展性和容错较差
共享磁盘更好的扩展性和容错复杂的缓存一致性
扩展性差
依赖高昂的磁盘阵列
无共享(分区数据)成本低,扩展性好、容错性好传统的并发控制和恢复机制(如事务锁、日志恢复等)需要重新设计
由于数据被分区并分布在多个节点上,因此执行查询或操作时需要新的执行引擎

并行化查询处理

有三种方法并行

  • 运行多条查询,每个查询都在不同的线程

  • 流水线并行: 不同的线程执行各自的操作

    • 截屏2024-04-02 12.35.37
  • 分区并行:不同的处理器处理每个分区

    • 截屏2024-08-20 10.17.42

流水线并行

  • 只有在每个流水线阶段的速度大致相同时才有效
  • 只能在有限的阶段内实现并行化
  • 在阶段i+1的输入取决于阶段i
  • 如果阶段i阻塞了(比如,排序),将会“阻塞”流水线
  • 由于以上管道并行的局限性,数据库系统通常采用分区并行来实现扩展

分区并行

数据分区策略
  • 随机/轮转分区

    • 截屏2024-08-20 11.03.59
    • 优点:负载比较平均,没有数据倾斜(no skew),
    • 缺点:
      • 连接时, 需要我们重新分区(repartitioning),重新分区目的是使得具有相同连接属性的记录被分到同一个分区中
      • 不能提供下推谓词的能力
  • 范围分区

    • 截屏2024-08-20 11.04.24
    • 当表根据连接属性被分区好了后,允许我们用连接而无需重新分区
    • 优点:容易下推谓词(根据分区的属性)
    • 缺点:
      • 难以保证等量的分区,特别是插
  • Hash分区

    • 截屏2024-08-20 11.13.37
    • 当表根据连接属性被分区好了后,允许我们用连接而无需重新分区
    • 数据倾斜问题主要发生在数据中存在大量重复值的情况下
    • 优点:每个分区大小大致相同,除非相同值非常频繁;有可能能够下推等价谓词(基于分区属性)
    • 缺点:不能下推范围谓词

在分区数据库中的并行操作

选择SELECT

  • 很自然”下推“到每个工作者
  • 取决与分区属性,可能可以跳过一些分区

投影PROJECT

  • 假设所有列都在每个节点上,没什么可做的

连接JOIN

  • 取决于数据分区,能够处理独立的分区,然后Merge,或者可能需要重分区

聚合AGGREGATE

  • 在每个节点分别聚合,然后Merge最终结果

Join 策略

  • 如果按照相同属性进行分区后,只在本地运行Join操作
    • 并且,如果一个表被复制到所有节点上,就不需要join了
  • 否则,有几个选项:
    • 将所有表搜集到一个节点
      • 这种方法通常不理想,除非在极端情况下,例如当表非常小的时候
    • 重新分区一个或两个表——"shuffle join"
      • 根据初始的分区策略,可以选择重新分区一个或两个表
    • 在所有节点上复制(较小的)表

根据连接属性预分区

  • 查询: SELECT * FROM A, B WHERE A.a = B.b

  • 假设我们hash 在A的a属性,用hash函数 F 来得到F(A, a) ->1...n (n = #machines)

  • 同样地,用hash函数F来对B进行Hash

  • 由于A和B使用了相同的hash函数,意味着相匹配的记录都会被分配到相同分区

截屏2024-08-20 12.25.14

重新分区例子——”shuffle join“

  • 假设表A对a属性进行了预分区,因此不需要重新分区
  • 表B也要按照属性a进行连接,但是初始分区与表A不一致,因此需要重新分区
  • 有n个节点处理这个分区

截屏2024-04-02 14.50.05

重新分区操作
  1. 重新分区:
    • 表B的每个分区被分割成n个新分区(每个节点一个新分区)
    • 每个节点会把它持有的分区数据按照分区规则分配到所有n个节点中,包括自身。这意味着每个节点都会把原分区分割成n份,发送到n个不同节点
  2. 数据传输:
    • 假设表B的分区大小是|B|/n 字节,因此每一份大小就是|B|/n / n字节
    • 因为每个节点上都有一个新的分区,所以每个节点需要把n-1份数据发送到其他节点,每份数据大小为|B|/n2

每台机器需要接受和发送多少字节的数据?

截屏2024-08-20 12.27.59

  • 每个分区有 |B| / n个记录, 重分区将它水平拆分成n个chunk,每个节点发送n-1
  • 每个节点: 发送 = 接受 =$ (n-1) * |B| / n^2$ bytes

假如表A,B都需要重新分区,每台机器需要接受和发送多少字节的数据?

每个节点: $(|A| / n^2)* (n-1) + (|B|/n^2) * (n-1) $​bytes

复制的例子

  • 假设我们需要将B复制到所有节点
  • 在复制策略中,较小的表需要被复制到所有其他节点上。每个节点发送的字节数计算公式为 |B|/n(n1)
  • 截屏2024-08-20 12.59.16

复制 vs. 分区

  • 复制需要每个节点将较小的表发送给所有其他节点
    • 每个节点发送 (|T| / n) * (n-1) 字节
    • 而重分区一个表的情况下,每个节点发送 ((|T| / n) / n) * (n-1) 字节
  • 在什么情况下,复制会优于重分区来执行连接操作?
    • 如果较小表的大小 小于 需要重分区一个或两个表时发送的数据量。
    • 还需考虑连接操作的成本:使用复制的表时成本会更高。

例子:假设 |B| = 1 MB|A| = 100 MBn = 3

  • 需要对 A 进行重分区(B 按连接属性分布)。

    • 重分区策略:重分区 A 的每个节点数据量为 |A| / 3 / 3 * 2 = 22.2 MB

      • 这个数据量明显大于B表大小,所以重分区A表开销较高
      • 连接操作将 .33 MB 的数据与 33 MB 的数据进行连接。
    • 复制策略:广播 B 的数据量为 |B| = 1 MB,即 1 / 3 * 2 = 0.66 MB

      • 连接 1 MB 数据与 33 MB 数据进行连接。

结论: 分布式数据库执行连接操作时

  • 当较小表的大小小于重分区时所需传输的数据量时,复制会是更好的选择。复制可以避免复杂的重分区操作,尤其是当较小表的大小相对较小时
  • 如果需要进行连接的表大小较大

假设我们有两个表 A 和 B,它们分布在 3 个节点上。

A 的大小为 9 MB。

B 的大小为 90 MB。

连接条件是 A.a = B.b

  • B 表根据 b 属性进行了哈希分区,而 A 表没有根据 a 属性分区。

如果我们执行以下操作,每个节点需要发送多少数据:

  1. 重分区 A 表。
  2. 复制 A 表。

Solution: 1. (9 / 3) / 3 * 2 = 2MB ; 2. 9 / 3 * 2 = 6MB

其他选择

  • 预先复制小表
    • 如果空间允许,是一个不错的选择
  • ”半连接“
    • 首先,将 B 表的连接属性值(例如 B.b)的列表发送给 A 表所在的节点。
    • 然后,A 表仅选择那些与 B 表中的值匹配的记录,并将这些匹配记录发送回 B 表所在的节点
    • 最后,B 表使用从 A 表接收到的匹配记录列表来完成最终的连接计算
    • 适合处理宽表(列数多的表),因为宽表的数据量较大,直接传输会很耗费资源。通过预过滤,只传输在 B 表中实际存在的值,避免了不必要的数据传输,提高了效率

半连接的例子

聚合策略

截屏2024-08-20 14.40.34

通常来说,每个几点

DP并行处理 vs 一般的并行处理

  • 无共享分区并行是主流的方法。

  • 为关系模型欢呼!

    • 在并行化系统时,应用程序无需更改(物理数据独立性!)。

    • 可以在不更改应用程序的情况下调整和扩展系统!

    • 可以任意划分记录,无需同步。

  • 基本上没有同步,除了设置和拆除阶段。

    • 没有障碍、缓存一致性等问题。

    • 数据库事务在并行处理中工作良好。