我是如何低效的看TiKV代码的(一)

先从TiDB说起

TiDB 是什么

首先引用一下官方的定义:

TiDB 是 PingCAP 公司受 Google Spanner / F1 论文启发而设计的开源分布式 HTAP (Hybrid Transactional and Analytical Processing) 数据库,结合了传统的 RDBMS 和 NoSQL 的最佳特性。TiDB 兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。TiDB 的目标是为 OLTP (Online Transactional Processing) 和 OLAP (Online Analytical Processing) 场景提供一站式的解决方案。

TiDB 具备如下核心特性:

  • 高度兼容 MySQL

大多数情况下,无需修改代码即可从 MySQL 轻松迁移至 TiDB,分库分表后的 MySQL 集群亦可通过 TiDB 工具进行实时迁移。

  • 水平弹性扩展

通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松应对高并发、海量数据场景。

  • 分布式事务

TiDB 100% 支持标准的 ACID 事务。

  • 真正金融级高可用

相比于传统主从 (M-S) 复制方案,基于 Raft 的多数派选举协议可以提供金融级的 100% 数据强一致性保证,且在不丢失大多数副本的前提下,可以实现故障的自动恢复 (auto-failover),无需人工介入。

  • 一站式 HTAP 解决方案

TiDB 作为典型的 OLTP 行存数据库,同时兼具强大的 OLAP 性能,配合 TiSpark,可提供一站式 HTAP 解决方案,一份存储同时处理 OLTP & OLAP,无需传统繁琐的 ETL 过程。

TiDB 的设计目标是 100% 的 OLTP 场景和 80% 的 OLAP 场景。它解决了我们工作中面临的因为数据量大到一定程度后横向扩展受限,人工进行分库分表,人工进行数据库事务的问题。降低了开发人员的心智负担,让开发人员可以更专注于具体业务,提高了生产效率。

TiDB 整体架构

tidb总体结构

TiDB 有 TiDB Server 、PD Server、 TiKV Server 三个核心组件。

  • PD 是整个集群的管理模块,它拥有上帝视角。 其主要工作有三个:一是存储集群的元信息(某个 Key 存储在哪个 TiKV 节点);二是对 TiKV 集群进行调度和负载均衡(如数据的迁移、Raft group leader 的迁移等);三是分配全局唯一且递增的事务 ID。

  • TiKV Server 是一个分布式的提供事务的 Key-Value 存储引擎。 TiDB Server 负责接收 SQL 请求,处理 SQL 相关的逻辑,并通过 PD 找到存储计算所需数据的 TiKV 地址,与 TiKV 交互获取数据,最终返回结果。

  • TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,

在执行一条Insert语句会做什么事情?

画不多说, 先上图:


tidb内部结构

不要被这么复杂的图吓怕,因为其中的绝大部分内容都不会涉及(我也不会,不会还要拿来show --!!)。
主体流程还是很容易明白的,首先,TiDB会解析执行的SQL语句,使用parser 将其变成AST,然后通过执行计划将其拆解成一个个的executor。在获取到所有的executor的执行结果后,对数据进行拼装,最终返回给客户端。

那么,在数据库中数据是怎么进行存储,Server又是如何进行访问的呢?
其实,数据库将表中的row映射成kv结构,然后将kv进行物理存储。MySQL如此,TiDB也是如此。这种想法其实也很自然,数据库表中的每行使用id 作为key,行的内容作为value存储下来,查询某条记录,就变成了根据某个key,找对应的value。

Key的生成策略

首先,我们需要面对的问题就是对于一个数据库表,使用什么样的key生成策略来保存行的内容。同时因为数据库的索引结构也可以用表存储,因此,数据库的索引也会被持久化到kv 中。

TiDB 对每个表分配一个 TableID,每一个索引都会分配一个 IndexID,每一行分配一个 RowID(如果表有整数型的 Primary Key,那么会用 Primary Key 的值当做 RowID),其中 TableID 在整个集群内唯一,IndexID/RowID 在表内唯一,这些 ID 都是 int64 类型。

  1. 数据库行的key生成策略
${tablePrefix}_${rowPrefix}_${tableID}_${rowID}

其中tablePrefix是固定的t_rowPrefix是固定的r_。比如 table table_demo 的ID 为10,其中第一条数据的row ID 是1,那么它的key是t_r_10_1

  1. 数据库索引key的生成策略
  • 主键或者唯一键的索引
${tablePrefix}_${idxPrefix}_${tableID}_${indexID}_${indexColumnsValue}

其中idxPrefix 是固定的i_, 比如id字段的索引ID 为2, 那么它对应的key 是 t_i_10_2_1 --> t_r_10_1

  • 非主键索引
${tablePrefix}_${idxPrefix}_${tableID}_${indexID}_${ColumnsValue}_${rowID}

具体的细节可以查看参考资料,里面有非常详细的表述。这里不做过多的解释

TiDB 和TiKV的交互接口

在整个学习的过程中,头脑中需要有一个问题,selectinsert 操作是怎么在TiKV中实现的。
既然TiDB 已经将具体的数据库的row, 转化成了kv,那么问题本身也就转化成了在TiKV中如何实现getset 命令。

