数据湖核心技术 | 青训营笔记

114 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第 13 天!

设计一个简单的数据湖

1、文件结构

  • 存入数据,按照 date 分区,schema: image.png
  • 每天都会写入新数据
  • 需要使用列存格式 image.png
  • 写入数据时
    • 按照每条数据的 date 进行分区
    • 额外使用 metadata 文件记录表信息,如下:
{
    "schema": [
        {
            "name": "nuserID"
            "type": "int"
        },
        {
            "name": "date"
            "type": "string"
        },
        {
            "name": "event"
            "type": "string"
        },
        {
            "name": "phoneNumber"
            "type": "string"
        }
    ],
    "partition_col": "date",
    "location": "mytable/",
    "partition": [
        "2020-01-01",
        "2020-01-02"
    ]
}

2、Time Travel

  • 每次写入都生成一个新的元数据文件,记录变更
  • 分区数据在 Update 时,不要删除旧数据,保证新旧共存
  • 元数据中存储具体的文件路径,而不仅仅是分区文件夹 image.png
  • 每一次写入操作,创建一个新的 json 文件,以递增版本号命名,记录本次新增/删除的文件
  • 每当产生 N 个 json,做一次聚合,记录完整的分区文件信息
  • 用 checkpoint 记录上次做聚合的版本号
{
    ...
    "partition": [
        "2020-01-01"{
            "xxx.parquet",
            "yyy.parquet"
        }
        "2020-01-02"{
            "xxx.parquet",
            "yyy.parquet"
        }
    ]
}

3、Transaction

  • Transaction 即事务
  • ACID,是指数据库在写入或更新资料的过程中,为保证事务是正确可靠所必须具备的四个特性
  • Atomicity:原子性-本次写入要么对用户可见,要么不可见(需要设计)。如:要么 A-10、B+10,要么不变。
  • Consistency:一致性-落盘和输入一致(由计算引擎保证)。如:不可以 A-10、B+5。
  • Isolation:事务隔离-正确解决读写冲突和写写冲突(需要设计)。如:A和C同时给B转10,B最终结果是+20.
  • Durability:持久性-转账服务器重启,结果不变。(由储存引擎决定)。

(1)原子性

image.png

  • 写入流程
    • 写入 parquet 数据文件;
    • 写入 json 元数据文件。
  • 如何保证原子性(从用户可见性入手)
    • 用户只会读取以版本号数字命名的 json 文件,每次都能读取到最大的版本号作为数据集的现状;
    • 新的写入写完 parquet 后开始写 json 文件,使用 hash 值对 json 命名,如 xxx.json;
    • 直到 json 文件内容写入完毕,利用 HDFS 的 RenameIfAbsent 能力将 xxx.json 替换为 000006.json 作为最新版本。
  • 读写冲突已经被解决,how?
    • 新的写入除非已经 commit,否则用户读不到;
    • 用户正在读的分区,被另一个写入进行了更新,数据不会进行替换,而是共存。

(2)事务隔离

image.png

  • Update 写入流程
    • 从最新的版本中,获取需要 update 分区;
    • 乐观锁先把该写入的文件全落盘,然后进行写 json 阶段;
    • 分几种情况:
      • 1.发现版本号和一开始没区别,直接写新的版本;
      • 2.发现版本号增加了,看着新增的这些版本有没有更新我需要更新的分区:
        • 没有,直接写新的版本;
        • 有,两者都更新了同一分区,得重新 update。

4、Schema Evolution

  • Add/Drop/Rename
  • 重要:
    • 用户并不直接读取 parquet 文件本身,而是通过数据湖接口读取,如 Datasetds=simpleDataLake.read(mytable).option(date=2020-01-01)
    • 数据湖内部会读取应该读的 parquet,并在 schema 上做进一步处理
  • ID 将 data 和 metadata 的列名做一一对应!
    • 唯一确定的 ID、新增列赋予新 ID、删列 ID 不复用;
    • 写入数据时,ID 也写入数据文件;
    • 读取数据时,用 ID 做映射,如果:
      • 1.Data 中没有,metadata 中有:ADD;
      • 2.Data 中有,matadata 中没有,DROP;
      • 3.Data 和 metadata 中都有同一 ID但是 name 不同:RENAME。

参考:htps://baike.baidu.com/item/ACID/10738