TiDB Best Practice

2017-07-05 17:24:45 +08:00
 PingCAP

本文档用于总结在使用 TiDB 时候的一些最佳实践,主要涉及 SQL 使用、OLAP/OLTP 优化技巧,特别是一些 TiDB 专有的优化开关。 建议先阅读讲解 TiDB 原理的三篇文章(讲存储说计算谈调度),再来看这篇文章。

前言

数据库是一个通用的基础组件,在开发过程中会考虑到多种目标场景,在具体的业务场景中,需要根据业务的实际情况对数据的参数或者使用方式进行调整。

TiDB 是一个兼容 MySQL 协议和语法的分布式数据库,但是由于其内部实现,特别是支持分布式存储以及分布式事务,使得一些使用方法和 MySQL 有所区别。

基本概念

TiDB 的最佳实践与其实现原理密切相关,建议读者先了解一些基本的实现机制,包括 Raft、分布式事务、数据分片、负载均衡、SQL 到 KV 的映射方案、二级索引的实现方法、分布式执行引擎。下面会做一点简单的介绍,更详细的信息可以参考 PingCAP 公众号以及知乎专栏的一些文章。

Raft

Raft 是一种一致性协议,能提供强一致的数据复制保证,TiDB 最底层用 Raft 来同步数据。每次写入都要写入多数副本,才能对外返回成功,这样即使丢掉少数副本,也能保证系统中还有最新的数据。比如最大 3 副本的话,每次写入 2 副本才算成功,任何时候,只丢失一个副本的情况下,存活的两个副本中至少有一个具有最新的数据。

相比 Master-Slave 方式的同步,同样是保存三副本,Raft 的方式更为高效,写入的延迟取决于最快的两个副本,而不是最慢的那个副本。所以使用 Raft 同步的情况下,异地多活成为可能。在典型的两地三中心场景下,每次写入只需要本数据中心以及离得近的一个数据中心写入成功就能保证数据的一致性,而并不需要三个数据中心都写成功。但是这并不意味着在任何场景都能构建跨机房部署的业务,当写入量比较大时候,机房之间的带宽和延迟成为关键因素,如果写入速度超过机房之间的带宽,或者是机房之间延迟过大,整个 Raft 同步机制依然无法很好的运转。

分布式事务

TiDB 提供完整的分布式事务,事务模型是在 Google Percolator 的基础上做了一些优化。具体的实现大家可以参考这篇文章。这里只说两点:

数据分片

TiKV 自动将底层数据按照 Key 的 Range 进行分片。每个 Region 是一个 Key 的范围,从 StartKey 到 EndKey 的左闭右开区间。Region 中的 Key-Value 总量超过一定值,就会自动分裂。这部分用户不需要担心。

负载均衡

PD 会根据整个 TiKV 集群的状态,对集群的负载进行调度。调度是以 Region 为单位,以 PD 配置的策略为调度逻辑,自动完成。

SQL on KV

TiDB 自动将 SQL 结构映射为 KV 结构。具体的可以参考这篇文档。简单来说,TiDB 做了两件事:

可以看到,对于一个表中的数据或者索引,会具有相同的前缀,这样在 TiKV 的 Key 空间内,这些 Key-Value 会在相邻的位置。那么当写入量很大,并且集中在一个表上面时,就会造成写入的热点,特别是连续写入的数据中某些索引值也是连续的(比如 update time 这种按时间递增的字段),会再很少的几个 Region 上形成写入热点,成为整个系统的瓶颈。同样,如果所有的数据读取操作也都集中在很小的一个范围内 (比如在连续的几万或者十几万行数据上),那么可能造成数据的访问热点。

Secondary Index

TiDB 支持完整的二级索引,并且是全局索引,很多查询可以通过索引来优化。如果利用好二级索引,对业务非常重要,很多 MySQL 上的经验在 TiDB 这里依然适用,不过 TiDB 还有一些自己的特点,需要注意,这一节主要讨论在 TiDB 上使用二级索引的一些注意事项。

二级索引能加速查询,但是要注意新增一个索引是有副作用的,在上一节中我们介绍了索引的存储模型,那么每增加一个索引,在插入一条数据的时候,就要新增一个 Key-Value,所以索引越多,写入越慢,并且空间占用越大。另外过多的索引也会影响优化器运行时间,并且不合适的索引会误导优化器。所以索引并不是越多越好。

场景与实践

上一节我们讨论了一些 TiDB 基本的实现机制及其对使用带来的影响,本节我们从具体的使用场景出发,谈一些更为具体的操作实践。我们以从部署到支撑业务这条链路为序,进行讨论。

部署

在部署之前请务必阅读 TiDB 部署建议以及对硬件的需求

推荐通过 TiDB-Ansible 部署 TiDB 集群,这个工具可以部署、停止、销毁、升级整个集群,非常方便易用。