这里先列举相关的TiKV暴露给TiDB调用的接口,学习的过程可以从这里入手。

service Tikv {

    // KV commands with mvcc/txn supported.

    rpc KvGet(kvrpcpb.GetRequest) returns (kvrpcpb.GetResponse) {}

    rpc KvScan(kvrpcpb.ScanRequest) returns (kvrpcpb.ScanResponse) {}

    rpc KvPrewrite(kvrpcpb.PrewriteRequest) returns (kvrpcpb.PrewriteResponse) {}

    rpc KvCommit(kvrpcpb.CommitRequest) returns (kvrpcpb.CommitResponse) {}

    rpc KvImport(kvrpcpb.ImportRequest) returns (kvrpcpb.ImportResponse) {}

    rpc KvCleanup(kvrpcpb.CleanupRequest) returns (kvrpcpb.CleanupResponse) {}

    rpc KvBatchGet(kvrpcpb.BatchGetRequest) returns (kvrpcpb.BatchGetResponse) {}

    rpc KvBatchRollback(kvrpcpb.BatchRollbackRequest) returns (kvrpcpb.BatchRollbackResponse) {}

    rpc KvScanLock(kvrpcpb.ScanLockRequest) returns (kvrpcpb.ScanLockResponse) {}

    rpc KvResolveLock(kvrpcpb.ResolveLockRequest) returns (kvrpcpb.ResolveLockResponse) {}

    rpc KvGC(kvrpcpb.GCRequest) returns (kvrpcpb.GCResponse) {}

    rpc KvDeleteRange(kvrpcpb.DeleteRangeRequest) returns (kvrpcpb.DeleteRangeResponse) {}

    // RawKV commands.

    rpc RawGet(kvrpcpb.RawGetRequest) returns (kvrpcpb.RawGetResponse) {}

    rpc RawBatchGet(kvrpcpb.RawBatchGetRequest) returns (kvrpcpb.RawBatchGetResponse) {}

    rpc RawPut(kvrpcpb.RawPutRequest) returns (kvrpcpb.RawPutResponse) {}

    rpc RawBatchPut(kvrpcpb.RawBatchPutRequest) returns (kvrpcpb.RawBatchPutResponse) {}

    rpc RawDelete(kvrpcpb.RawDeleteRequest) returns (kvrpcpb.RawDeleteResponse) {}

    rpc RawBatchDelete(kvrpcpb.RawBatchDeleteRequest) returns (kvrpcpb.RawBatchDeleteResponse) {}

    rpc RawScan(kvrpcpb.RawScanRequest) returns (kvrpcpb.RawScanResponse) {}

    rpc RawDeleteRange(kvrpcpb.RawDeleteRangeRequest) returns (kvrpcpb.RawDeleteRangeResponse) {}

    rpc RawBatchScan(kvrpcpb.RawBatchScanRequest) returns (kvrpcpb.RawBatchScanResponse) {}

    // SQL push down commands.

    rpc Coprocessor(coprocessor.Request) returns (coprocessor.Response) {}

    rpc CoprocessorStream(coprocessor.Request)  returns (stream coprocessor.Response) {}

    // Raft commands (tikv <-> tikv).

    rpc Raft(stream raft_serverpb.RaftMessage) returns (raft_serverpb.Done) {}

    rpc Snapshot(stream raft_serverpb.SnapshotChunk) returns (raft_serverpb.Done) {}

    // Region commands.

    rpc SplitRegion (kvrpcpb.SplitRegionRequest) returns (kvrpcpb.SplitRegionResponse) {}

    // transaction debugger commands.

    rpc MvccGetByKey(kvrpcpb.MvccGetByKeyRequest) returns (kvrpcpb.MvccGetByKeyResponse) {}

    rpc MvccGetByStartTs(kvrpcpb.MvccGetByStartTsRequest) returns (kvrpcpb.MvccGetByStartTsResponse) {}

}

参考资料

  1. https://pingcap.com/blog-cn/tidb-internal-2/

  2. https://pingcap.com/blog-cn/tidb-source-code-reading-4/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 一、分布式数据库诞生背景 随着互联网的飞速发展,业务量可能在短短的时间内爆发式地增长,对应的数据量可能快速地从几百...
    nightwish夜愿阅读 3,514评论 0 12
  • 71.1kg 早饭:一杯醇品,三片切片,20g原味沙拉酱,白开水两杯。 午饭:一份米饭淋辣椒油(美滋滋),一份葱豆...
    yummy0632阅读 190评论 0 0
  • 产后第一件事:满月排毒发汗 产后排毒发汗越早做越好,只要在产后身体没有闭合状态下,早排毒早好,排出身体毒素、湿气,...
    蕴姿妈妈产后调理阅读 1,261评论 0 1
  • 初识饼部落是一个很简单的开始:爱鲜啤的掌柜在朋友圈做了一个推荐,出于对掌柜的信任,添加了酋长和饼哥的微信,...
    尧酋长阅读 746评论 2 3
  • 自我分析(以第三人称叙述): 首先是屋顶。屋顶瓦片层层叠叠,看似很用细心添砖加瓦,细看的话,第一排和最后一排的精细...
    渡迷阅读 279评论 2 1