背景
在日益数据量增加的状况下,影响数据库的读写性能,咱们通常会有分库分表的方案和使用newSql方案,newSql如TIDB。那么为何须要使用TiDB呢?有什么状况下才用TiDB呢?解决传统分库分表的什么问题呢?还会解释一些关键点和踩坑点。下面我会用比较白话的形式解读,当作对TiDB进行推广。mysql
目前痛点
目前分库表不管使用原生JDBC+ThreadLocal方案,仍是使用中间件proxy、仍是SDK嵌入代码的形式,即便用sharding-jdbc、zdal、mycat都存在着如下问题。git
- 分库分表算法方案的选型
- 分库分表后带来的后续维护工做,每次增长节点,都须要申请磁盘、机器
- 新增节点须要进行停机、而后迁移数据,停机迁移对线上用户形成实时的读写影响。迁移失败还有代码回滚。迁移前还要等mysql没有binlog产生后才能迁移。
- 分库分表后,跨库一致性问题,都是使用最终一致性,代码维护繁琐。
- 数据存储压力、数据存放量偏移于某个节点
- 数据索引查询效率:即便是分库了,要走索引查询,其实仍是须要查询多个库后得出结果后汇聚的。
- 不支持跨库left join其余表
- 惟一索引在跨库跨表不能保证惟一,场景如:支付流水号。如今分库分表的惟一key都很靠应用层代码控制。
- 表加字段麻烦。每一个库每一个表都要加
目的
分析TiDB如何解决痛点算法
点赞再看,关注公众号:【地藏思惟】给你们分享互联网场景设计与架构设计方案 掘金:地藏Kelvin https://juejin.im/user/5d67da8d6fb9a06aff5e85f7sql
TiDB总体架构
TiDB是一种分布式数据库。其实形式上来说比较像Hadoop的作法,把数据分布在不一样的机器上,而且有副本,有负责计算的机器、也由负责存储的机器。 数据库
入口层为tidb-server,图中TiDB,是客户端接入的入口,负责处理请求接口,这一层对存储要求不高,用于计算因此对CPU要求高,还有记录每一个region的负责的范围。 第二层是PD,负责调度,如zookeeper的形式,负责数据迁移的调度、选举的调度。 第三层是tikv,也叫store,负责真实存储数据的一层。其中tikv由1个或者多个region组成,Region为最小的存储单元,就如JVM G1算法的Region的意思。每一个Region将会打散分布在各个tikv下。服务器
数据存储模型
- 行数据(元数据) 一个表将会由一个或者多个Region存储。不一样的表将会在不一样的Region,而不是如传统分库那样每一个库里的表都是相同。 那么一个表下,每一行数据存储在哪一个Region下是如何肯定呢? 首先,Region里面是一个Map, key 由 table_id表id、rowid主键组成。如:
t[table_id]_r[row_id]网络
map的value为表中每行数据的真实数据。数据结构
- 索引数据 索引数据将会在另一个Region存储,每建一个索引,就会有那个索引对应的Region。它的Map的 key 由 table_id、index_id 以及索引列的值编码组成。如:
t[table_id]_i[index_id][index_value]架构
value为rowid,这样就能用rowid来找到上面的表数据的位置。 就如mysql按索引查询,会先去找索引记录,再去找到主键聚簇索引来获取真实数据一个逻辑。框架
数据切分
定位在哪一个Region,就是靠Key来算出落在哪一个Region里面。和分库分表的根据某个字段来一致性hash算法方案不一样。 TiDB的负责行真实数据的Region是使用主键范围来划分的。 有索引状况下,负责索引的Region会根据索引字段范围来划分。 基于Key经过计算,将会得出一个数字,而后按范围划分多个区间,每一个区间由一个Region管理。
如:一个表数据主键rowid落在3个Region。 [0,10000) [10001,20000) [20001,30000)
这个范围须要数据入表前肯定这个规则。
由于Region将会分布在全部TiKV上,也就有多个服务器去存数据,因此利用多机器CPU和磁盘,解决了痛点5存储压力,也解决了痛点1分库分表用哪一个算法方案,只须要肯定主键范围便可。
后续会说如何扩容。
提升索引效率
现有问题: 传统分库分表的索引都是在每一个mysql实例里,跟着表走的。分库分表规则,通常都是根据表中的userid用户字段或组合性较高的字段来作切分库或者表的键,相同的userid将会落在相同的库或者表。
可是上述状况下,表中的索引字段假设为code,则code="aaa"的可能会由于不一样的userid落在不一样的库中,须要查询全量的库和表后,再从新聚合,这样就会增长CPU查询的消耗、还有TCP链接握手的消耗。
TiDB解决: 然而TiKV的有专门用于存储索引的Region,它数据结构的Key是由 表id+索引id+索引值id来决定的,value是rowid数据行主键,而且一个Region管理一个范围的Key,因此同一个索引同一个值都会在一个Region里面,这样就比较好快速定位相同的索引值的Region,得出对应的rowid,再根据rowid去存储表数据的Region中更快速找到表真实数据。就不须要走全量库的索引查找,由于mysql索引查找机制是先找到索引值,而后再找聚簇的主键后返回整行数据,从而提升性能。
这种作法有点像elastic-search的倒排索引,先根据value值再定位数据原来位置。这里解决痛点6减小索引查询压力。
TIDB特性
1. 提供乐观事务模型和悲观事务模型
在3.0.8以前只有乐观事务模型,都是经过2PC两次提交的方式来进行事务提交。若是开启悲观事务模型,会比较像sharding-jdbc的柔性事务,有重试的功能,可是依然重试过屡次(256次)失败仍然会丢失。
1.1 优缺点分析
TiDB 事务有以下优势:
- 实现原理简单,易于理解。
- 基于单实例事务实现了跨节点事务。
- 锁管理实现了去中心化。 但 TiDB 事务也存在如下缺点:
- 两阶段提交使网络交互增多。
- 须要一个中心化的版本管理服务。
- 事务数据量过大时易致使内存暴涨。
1.2 事务的重试
使用乐观事务模型时,在高冲突率的场景中,事务很容易提交失败。而 MySQL 内部使用的是悲观事务模型,在执行 SQL 语句的过程当中进行冲突检测,因此提交时很难出现异常。为了兼容 MySQL 的悲观事务行为,TiDB 提供了重试机制。 这种加剧试就是悲观事务。
上述解决痛点4,不用再去本身维护跨库处理的事务最终一致性的代码,如A用户转帐到B用户,也如商家和买家的状况,商家比较多收入时的交易状况。 虽然重试屡次仍然会失败,可是这部分由TiDB处理。若是跨库事务之前的系统有框架处理,那如今就不须要如sharding-jdbc的sdk方式须要靠程序运行时才能重试,否则若是咱们程序down机重试就没了。
2. 自动扩容
2.1 Region分裂
Region为最小的存储单元,当数据进入一个Region后达到必定数量,就会开始分裂(默认是超过现有Region负责范围的1/16)。 注意:数据表 Key 的 Range 范围划分,须要提早设置好,TiKV 是根据 Region 的大小动态分裂的。
这里是解决痛点2的每次都须要申请资源,再也不运维来作上线前迁移数据,痛点3迁移时又要停机影响生成用户。
由于TiDB做为中间件,不带任何业务属性,因此就不能使用userid等字段来作分片规则的键和自定义算法,使用主键是最通用的选择。(其实我以为若是TiDB能作到就最好了)
2.2 新增存储节点
- 新增节点或者分裂Region,都有可能会触发迁移Region,由TiDB自动完成。再也不须要入侵代码、或者使用中间件作分库分表逻辑和数据迁移、上线演练,全程交给运维(手动甩锅)。
- 而且不须要代码服务停机,不须要等没有新sql执行后才能迁移,这个是运行过程当中实时迁移数据的。
这里就解决了痛点3停机迁移数据、痛点5存储压力。
3. 副本容灾
每一个 Region 负责维护集群的一段连续数据(默认配置下平均约 96 MiB),每份数据会在不一样的 Store 存储多个副本(默认配置是 3 副本),每一个副本称为 Peer。同一个 Region 的多个 Peer 经过 raft 协议进行数据同步,因此 Peer 也用来指代 raft 实例中的成员。
因此若是有1亿数据,将会由3亿数据落在磁盘中,虽然消耗磁盘,可是提升了可靠性。
TIDB成本
- 官方推荐至少部署 3 个 TiKV, 3 个 PD,2 个 TiDB。
- TiDB须要能使用线程数多的,PD须要CPU比较好的,TiKV须要SSD和CPU比较好的。
- 在论坛看到你们用的内存都是100G的,磁盘都是2T 的SSD。由于每行数据都总共有3个副本,消耗磁盘多。因此一个系统使用一套TiDB须要很多的成本。
- 然而这只是一个系统所需,一个项目中有多个系统组成状况下,就消耗更多资源了。而且随着数据日益增多将会愈来愈多资源。
使用场景
- 数据量达到必定量级,须要减小查询压力或者链接池不够等等因素后才须要进行。由于官方建议须要有2个tidb-server、至少两个PD、三个tikv,并且tikv须要都是SSD固态硬盘。因此在这种成本下,不必定全部项目都会使用,公司不必定愿意花成本去使用。而在一些数据量小的状况,建议仍是使用mysql,等到数据量上来后,再作数据同步到TiDB。
- 已经分库分表后,但愿改成使用TiDB,也能进行合并,须要使用TiDB Data Migration。
- 先在公司的架构组的项目使用,再到不是核心业务的项目使用,最后铺开给核心项目使用。
- 入门成本高,实验起来须要成本,由于官方推荐的部署方式须要多台好的机器。
注意事项与坑点
- 建议使用3.0.四、3.0.8或者4.0.0 (如今是2020年4月2日),不建议使用2.0版本,否则会出现升级不兼容的问题,须要去解决。
- 在增长节点扩容时,或者Region分裂时,同时有SQL执行insert或者更新数据,若是命中到对应的Region正在迁移,就可能会出现insert或者update出错 说“not leader”没有找到对应的位置的意思。可是会有重试的形式,把数据最终提交。
- 提早设置路由Region的分片范围规则,否则导入数据时会都落在一个节点上。若是你之前的主键数据时雪花算法得出的,那就须要求出最大最小值本身算范围手动设置好范围规则。
- TiDB 不支持 SELECT LOCK IN SHARE MODE。使用这个语句执行的时候,效果和没有加锁是同样的,不会阻塞其余事务的读写。
- 不要再使用Syncer同步数据或迁移到TiDB,由于若是在已经分库分表的状况下,使用Syncer同步,在某个帖子看的说会出问题。建议使用TiDB Data Migration
- TiDB没法修改字段类型
总结
其实有了上述功能,就能够减小分库分表的开发、运维维护成本,主要是日常分库分表到必定量要迁移,常常须要监控是否到迁移的量了,迁移时须要演练,迁移时要更新代码或者配置而且停业务是影响最大的。 虽然完成分库分表好像解决了一些问题,可是带来的后续仍是不少的,TiDB就给咱们解决了上面的问题,这样就能够更加专一的作业务了。
欢迎关注,文章更快一步
个人公众号 :地藏思惟
掘金:地藏Kelvin
简书:地藏Kelvin
个人Gitee: 地藏Kelvin https://gitee.com/kelvin-cai