您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
   
 
     
   
 订阅
  捐助
Go 在 TiDB 的实践
 
作者:GopherChina
 
次浏览 评价:  
2020-12-24
 
编辑推荐:
本文主要介绍了TiDB架构和PD是如何用Go实现的,TiKV是如何用Rust实现的,希望对您的学习有所帮助。
本文来自开源中国社区,由火龙果软件Alice编辑、推荐。

为什么加入PingCAP呢?

在360的时候,负责Atlas的Sharding(切片技术)的实现。在这个过程中,发现中间件这个数据库方案存在了诸多限制。比如说数据迁移的场景,当槽位需要在原有设定值的基础上再增加,整个操作过程需要人工介入而且极其复杂,同时也避免不了系统停机。比如说分布式事务,这在跨Sharding的节点上几乎不可能支持的。

为什么要做一个新的数据库?

关于数据库发展的历史,如图一所示在早期,大家主要是使用单机数据库,如Mysql等。这些数据库的性能完全可以满足当时业务的需求。但是自2005年开始,也就是互联网浪潮到来的时候,这些早期的单机数据库就慢慢开始力不从心了。当时Google发表了几篇论文,谈论了其内部使用的Bigtable Mapreduce。然后就有了Redis、HBase 等非关系型数据库,这些数据库实际上已经足以满足当时业务的需求。

图 1

直到最近的五六年,我们发现尽管各种NoSQL产品大行其道,但是Mysql依然是不可或缺的。即使是Google,在某一些不能丢数据的场景中,对一些数据的处理依然需要用到ACID,需要用到跨行事务。因此Google在12年的时候发表了一篇名为《Google Spanner》的论文(注:Spanner是在Bigtable之上,用2PC实现了分布式事务)。然后基于Spanner,Google的团队做了F1(注:F1实际上是一个SQL层,支持SQL的语法),F1用了一些中间状态来屏蔽了单机Mysql可能碰到的阻塞的场景。

在PingCAP成立之前,当时还在豌豆荚的PingCAP的创始人,在接触数据库的中间件方案过程中也是深受其害。因此在受到Google上述的两篇论文的启发后,就成立了PingCAP,开始TiDB的研发。

TiDB的架构

图 2

TiDB的架构如图2所示。TiDB主要分为三个部分:负责对接SQL语句的SQL Layer、负责底层存储的TiKV和负责元数据管理的Placement Driver(PD,下文以此简称)。

其中TiDB和PD是用Go实现的,TiKV是用Rust实现的。它们的具体功能在后文会提到。

TiKV的概述

图 3

首先是Region的概念,它是指一段连续key的key-value对的集合。所有的数据都是以Region为一个基本单位来组织调度的。

Region是高度分层的。最底层的是RocksDB,这一层负责键值对的存储。之上是Raft状态机,每一个Region都是是通过Raft协议来保证数据的外部一致性的(我们的设计保证了即使在写数据的过程中宕机也不会丢数据),足以支持金融级别的场景。然后是数据库中比较常用的MVCC层,它可以实现隔离级别等很多功能。再之上,就是事务,这里的事务是用2PC的变种的方式实现的。(可能大家觉得2PC做分布式事务会出现阻塞的情况。但是我们也知道,2PC只会在键发生冲突时阻塞从而引起时延。但是这是一种极端情况,实际的业务场景,比如用户ID,只要我们将key均匀分布,这种冲突情况是几乎很少发生甚至可以完全避免的)。

现在一个Region的大小是96MB,当Region快要填满时,Region会发生分裂,整个分裂的过程都是由PD来调度,完全不需要人为干预。

PD的概述

PD主要负责元数据的管理。PD的主要作用:1、管理TiKV(一段范围key的数据),通过PD,可以获取每一段数据具体的位置;2、F1中提到的授时,即用于保证分布式数据库的外部一致性。

图 4

TiKV中的Multi-Raft

如图五所示,每一个Region都是一组Raft状态机。

假设节点一中出现Region的阻塞,这种设计能够保证其它节点并不会因此而受影响发生阻塞。

图 5

TiKV的水平扩容

TiKV的扩容,唯一需要人工操作的就是把机器加入到这个集群即可。剩下的完全会由PD来实现整个扩容的流程,同时PD还保证Region会均匀地分布在各个节点上。

图 6

实际上,在新节点刚刚加入集群时,存在一种潜在的可能发生阻塞的情况,即在该节点还没有任何数据加入时就需要进行"Raft"中的投票环节。我们给出的解决方案是,在该节点还没有获取到数据时,不让其参与投票的过程,然后直到数据迁移完成后再让其加入投票的过程。

SQL Layer

整个这一层都是用Go语言开发的。

在我看来,任何的键值对系统,只要是和SQL有关,那么其复杂度会以指数级上升。因为数据库中最难的就是查询优化器。大家有没有想过,为什么Mysql问题很多,但是这么多年却依旧没有人对其进行改进和优化。实际上就是因为这一块的实现难度太大了。

图 7

SQL本身实际上就是一串字符串,所以我们首先会有一个解析器。语法解析器(Parser)的实现本身不难,但是却极其繁琐。这主要是因为Mysql比较奇葩的语法,Mysql在SQL标准的基础上增加了很多自己的语法,因此这一模块的实现耗时极长,有一两个月之久。

但由于Parser只做语法规则的检查,SQL语句本身的逻辑却没法保证,因此在Parser后紧跟了Validate模块来检查SQL语句的逻辑意义。

在Validate模块后是一个类型推断。之所以有这个模块,主要是因为同一个SQL语句在不同的上下文环境有不同的语义,因此我们不得不根据上下文来进行类型推断。

接下来是优化器,这个模块我们有一个专门的团队来负责。优化器主要分为逻辑优化器和物理优化器。逻辑优化器主要是基于关系代数,比如子查询去关联等。然后是和底层的物理存储层打交道的物理优化器,索引等就是在这一块实现的。

后面还有一个分布式执行器,它主要是利用MPP模型来实现的,这也是分布式数据库比单机数据库要快的主要原因。

为什么选用go?

如图七 图八所示,主要是基于分布式数据库所带来的挑战以及Go语言在这一块所拥有的优势等考量,因而我们采用Go语言来实现TiDB。

首先是分布式数据库的实现本身确实极其复杂;TiDB底层通讯涉及大量RPC过程,如果是用诸如c++语言来实现的话,不是说不能,而是太过复杂了,Go语言和c++相比,它封装了底层的很多细节,而且Go语言本身也易学容易上手,生成效率高,更何况我们整个团队都是以Go语言为主;同时Go语言也足以满足性能方面的需求,尤其是在高并发、数据量大和OLTP查询等场景,甚至有时用户输入的不合理复杂的OLAP查询也不是问题;外部一致性,即Spanner中提到的全局一致性的保证;SQL带来的复杂度;易于Bug的发现,以及Profile等工具以及够用的GC性能。

图 8

图 9

Go在TiDB中的作用

图 10

由图九所示,TiDB中Golang的语言实现占得比例相当大,以及包括谢大在内的138个开源贡献者。

Go的调优

实际上主要是涉及内存方面的。

图 11

对象重用

图 12

OLTP和OLAP的融合

图 13

一些大型公司在做大数据分析时,基本是在晚上把数据从数据库通过ETL导入到Hive、ODPS等,也就是说要到第二天才能完成对这部分数据的查询。

因此我们团队考虑,是否可以直接在OLTP上跑一个大数据查询的引擎,这样就可以避免上述提到的这个过程,而且数据本身也可以比较实时地出现在报表中。TiSpark项目就是来实现这个功能的。

图 14

TiSpark是用的Spark的引擎,然后用Scala语言写了一个CoProcessor来实现Spark相关的一些操作。

这样子的话,和提供分布式事务功能的TiDB不同,TiSpark主要是用于需要分析和跑得快的场景。

   
次浏览     评价: 订阅 捐助
相关文章

我们该如何设计数据库
数据库设计经验谈
数据库设计过程
数据库编程总结
 
相关文档

数据库性能调优技巧
数据库性能调整
数据库性能优化讲座
数据库系统性能调优系列
相关课程

高性能数据库设计与优化
高级数据库架构师
数据仓库和数据挖掘技术
Hadoop原理、部署与性能调优
最新课程计划
 
最新文章
InfluxDB概念和基本操作
InfluxDB TSM存储引擎之数据写入
深度漫谈数据系统架构——Lambda architecture
Lambda架构实践
InfluxDB TSM存储引擎之数据读取
最新课程
Oracle数据库性能优化、架构设计和运行维护
并发、大容量、高性能数据库设计与优化
NoSQL数据库(原理、应用、最佳实践)
企业级Hadoop大数据处理最佳实践
Oracle数据库性能优化最佳实践
更多...   
成功案例
某金融公司 Mysql集群与性能优化
北京 并发、大容量、高性能数据库设计与优化
知名某信息通信公司 NoSQL缓存数据库技术
北京 oracle数据库SQL优化
中国移动 IaaS云平台-主流数据库及存储技术
更多...