为什么选择 TiDB?
在深入调研后,TiDB这款广受欢迎的开源分布式HTAP(Hybrid Transactional and Analytical Processing)数据库逐渐进入了我们团队的视野,并成为了我们重点考虑和应用的数据库产品。
TiDB作为一款集在线事务处理(OLTP)与在线分析处理(OLAP)于一体的分布式数据库产品,展现出了卓越的性能与灵活性。它支持水平弹性扩容和缩容,能够根据业务需求灵活调整资源,实现高效的数据处理。同时,TiDB还具备金融级的高可用性,确保数据在关键时刻始终可靠可用。
值得一提的是,TiDB实现了实时的HTAP功能,使得事务处理与分析处理能够无缝融合,为用户提供了更加便捷、高效的数据处理体验。此外,其云原生的设计使得TiDB能够轻松适应各种云环境,为企业的数字化转型提供了有力支持。
在兼容性方面,TiDB全面支持MySQL 5.7和MySQL 8.0协议,以及MySQL生态中的各种工具和应用,这大大降低了企业的迁移成本和学习门槛。无论是对于已有MySQL应用的企业,还是对于希望尝试新数据库技术的企业来说,TiDB都是一个理想的选择。
TiDB的诸多优势特性完美契合了我们数据应用团队在处理大规模数据和高并发事务时的需求。它不仅为我们提供了一个高性能、高可用的数据库解决方案,还通过其强大的生态系统,全面支持了数据的管理、分析以及业务的持续创新与发展。我们相信,在未来的日子里,TiDB将成为我们团队不可或缺的重要伙伴,共同推动业务的蓬勃向前。
架构对比
数据应用团队从架构、存储层面对比了 TiDB 与 MySQL 的区别与优势:
TiDB 架构详细描述
TiDB Server 层:
-
SQL解析与优化:TiDB Server负责接收客户端的SQL请求,进行语法解析和逻辑优化,生成执行计划。这一步骤是查询优化的关键,TiDB Server会利用其优化器来决定最有效的查询执行路径。
-
分布式协调器PD(Placement Driver):PD是TiDB的元数据管理组件,负责存储集群的元信息,包括数据分布和节点状态。它与TiDB Server交互,协调数据的分布和负载均衡。
-
分布式存储TiKV:TiKV是一个分布式的键值存储系统,负责存储实际的数据。TiDB Server通过PD与TiKV进行交互,获取或写入数据。
-
执行器:在获取到数据后,TiDB Server的执行器负责进行数据的进一步处理,包括合并、排序、分页和聚合等操作。
特点:
-
水平扩展:TiDB Server可以轻松地通过增加节点来扩展系统的处理能力。
-
高可用性:TiDB Server设计为无状态,可以快速故障转移,保证服务的连续性。
-
强一致性:通过分布式事务和MVCC机制,TiDB保证了事务的ACID属性。
MySQL架构详细描述
传统单体架构:
-
集中式处理:MySQL的所有数据库操作,包括SQL解析、查询优化、数据存储和检索,都在同一服务器上完成。
-
单一数据存储:数据存储在本地磁盘或连接的存储系统中,没有分布式存储的概念。
-
垂直扩展依赖:由于是单体架构,MySQL通常通过增加单个服务器的硬件能力(如CPU、内存、存储)来提升性能,这称为垂直扩展。
特点:
-
简化管理:由于所有组件都在一个服务器上,管理和维护相对简单。
-
扩展性限制:垂直扩展有其物理限制,当达到硬件极限时,性能提升会遇到瓶颈。
-
事务和并发处理:MySQL通过行锁和表锁等机制来处理并发和事务,但在高并发场景下可能会遇到性能瓶颈。
结构对比总结
-
扩展性:TiDB的分布式架构允许其水平扩展,而MySQL主要依赖垂直扩展。
-
容错能力:TiDB通过多节点和副本机制提供高可用性,MySQL则依赖于主从复制和故障转移机制。
-
性能:TiDB通过分布式计算和存储优化了大规模数据集的性能,MySQL在大规模数据集下可能会遇到性能瓶颈。
-
复杂性与灵活性:TiDB的架构较为复杂,但提供了更高的灵活性和扩展性;MySQL架构简单,但在处理大规模和高并发场景时可能需要额外的优化措施。
MySQL 架构图
TiDB 架构图
存储层
MySQL存储架构
InnoDB存储引擎:
-
MySQL的默认存储引擎是InnoDB,它是一个健壮的事务型存储引擎,支持ACID事务。
-
所有数据都存储在表空间中,表空间可以包含多个数据文件和日志文件。
-
表数据以B+树的索引结构存储,这为快速的数据访问提供了基础。
B+树索引结构:
-
主键索引和非主键索引都是B+树结构,其中非主键索引的叶子节点存储主键值,用于快速定位到具体的数据行。
-
B+树的每个节点可以存储更多的键值,这意味着相比B树,B+树的高度更低,查询效率更高。
事务和MVCC:
-
InnoDB通过行级锁定和MVCC机制来支持高并发的读写操作。
-
通过Undo日志来实现MVCC,允许在不锁定资源的情况下读取历史数据版本。
TiDB存储层
TiKV分布式键值存储:
-
TiKV是TiDB的分布式存储层,它使用RocksDB作为其本地存储引擎,优化了写入性能和磁盘空间使用。
-
TiKV将数据分散存储在多个节点上,通过Raft协议保证数据的强一致性和高可用性。
MVCC版本控制:
-
TiKV使用MVCC机制来处理并发控制和历史数据版本,每个事务都会获取一个全局唯一的时间戳(TS)作为版本号。
-
通过这种方式,TiKV可以支持同一时间点的多个事务读取到一致的数据快照。
数据存储格式:
-
主键数据存储格式为
tablePrefix{tableID}_recordPrefixSep{Col1}
,其中Value
包含了行数据的所有列值。 -
唯一索引的存储格式为
tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue
,Value
为对应的行ID。 -
非唯一索引的存储格式与唯一索引类似,但每个索引值后附加行ID,
Value
可能为null
。
特点:
-
TiKV的存储层设计为易于扩展,可以水平扩展以适应不断增长的数据量。
-
通过Raft协议,TiKV能够在多个副本之间同步数据,提高了数据的可用性和容错能力。
存储层对比总结
-
扩展性:TiDB的TiKV存储层设计为分布式,易于水平扩展,而MySQL的InnoDB存储引擎通常需要垂直扩展。
-
并发控制:TiDB使用MVCC和TSO(Timestamp Ordering)来实现并发控制,而MySQL使用行级锁定和MVCC。
-
数据一致性:TiKV通过Raft协议保证跨多个节点的数据一致性,InnoDB则依赖于单个服务器的事务日志和恢复机制。
-
存储效率:TiKV的RocksDB存储引擎优化了写入性能和压缩,而InnoDB的B+树结构优化了读取性能。
MySQL 存储架构
TiDB 存储层架构
TiDB索引实现
KV存储模型:
-
TiDB的索引基于键值(Key-Value)存储模型实现。这种模型非常适合分布式环境,因为它允许数据的水平分割和分布式存储。
主键索引:
-
主键索引使用行的主键值作为键,行数据的序列化形式作为值。例如,如果
Col1
是主键,则键可能表示为tablePrefix{tableID}_recordPrefixSep{Col1}
。 -
这种映射允许TiDB通过主键值直接访问对应的行数据,提供了高效的数据检索。
唯一索引:
-
唯一索引使用索引列的值作为键,行的主键值作为值。例如,键可能表示为
tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue
,值是对应的RowID
。 -
这种设计确保了索引的唯一性,并且可以通过索引值快速定位到具体的数据行。
非唯一索引:
-
非唯一索引与唯一索引类似,但允许同一个键对应多个值。在这种情况下,键仍然是索引列的值,但值是包含
RowID
的列表。 -
这允许TiDB处理具有相同索引值的多行数据。
特点:
-
TiDB的索引实现简化了分布式环境下的数据访问,通过键值对直接映射,提高了查询效率。
-
由于TiDB的存储层TiKV使用RocksDB,索引数据也被优化存储,以减少磁盘空间的使用。
MySQL索引实现
B+树结构:
-
MySQL的索引基于B+树结构,这是一种自平衡树,优化了读写性能和空间使用。
-
B+树的所有数据都存储在叶子节点,内部节点仅存储键值和指向子节点的指针,这减少了查找过程中的磁盘I/O操作。
主键索引:
-
主键索引是聚簇索引,非主键索引是二级索引。聚簇索引的叶子节点直接包含行数据,而非主键索引的叶子节点包含主键值,用于快速跳转到聚簇索引。
非主键索引:
-
非主键索引的叶子节点不直接存储行数据,而是存储对应的主键值。查询时,需要通过主键值回表查询,访问聚簇索引以获取完整的行数据。
特点:
-
B+树结构减少了查询过程中的I/O操作次数,提高了数据访问速度。
-
聚簇索引和非聚簇索引的设计,优化了数据的物理存储,减少了冗余和空间使用。
索引实现对比总结
-
数据访问方式:TiDB通过键值对直接映射数据,而MySQL通过B+树结构进行索引。
-
分布式适应性:TiDB的索引实现更适合分布式环境,易于水平扩展。MySQL的B+树索引则优化了单个服务器上的数据访问。
-
查询效率:TiDB的索引实现允许快速的数据检索,特别是在分布式查询中。MySQL的B+树索引通过减少I/O操作提高了查询效率。
-
存储优化:TiDB的RocksDB存储引擎优化了索引数据的存储,而MySQL的B+树结构减少了索引的存储空间需求。
MySQL 索引 b+tree
TiDB 中 Rocksdb 分布式 leveldb lsm
TiDB事务处理和MVCC
TiDB事务模型:
-
TiDB支持两种类型的锁:乐观锁和悲观锁,以适应不同的业务场景。
-
乐观锁:适用于写冲突较少的环境,通过检测在事务开始后数据是否被其他事务修改来避免锁的争用。如果检测到冲突,事务会进行重试。
-
悲观锁:适用于高冲突环境,通过在事务开始时就锁定涉及的数据行,防止其他事务修改这些数据。
MVCC实现:
-
TiDB采用MVCC机制来提供在不锁定资源的情况下读取历史数据版本的能力,从而提高并发性能。
-
MVCC通过为每个事务分配一个全局唯一的时间戳(TS),并使用这个时间戳来确定数据的可见性。
-
在TiDB中,每个数据行都保存了多个版本,每个版本都有一个开始和结束的时间戳。查询操作会根据当前事务的时间戳来确定应该读取哪个版本的数据。
MySQL事务处理和MVCC
InnoDB事务模型:
-
MySQL的InnoDB存储引擎支持ACID(原子性、一致性、隔离性、持久性)事务。
-
InnoDB使用行级锁定机制来处理并发写入,确保事务的隔离性。
MVCC实现:
-
InnoDB通过Undo Log来实现MVCC,允许在不锁定资源的情况下读取历史数据版本。
-
Undo Log记录了数据在事务开始前的状态,这样即使在其他事务修改了数据之后,当前事务仍然可以读取到事务开始前的数据状态。
-
InnoDB的MVCC主要通过Read View来实现,Read View是一个快照,包含了在事务开始时所有已提交的数据的可见性信息。
锁机制:
-
InnoDB主要使用悲观锁,通过行锁和表锁来处理数据的并发访问,防止数据的不一致性。
-
行锁在SELECT ... FOR UPDATE或INSERT/UPDATE/DELETE操作时自动加锁,以保证事务的原子性和隔离性。
-
表锁在某些特定的操作,如全表扫描或某些类型的索引操作中使用。
事务与MVCC对比总结
-
锁机制:TiDB支持乐观锁和悲观锁,提供了更灵活的锁策略,而MySQL主要使用悲观锁。
-
MVCC实现:TiDB使用时间戳和版本控制来实现MVCC,而InnoDB使用Undo Log和Read View。
-
并发性能:TiDB的MVCC机制通过减少锁的争用来提高并发性能,特别是在高并发读写的场景下。InnoDB的MVCC通过Undo Log减少锁的使用,但在高冲突环境下可能仍然会遇到锁争用。
-
历史数据访问:TiDB和InnoDB都允许在不锁定资源的情况下访问历史数据版本,提高了系统的并发读取能力。
通过这种详细的事务和MVCC机制对比,我们可以更深入地理解TiDB和MySQL在事务处理和并发控制方面的差异,以及它们如何适应不同的业务场景和性能需求。
TiDB 同时支持了乐观锁和悲观锁模式
MySQL 通过undolog实现( Redo Log、Undo Log、Bin Log)
TiDB MVCC 的实现
SQL生命周期
-
TiDB SQL执行:分布式环境中,SQL执行涉及多个组件和步骤,包括索引使用、存储引擎选择等。
-
性能分析工具:使用
EXPLAIN
和EXPLAIN ANALYZE
分析SQL执行计划和实际执行情况。
由于是分布式数据库,在 TiDB 中 SQL 的执行和 MySQL 有很大区别,如索引实现、存储机制等。
-
在 TiDB 中查询一条 SQL 是如何执行的,使用的引擎,索引等信息操作如下:
explain yoursql;
explain analyze yoursql; //真实执行
-
SQL 语法的兼容性
TiDB 语法兼容了 MySQL 8.0 的绝大部分语法,目前仅发现新版的 MySQL 一些特殊语法不支持,比如default CURRENT_DATE;同时新增了一些语法,比如主键索引 auto_random 的类型,基本上业务上一般已经用的 MySQL 的 SQL 基本都支持。
分区的使用
-
TiDB分区:支持多种分区类型,如Range、List和Hash分区,简化数据管理并提高查询效率。
-
分区表分析:自动分析分区数据分布,优化查询计划。
TiDB 当前支持的类型包括 Range 分区、Range COLUMNS 分区、Range INTERVAL 分区、List 分区、List COLUMNS 分区和 Hash 分区
-
查看分区的数据
/*查看分区的数据分布*/
SHOW STATS_META where table_name = "table_demo";
/*从分区直接查询数据*/
CREATE TABLE table_demo (
`id` bigint(20) primary key auto_random,
start_time timestamp(3)
) PARTITION BY RANGE (FLOOR(UNIX_TIMESTAMP(`start_time`)))
SELECT * FROM table_demo PARTITION (p1) where xxx;
/* 新增分区 */
ALTER TABLE table_demo ADD PARTITION(PATITION p2 VALUES LESS THAN ( FLOOR(UNIX_TIMESTAMP(`start_time`))
/* 删除分区 */
ALTER TABLE table_demo drop partition p1
-
分区表的说明:
TiDB 每个分区都是单独的一张表,会对每个分区进行统计,如查询的时候进行逻辑优化,推算数据在哪些分区里面;TiFlash 也支持分区。
-
分区表的分析
TiDB 分区表分析有利于统计索引(分区)的分布情况
show variables like '%tidb_auto_analyze_end_time%';
set global tidb_auto_analyze_end_time = "06:00 +0000";
analysis table table_name; //分析表,有利于执行计划
列式存储 TiFlash
TiDB 提供了列式存储引擎 TiFlash,它是 TiKV 的列存扩展,在提供了良好的隔离性的同时,也兼顾了强一致性。
只需在 TiDB 做出一些设置,数据就可以从 TiKV->TiFlash 同步过去。
//增加tiflash副本
ALTER TABLE table_name SET TIFLASH REPLICA count;
//查看数据同步进度
SELECT * FROM information_schema.tiflash_replica WHERE TABLE_SCHEMA = '<db_name>' and TABLE_NAME = '<table_name>';
TiDB 可以根据表分析的情况综合索引信息和数据量,自动选择使用 TiFlash 或者 TiKV,也可以在 SQL 内指定使用的存储引擎,且支持多表。
select /*+ read_from_storage(tiflash[table_name]) */ ... from table_name;
解决方案
在原有的架构中,用户业务数据均存储在MySQL数据库中。为了确保数据迁移的稳健性与安全性,数据团队采取了一种巧妙的策略:他们首先将数据写入MySQL数据库,随后利用TiDB Data Migration(DM)工具实现数据向TiDB的同步。这一举措不仅保障了数据的完整性和一致性,还极大地提升了数据迁移的效率。
得益于这一策略,公司内部各大系统现在直接访问TiDB进行数据查询,从而充分利用了TiDB在查询性能上的显著优势。这一改变不仅大幅缩短了查询响应时间,还显著提升了数据处理的吞吐量和并发能力,为业务的高效运行提供了坚实的数据支撑。
总结
目前,TiDB 已经在得到了大范围推广,有多个业务开始使用 TiDB。业务方反馈 TiDB 真正解决了业务中的很多问题,并且在使用中表现非常平稳,稳定性超乎预料,大大增强了使用国产分布式数据库的信心。
参考资料: