F1 在线异步执行schema change

F1 在线异步执行schema change
论文《Online, Asynchronous Schema Change in F1》

总结

对,先来个总结。
F1拥有几百个无状态的F1 server,其内存中会缓存schema信息。不能做到同时让所有的F1 server同时应用某个schema,因此存在不同F1 server访问不同schema的状态。这篇论文就是介绍了如果在两个schema同时存在时,怎么操作而不破坏数据库的完整性。

简介

本论文的目的在于介绍F1在线异步schema change的原理和实现。
F1基于Spanner之上,Spanner是一个KV存储,具有以下特性:

  • 大规模分布式。有上百个独立的F1 server;
  • 关系型模型。每个F1 server都会存储一份关系型的模型描述,包括表、列、索引和约束;
  • 共享数据存储。F1 server不存储数据,都从Spanner访问;
  • 无状态。F1 server是无状态的, 不存储数据;
  • 不记录全局成员信息。

schema change的设计约束:

  • 全部数据可用。不存在停止服务时间;
  • 性能影响最小化;
  • 异步schema change;没办法做到所有的F1 server同步变更。

不能直接变更的例子:
假如某张表R从schema S1变更到S2,增加了一个索引I。两个不同的F1 server M1和M2做这样的动作:

  1. M2使用S2插入一行r到表R。因为S2里面包含了索引I,所以会插入索引I;
  2. M1使用S1删除行r。因为S1中不包含索引I,所以不会删除对应的索引I。
    这时如果另一个F1 server通过索引I访问数据时,就会访问到被删除的行r。

背景

KV存储

Spanner是以KV的方式存储数据的,包括索引。次级索引(Secondary Index)在Spanner中存储在单独的表中。具体参考F1和Spanner的论文。

关系模型(Relational Schema)

Spanner中数据按照KV存储,表定义(schema definition)由F1 server解释。表包含列、次级索引、完整性约束(外键和唯一索引),还有乐观锁(wangyl11:乐观锁相关的推论将直接忽略)。

两个重要的概念:

  • Required Element: 某一列必须在表的每一行中都存在,则称为required。就是KV中每一行必须存在这一列。主键默认是required。
  • Optional Element:与Required对应,如果某个非索引列不要求在每行都要出现,则称为optional

这两个类型影响到在增加或删除某个元素时,是否要对数据做重组。比如增加一个required字段,那么必须在变更结束前,所有的行的KV信息中都必须增加这一列信息。相反,如果增加一个optional字段,变更后的表结构也不要求必须包含这一列,因此不用重组信息。

关系型操作

关系型操作包括insert、update、delete和query。
oper可以为任意的insert/update/delete/query。

Schema Change

数据库描述(database representation)是指一系列的KV行数据。每个F1 server在内存中保存了schema信息,使用这些schema信息将KV数据解释为关系型操作。
schema change: 当从一个schema信息转换为另一个版本的schema信息时,就称为schema change。因为不同的F1 server不能同步执行变更操作,所以在变更过程中,有些F1 server使用旧的schema,有些使用新的schema。但是他们使用的数据实例是一样的,就是访问同一份KV数据。
为了防止在变更时,数据被破坏,增加了一些中间状态(intermediate state)。通过这些中间状态和设计的执行步骤,可以保证所有操作都是安全的,不会破坏数据完整性。
约束:同一个时刻最多有两个版本的schema。一个F1 server要么使用旧的schema,要么使用新的schema。

Schema元素和状态

Schema Element:表、列、索引、约束(外键和索引唯一性),还有乐观锁(后续不做介绍)。

非中间状态:

  • absent: schema中不存在的元素,就称为absent;
  • public:模型中存在的,就称为public。public状态的元素可以应用各种操作。

中间状态

  • delete-only:对于表和列只接受删除操作。对于索引,可以接受删除和更新,但是不允许更新操作创建新的索引。delete-only状态不允许读取。
  • write-only:列和索引可以插入删除和更新,不能查询。约束可以接受插入删除和更新,但是不能保证覆盖了所有已经存在的数据。

数据库对schema的一致性

一个数据库描述与schema要求一致:

  1. 不存在这样的列值:没有对应的行和表。
  2. 所有行都包含了所有public required列的值。public很关键,如果一个元素还不是public,可以不包含对应的值。
  3. 模型中不存在某个索引,那么也不存在这个索引的数据。
  4. 所有public索引都是完整的。每行都有对应的索引数据。
  5. 所有索引都指向有效的行。
  6. 满足所有约束。
  7. 没有未知数据。除了1和3中的数据,没有其它额外的数据。

数据库描述与schema不一致性的场景:

  • 孤儿数据异常(orphan data anomaly): 数据库中存在与schema不符的数据。
  • 完整性异常(integrity anomaly): 缺少应该包含的数据或者违反了public状态的约束。

一致性保护变更:
为了防止某些操作破坏了数据库与schema的一致性,约束了某些操作,保证只允许存在对变更前schema S1和变更后schema S2都符合一致性要求的操作。
做到一致性保护的变更,都不会破坏数据库。

添加或移除schema元素

structural schema element(简称structural element),结构化元素:表、列和索引。
能够避免出现orphan data anomaly(孤儿数据异常)和integrity anomaly(完整性异常)的一致性保护都是对S1和S2来说是一致性的。

Optional structural elements

对可选element的添加和删除可以通过增加一个中间状态delete-only做到一致性保护变更。

增加structural元素(表列索引):

  1. 增加一个delete-only元素。
    假设从schema S1变更到schema S2,增加元素E。E在S2中不是public,S1和S2都是delete-only。这时所有的操作(其实只有删除和更新)都不会破坏S1和S2的一致性。
  2. 将delete-only元素变更为public。
    这时数据库是符合S1的。因为元素E是可选的,所以不要求一定在S2中出现,所以也是符合S2的。
seqS1S2
1absentdelete-only
2delete-onlypublic

删除structural元素E:
与添加动作类似。
将S1变成delete-only,这时只能删除与E相关数据。使用S2的操作,删除操作会将元素E删除,此时E还是public状态。

seqS1S2
1delete-onlypublic
2delete-onlyabsent

删除元素在完成之前要经过数据重组,需要删除所有元素对应的数据。

对于增加optional元素,增加一个中间状态即可(删除元素顺序相反):
absent -> delete-only -> public

Required structural elements

Required元素与Optoinal的区别是增加或删除会破坏schema的完整性(optional的元素在schema中每行数据有没有都可以,但是required要求每行数据都包含对应的元素)。通过增加write-only状态,可以避免这个异常情况。

增加元素的状态变更(删除顺序相反):
absent -> delete-only -> write-only -> public

下面说明从delete-only状态到write-only状态是不会破坏数据库描述与schema的一致性的。

  1. S1的E是delete-only,S2的E是write-only。这样适用两个schema的操作都不会破坏一致性。
  2. 从write-only转换到public。在切换为public之前,需要进行数据重组,比如增加一个索引,要把所有行数据对应的索引创建出来。

增加元素的状态变化:

seq | S1 | S2 | 备注
–|--|–
1 | absent | delete-only
2 | delete-only | write-only | 数据重组
3 | delete-only | public

删除元素的状态变化:

seq | S1 | S2 | 备注
–|--|–
1 | write-only | public
2 | delete-only | delete-only | 数据重组
3 | delete-only | absent

约束

这里的约束包括外键和索引唯一性。
增加约束:
absent -> write-only -> public

增加一个约束,从write-only到public也需要做数据重组(或者完整性校验),但可能会失败。
删除约束的状态变化是相反的。

实现

Write fencing

每个写入操作都有一个截止时间(deadline),超过截止时间没有完成就终止。这个限制是为了实现schema的租约机制。

schema租约

最多有两个schema同时存在。每个F1 server有一个schema租约,一般是几分钟。每次从某个位置重新读取schema信息。如果schema信息重新获取失败,直接退出。
这样的话,每次schema变更,只需要等待一个schema租约时间,可以保证没有F1 server使用旧的schema。
如果一个操作在提交时,对应的schema已经过期了,那么事务会被终止。

其它

Spanner实现schema变更使用同步变更,依赖于同步时钟(synchronized clocks)和全局成员信息。

总结

F1拥有几百个无状态的F1 server,其内存中会缓存schema信息。不能做到同时让所有的F1 server同时应用某个schema,因此存在不同F1 server访问不同schema的状态。这篇论文就是介绍了如果在两个schema同时存在时,怎么操作而不破坏数据库的完整性。

问题

  • Spanner怎么处理schema变更的?
  • schema 的状态在Spanner中怎么管理的?
  • schema 修改和状态变更在Spanner执行的是同步操作吗? 即是否所有Spanner同时执行,同时结束。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值