具体的使用文档在这里。非常不推荐手动部署,后期的维护和升级会很麻烦。

导入数据

如果有 Unique Key 并且业务端可以保证数据中没有冲突,可以在 Session 内打开这个开关: SET @@session.tidb_skip_constraint_check=1;

另外为了提高写入性能,可以对 TiKV 的参数进行调优,具体的文档在这里

请特别注意这个参数:

[raftstore]
# 默认为 true,表示强制将数据刷到磁盘上。如果是非金融安全级别的业务场景,建议设置成 false,
# 以便获得更高的性能。
sync-log = true

写入

上面提到了 TiDB 对单个事务的大小有限制,这层限制是在 KV 层面,反映在 SQL 层面的话,简单来说一行数据会映射为一个 KV entry,每多一个索引,也会增加一个 KV entry,所以这个限制反映在 SQL 层面是:

另外注意,无论是大小限制还是行数限制,还要考虑 TiDB 做编码以及事务额外 Key 的开销,在使用的时候,建议每个事务的行数不要超过 1w 行,否则有可能会超过限制,或者是性能不佳。

建议无论是 Insert,Update 还是 Delete 语句,都通过分 Batch 或者是加 Limit 的方式限制。

在删除大量数据的时候,建议使用 Delete * from t where xx limit 5000; 这样的方案,通过循环来删除,用 Affected Rows == 0 作为循环结束条件,这样避免遇到事务大小的限制。

如果一次删除的数据量非常大,这种循环的方式会越来越慢,因为每次删除都是从前向后遍历,前面的删除之后,短时间内会残留不少删除标记(后续会被 gc 掉),影响后面的 Delete 语句。如果有可能,建议把 Where 条件细化。举个例子,假设要删除 2017-05-26 当天的所有数据,那么可以这样做:

for i from 0 to 23:
    while affected_rows > 0:
	delete * from t where insert_time >= i:00:00 and insert_time < (i+1):00:00 limit 5000;
	affected_rows = select affected_rows()

上面是一段伪代码,意思就是要把大块的数据拆成小块删除,以避免删除过程中前面的 Delete 语句影响后面的 Delete 语句。

查询

看业务的查询需求以及具体的语句,可以参考这篇文档 可以通过 SET 语句控制 SQL 执行的并发度,另外通过 Hint 控制 Join 物理算子选择。

另外 MySQL 标准的索引选择 Hint 语法,也可以用,通过 Use Index/Ignore Index hint 控制优化器选择索引。

如果是个 OLTP 和 OLAP 混合类型的业务,可以把 TP 请求和 AP 请求发送到不同的 tidb-server 上,这样能够减小 AP 业务对于 TP 业务的影响。 承载 AP 业务的 tidb-server 推荐使用高配的机器,比如 CPU 核数比较多,内存比较大。

监控 & 日志

Metrics 系统是了解系统状态的最佳方法,建议所有的用户都部署监控系统。TiDB 使用 Grafana+Prometheus 监控系统状态,如果使用 TiDB-Ansible 部署集群,那么会自动部署和配置监控系统。

监控系统中的监控项很多,大部分是给 TiDB 开发者查看的内容,如果没有对源代码比较深入的了解,并没有必要了解这些监控项。我们会精简出一些和业务相关或者是系统关键组件状态相关的监控项,放在一个独立的面板中,供用户使用。

除了监控之外,查看日志也是了解系统状态的常用方法。TiDB 的三个组件 tidb-server/tikv-server/pd-server 都有一个 --log-file 的参数,如果启动的时候设置了这个参数,那么日志会保存着参数所设置的文件的位置,另外会自动的按天对 Log 文件做归档。如果没有设置 --log-file 参数,日志会输出在 stderr 中。

文档

了解一个系统或者解决使用中的问题最好的方法是阅读文档,明白实现原理,TiDB 有大量的官方文档,希望大家在遇到问题的时候能先尝试通过文档或者搜索 Issue list 寻找解决方案。官方文档在这里。如果希望阅读英文文档,可以看这里

其中的 FAQ故障诊断章节建议大家仔细阅读。另外 TiDB 还有一些不错的工具,也有配套的文档,具体的见各项工具的 GitHub 页面。

除了文档之外,还有很多不错的文章介绍 TiDB 的各项技术细节内幕,大家可以关注下面这些文章发布渠道:

TiDB 的最佳适用场景

简单来说,TiDB 适合具备下面这些特点的场景:

785 次点击
所在节点    数据库
3 条回复
HowardMei
2017-07-05 20:40:14 +08:00
这个项目牛逼啊,是给云平台用来建设 Google Spanner 替代品的么?
好像跟以前被 Apple 收购、私有化的 FoundationDB 思路差不多。
wangdu2012
2017-07-05 22:29:58 +08:00
加油。
sfyumi
2017-07-05 23:59:41 +08:00
前几天刚发现 TiDB 在我们公司旁边

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/373272

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX