这个系列共三篇译文:
TiDB 官方设计文档翻译(一)
TiDB 官方设计文档翻译(二)
TiDB 官方设计文档翻译(三)
原文:
https://pingcap.github.io/blog/2016/10/17/how-we-build-tidb/
5.3 TiDB核心技术
让我们继续讨论TiDB。TiDB有一个与MySQL兼容的协议层,有以下功能:
- 将表数据映射到键值存储,从而连接到键值存储引擎。
- 谓词下推(译者注:将外层查询块的 WHERE 子句中的谓词移入所包含的较低层查询块,不理解的可以搜索一下这个名词),以加速查询
- 在线DDL
5.3.1 将表数据映射到键值存储
让我们使用一个例子来展示SQL表如何映射到键值对。
如果我们在数据库中有一个简单的用户表。 它有2行3列:用户ID,名称和电子邮件,其中用户id是主键。
INSERT INTO user VALUES (1, "bob", "huang@pingcap.com");
INSERT INTO user VALUES (2, "tom", "tom@pingcap.com");
- 1
- 2
如果我们将此表映射到键值对,则应按以下方式进行。
当然,TiDB支持二级索引。 它是一个全局索引。 TiDB将数据和索引更新放在同一个事务中,因此TiDB中的所有索引都是事务性的和完全一致的。 整个过程对用户是透明的。
索引只是值指向行键的键值对。 在为用户名创建索引之后,键值存储如下所示:
索引的键由两部分组成:人名加后缀用户ID。比如这里“bob”是人名,1是用户id,值指向行键。
5.3.2 谓词下推
对于一些操作,如计算表中的一些列,TiDB将这些操作下推到相应的TiKV节点,由TiKV节点进行计算,然后TiDB合并最终结果。 下图展示了谓词下推的过程。
5.3.3 Schema更改
这部分关于Schema更改(译者注:Schema是数据库对象的集合,一个用户一般对应一个schema)。 为什么在线Schema更改是必备功能? 这是因为我们需要一直有完整的数据可用性,以及最小的性能影响,使运维人员睡得安稳。
与Google F1相同的部分
影响Schema更改的TiDB的主要功能有:
- 分布式——TiDB的实例由许多单独的TiDB服务器组成
- 关系Schema——每个TiDB服务器都有一个描述表,列,索引和约束的关系Schema的副本。对Schema的任何修改都应该是分布式的,以更新所有服务器。
- 共享数据存储——所有数据中心中的所有TiDB服务器都可以访问存储在TiKV中的所有数据。在TiDB服务器之间没有数据分区。
- 没有全局会员——因为TiDB服务器是无状态的,所以不需要TiDB实现全局成员协议。这意味着没有可靠的机制来确定当前运行的TiDB服务器,并且显式全局同步是不可能的。
与Google F1不同的部分 - TiDB使用MySQL协议
- 单个事务中的语句不能跨越不同的TiDB服务器
关于Schema更改的补充说明
Schema更改之前,让我们看看下图展示的TiDB中的SQL
下面是Schema更改期间TiDB实例的概述:
Schema更改: 增加索引
接下来,让我们看看在添加索引时Schema是如何变化的。如果我们不小心,使用不同Schema版本的服务器可能会损坏数据库。
考虑从Schema S1到Schema S2的变更,其将索引 I 添加到表T上。假设两个不同的服务器M1和M2执行下列操作:
- 服务器M2使用Schema S2向表T插入新行r。由于S2包含索引 I ,所以服务器M2还向键值存储添加对应 r 的新索引条目。
- 服务器M1使用Schema S1删除r。 因为S1不包含 I,M1从键值存储中删除r,但无法删除 I 中的相应索引条目。
第二次删除会破坏数据库。 例如,仅针对索引的扫描将返回不正确的结果,包括已删除行r的列值。
Schema 状态
通常情况下,Schema 更改是一个多状态多阶段协议。 有两种状态,我们认为是非中间的:absent和public。有两个内部、中间状态:delete-only和write-only
delete-only:一个仅删除的表、列或索引不能由用户事务读取其键值对,并且
- 如果E是表或列,则只能通过删除操作进行修改。
- 如果E是一个索引,它只被删除和更新操作修改。 此外,更新操作可以删除与更新的索引键相对应的键值对,但是它们不能创建任何新的键值对。
对于write-only状态,它这样定义列和索引:
write-only列或索引可以通过插入,删除和更新操作修改其键/值对,但不能通过用户事务读取它们的键值对。
Schema 更改流程:添加索引
添加索引需要4个步骤。
步骤1,我们将状态标记为delete-only,等待一个Schema 租用,在所有TiDB服务器达到相同状态后,到第二步
步骤2,将状态标记为write-only,等待一个Schema 租用,
步骤3,将状态标记为填充索引,并开始mapreduce作业。 在完成索引填充作业后,我们等待一个Schema 租用,
步骤4,切换到最终状态,所有新查询可以使用新添加的索引。
TiDB:添加索引的状态(delete-only)
以下是添加索引的屏幕截图之一。
我们可以使用任何MySQL客户端查询在线DDL作业的状态。 只是简单地运行“show status”语句,我们可以看到高亮部分,当前状态是“delete-only”,并且操作是“添加索引”。 还有一些其他信息,如谁在做DDL作业,当前作业的状态和当前schema 版本。
TiDB:添加索引的状态(添加索引)
如红笔所示,此屏幕截图显示当前状态是“write reorganization”。
6 如何测试?
在本节中,我将介绍如何测试系统。
- 测试用例来自社区。 在MySQL驱动程序/连接器,ORM和应用程序中有很多测试用例。
- 在硬件和软件上执行故障注入以增加测试覆盖。
- 关于网络,我们模拟延迟,故障,分区,以检测当网络不可靠时我们的数据库中是否有bug。
- 我们使用Jepsen和Namazu进行分布式测试。
7 未来计划
这是我们的未来计划:
- 我们计划在未来使用GPS和原子钟。
- 我们正在改进我们的查询优化器以获得更好更快的查询结果。
- 我们将进一步提高与MySQL的兼容性。
- JSON和文档存储类型的支持也在我们的规划中。
- 我们计划支持推动更多的聚合和内置功能。
- 在将来,我们将使用gRPC替换自定义的RPC实现。