5

优化online schema change的等待时间

 3 years ago
source link: https://www.zenlife.tk/online-schema-change-optimize.md
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

优化online schema change的等待时间

2017-04-16

TiDB里面有个很恶心的lease参数,这个参数设置小了,TiDB就会挂掉。但设置大了呢,做DDL的时间就特别长。用户就很困惑,为啥有这么蛋疼的参数。 被问了很多次以后,我们将它放到了FAQ里面:

TiDB 的 lease 参数应该如何设置?

启动 TiDB Server 时,需要通过命令行参数设置 lease 参数(–lease=60),其值会影响 DDL 的速度(只会影响当前执行 DDL 的 session,其他的 session 不会受影响)。在测试阶段,lease 的值可以设为 1s,加快测试进度;在生产环境下,我们推荐这个值设为分钟级(一般可以设为 60),这样可以保证 DDL 操作的安全。

在使用 TiDB 时,DDL 语句为什么这么慢?

TiDB 实现了 Google F1 的在线 Schema 变更算法(具体参见 F1 论文 和我们的一篇 Blog)。 一般情况下,DDL 并不是一个频繁的操作,我们首先要保证的是数据的一致性以及线上业务不受影响。一个完整的 DDL 过程会有 2 到 5 个阶段(取决于语句类型),每个阶段至少会执行 2lease 时间,假设 lease 设为 1分钟,对于 Drop Table 语句(需要两个阶段),会执行 22*1 = 4 分钟。除此之外,DDL 的时间还取决其他的条件,比如做 Add Index 操作时,表中已有的数据量是影响 DDL 时间的主要因素。我们也了解过 Google 内部在 F1 上是如何做 DDL,一般是提交给 DBA,DBA 再通过专用的工具执行,执行的时间会很长。

然而这并没什么卵用。

首先,这个解释太技术化了,普通用户根本难以理解。

其次,小白用户根本就不看文档的,所以解释再多也白搭。

写这篇文章,是最近要做一个优化,把等待时间干掉。lease参数就不应该暴露给用户。

还是先讲一下online schema change,主要提一下思路,具体的细节可以看论文就行。

schema是数据库的元数据,一个数据库的表结构是什么样的,有哪些列,列的类型是什么,有没索引,这些东西都是schema信息。问题是这样子的,在一个分布式的数据库里面,并不容易保证大家看到的是同一个schema。如果schema有更新了,假设有一个节点用的旧的schema信息,而另一个节点用的新的schema信息,数据的一致性就难以保证了:比如某个表添加了一列,使用旧的schema插入数据,插入的数据没有这一列,而使用新的schema的节点,插进去的数据有这一列,显然是有问题的。

online schame change并不是一口气从旧的schema更新到新的schema,而是拆成了好几个阶段:可删除、可写、重组、可读。并且保证任意时刻所有的节点最多看到两个不同状态

下面我们以添加index为例子来说明,注意考虑如果没有中间阶段会出现什么问题。

我们假设schema更新了,而有个节点用的仍然是旧的schema,也就是它不知道这个索引,那么它执行DELETE会生什么事情?它会把数据删掉,但是却没删掉索引,于是出现“悬挂”的索引,这个索引指向了一块不存在的数据。

可删除阶段的引入就是解决上述问题。处于这个阶段,对新添加的索引只能执行删除操作,不能做其它操作。

假设schema有更新,有的节点用的旧schema,有的节点用的新schema,执行INSERT操作会出现什么问题?旧的节点插入了数据,却没有插入索引,这条记录是不完整的。

可写阶段的引入就是解决上述问题。在这个阶段,可以写入索引,也可以删除。但是无法执行其它操作(索引还不可见,无法读)。

这个阶段执行的操作非常重要。经过前两个阶段,我们知道,整个数据库的状态可能是,有数据但是却没有索引。在这个阶段里面会做backfill, 给旧的数据把索引填充上去。 这样子在进入下个阶段之前,我们可以保证,数据和索引都是一致的。

到了这个阶段,新加的索引才会变成对外可见。

上面就是大致的流程了,虽然是添加索引为例,但是对于其它的DDL操作比如添加删除列之类的,都是类似的走这几个阶段。

这个算法最大的问题是什么呢?

为了保证算法的正确性,有一个严格的约束条件:任意时刻所有的节点最多看到两个不同状态。实现这个约束,采用了lease机制,导致等待时间过长,也就是文章开头那一堆问题blahblah。

  1. 从一个版本变更到下一版本,必须等待1个lease时间。
  2. 客户端必须在lease过期前拿到最新的版本。如果拿不到,当前版本在超过2个lease就过期了,不提供服务了。

这样子,前者保证了一个lease之内,整个系统不会存在两个版本。后者保证所有节点对一个版本的使用不会跨越两个lease。共同作用之后,就保证了任意时刻所有的节点最多看到两个不同状态,约束条件成立了。

其实呢,仔细想一想,并不一定非得走lease机制。以前等lease的行为无非是为了保证约束条件。

实际上用什么方式实现都行,只要能保证约束。所以我觉得优化要解决问题就只有一个:

若所有的TiDB能对最新的schema版本达成共识,就不用等lease了。
前段时间我们引入了etcd,引入etcd之后就有更大的想象空间了。以前由lease保证的事情,可以etcd这边维护一致性,可以主动地做一些事情。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK