tidb

TiDB笔记 #

TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP)的融合型分布式数据库产品,具备水平扩容或者缩容、金融级高可用、实时 HTAP、云原生的分布式数据库、兼容 MySQL 5.7 协议和 MySQL 生态等重要特性。目标是为用户提供一站式 OLTP (Online Transactional Processing)、OLAP (Online Analytical Processing)、HTAP 解决方案。TiDB 适合高可用、强一致要求较高、数据规模较大等各种应用场景。

官方文档

1. 使用tiup离线部署 #

1.1. 准备tiup镜像目录 #

VER=v4.0.7
mkdir /data/src -p && \
  cd /data/src && \
  wget https://download.pingcap.org/tidb-community-server-${VER}-linux-amd64.tar.gz && \
  tar xf tidb-community-server-${VER}-linux-amd64.tar.gz && \
  bash tidb-community-server-${VER}-linux-amd64/local_install.sh

维护时如果需要修改镜像目录,可以通过tiup mirror set tidb-community-server-${VER}-linux-amd64进行切换

1.2. TiDB初始化 #

global:
  user: "tidb"
  ssh_port: 22
  deploy_dir: "/data/tidb/deploy"
  data_dir: "/data/tidb/data"

server_configs:
  tidb:
    log.slow-threshold: 600
    binlog.enable: false
    binlog.ignore-error: false
    mem-quota-query: 1073741824
    oom-action: "log"
  tikv:
    raftstore.hibernate-regions: true
    raftstore.raft-base-tick-interval: 2s
    raftstore.store-pool-size: 4
    readpool.storage.use-unified-pool: false
    server.grpc-concurrency: 8
    storage.block-cache.capacity: 24GB
  pd:
    replication.enable-placement-rules: true

pd_servers:
  - host: 10.40.195.1
    client_port: 2379
    peer_port: 2380
    data_dir: "/data/tidb/pd-2379/data"
    deploy_dir: "/data/tidb/pd-2379/deploy"
    log_dir: "/data/tidb/pd-2379/log"
  - host: 10.40.195.2
    client_port: 2379
    peer_port: 2380
    data_dir: "/data/tidb/pd-2379/data"
    deploy_dir: "/data/tidb/pd-2379/deploy"
    log_dir: "/data/tidb/pd-2379/log"
  - host: 10.40.195.3
    client_port: 2379
    peer_port: 2380
    data_dir: "/data/tidb/pd-2379/data"
    deploy_dir: "/data/tidb/pd-2379/deploy"
    log_dir: "/data/tidb/pd-2379/log"
tidb_servers:
  - host: 10.40.195.4
    port: 4000
    status_port: 10080
    deploy_dir: "/data/tidb/tidb-4000/deploy"
    log_dir: "/data/tidb/tidb-4000/log"
  - host: 10.40.195.5
    port: 4000
    status_port: 10080
    deploy_dir: "/data/tidb/tidb-4000/deploy"
    log_dir: "/data/tidb/tidb-4000/log"
  - host: 10.40.195.6
    port: 4000
    status_port: 10080
    deploy_dir: "/data/tidb/tidb-4000/deploy"
    log_dir: "/data/tidb/tidb-4000/log"
tikv_servers:
  - host: 10.40.195.7
    port: 20160
    status_port: 20180
    data_dir: "/data/tidb/tikv-20160/data"
    deploy_dir: "/data/tidb/tikv-20160/deploy"
    log_dir: "/data/tidb/tikv-20160/log"
  - host: 10.40.195.8
    port: 20160
    status_port: 20180
    data_dir: "/data/tidb/tikv-20160/data"
    deploy_dir: "/data/tidb/tikv-20160/deploy"
    log_dir: "/data/tidb/tikv-20160/log"
  - host: 10.40.195.9
    port: 20160
    status_port: 20180
    data_dir: "/data/tidb/tikv-20160/data"
    deploy_dir: "/data/tidb/tikv-20160/deploy"
    log_dir: "/data/tidb/tikv-20160/log"

monitoring_servers:
  - host: 10.40.195.10
    port: 9090
    deploy_dir: "/data/tidb/prometheus-9090/deploy"
    data_dir: "/data/tidb/prometheus-9090/data"
    log_dir: "/data/tidb/prometheus-9090/log"

grafana_servers:
  - host: 10.40.195.10
    port: 3000
    deploy_dir: "/data/tidb/grafana-3000/deploy"

alertmanager_servers:
  - host: 10.40.195.10
    deploy_dir: "/data/tidb/alertmanager-9093/deploy"
    data_dir: "/data/tidb/alertmanager-9093/data"
    log_dir: "/data/tidb/alertmanager-9093/log"

初始化,可以先弄3 * tidb-server + 3 * pd + 3 * tikv + 1 * monitor的简单拓扑,借助tiup强大的配置维护能力,增减组件很方便

# 部署集群
tiup cluster deploy tidb-dev v4.0.7 topology.yaml --user tidb
# 启动集群
tiup cluster start tidb-dev
# 查看组件状态
tiup cluster display tidb-dev

1.3. 如何离线升级 #

1.3.1. 下载新版本离线包,设置为镜像目录 #

1.3.2. 执行操作升级 #

tiup update cluster
# 以升级到v4.0.8为例
tiup cluster upgrade tidb-dev v4.0.8
# 升级后验证
tiup cluster display tidb-dev

2. 执行计划 #

TiDB 优化器会根据当前数据表的最新的统计信息来选择最优的执行计划,执行计划由一系列的算子构成。本文将详细解释 TiDB 中的执行计划。

  • EXPLAIN 可以和 SELECTDELETE 等语句一起使用;
  • 执行 EXPLAIN,TiDB 会返回被 EXPLAIN 的 SQL 语句经过优化器后的最终物理执行计划。也就是说,EXPLAIN 展示了 TiDB 执行该 SQL 语句的完整信息,比如以什么样的顺序,什么方式 JOIN 两个表,表达式树长什么样等等。

通过观察 EXPLAIN 的结果,你可以知道如何给数据表添加索引使得执行计划使用索引从而加速 SQL 语句的执行速度;你也可以使用 EXPLAIN 来检查优化器是否选择了最优的顺序来 JOIN 数据表。

2.1. EXPLAIN输出格式 #

属性名 含义
id 算子的 ID,是算子在整个执行计划中唯一的标识
estRows 算子预计将会输出的数据条数,基于统计信息以及算子的执行逻辑估算而来
task 算子属于的task类别。目前有两种,一种叫 root task,在 tidb-server 上执行,一种叫 cop task,在TiKV或者 TiFlash 上并行执行。当前的执行计划在 task 级别的拓扑关系是一个 root task 后面可以跟许多 cop taskroot task 使用 cop task 的输出结果作为输入。cop task 中执行的也即是 TiDB 下推到 TiKV 或者 TiFlash 上的任务,每个 cop task 分散在 TiKV 或者 TiFlash 集群中,由多个进程共同执行。
access object 算子所访问的数据项信息。包括表 table,表分区 partition 以及使用的索引 index(如果有)。只有直接访问数据的算子才拥有这些信息。
operator info 算子的其它信息。各个算子的operator info各有不同。

2.2. 算子的执行顺序 #

TiDB 的执行计划是一个树形结构,树中每个节点即是算子。考虑到每个算子内多线程并发执行的情况,在一条 SQL 执行的过程中,如果能够有一个手术刀把这棵树切开看看,大家可能会发现所有的算子都正在消耗 CPU 和内存处理数据,从这个角度来看,算子是没有执行顺序的。

但是如果从一行数据先后被哪些算子处理的角度来看,一条数据在算子上的执行是有顺序的。这个顺序可以通过下面这个规则简单总结出来:

Build 总是先于 Probe 执行,并且 Build 总是出现在 Probe 前面。

这个原则的前半句是说:如果一个算子有多个孩子节点,孩子节点 ID 后面有 Build 关键字的算子总是先于有 Probe 关键字的算子执行。后半句是说:TiDB 在展现执行计划的时候,Build 端总是第一个出现,接着才是 Probe 端。

这种规则隐含的另一个信息是:在同一层级的节点中,出现在最前面的算子可能是最先被执行的,而出现在最末尾的算子可能是最后被执行的。

2.3. 如何阅读扫表的执行计划 #

真正执行扫表(读盘或者读 TiKV Block Cache)操作的算子有如下几类:

  • TableFullScan:这是大家所熟知的 “全表扫” 操作
  • TableRangeScan:带有范围的表数据扫描操作
  • TableRowIDScan:根据上层传递下来的 RowID 精确地扫描表数据
  • IndexFullScan:另一种“全表扫”,只不过这里扫的是索引数据,不是表数据
  • IndexRangeScan:带有范围的索引数据扫描操作

TiDB 会汇聚 TiKV/TiFlash 上扫描的数据或者计算结果,这种“数据汇聚”算子目前有如下几类:

  • TableReader:将 TiKV 上底层扫表算子 TableFullScan 或 TableRangeScan 得到的数据进行汇总。
  • IndexReader:将 TiKV 上底层扫表算子 IndexFullScan 或 IndexRangeScan 得到的数据进行汇总。
  • IndexLookUp:先汇总 Build 端 TiKV 扫描上来的 RowID,再去 Probe 端上根据这些 RowID 精确地读取 TiKV 上的数据。Build 端是 IndexFullScan 或 IndexRangeScan 类型的算子,Probe 端是 TableRowIDScan 类型的算子。
  • IndexMerge:和 IndexLookupReader 类似,可以看做是它的扩展,可以同时读取多个索引的数据,有多个 Build 端,一个 Probe 端。执行过程也很类似,先汇总所有 Build 端 TiKV 扫描上来的 RowID,再去 Probe 端上根据这些 RowID 精确地读取 TiKV 上的数据。Build 端是 IndexFullScan 或 IndexRangeScan 类型的算子,Probe 端是 TableRowIDScan 类型的算子。

2.4. 如何阅读聚合的执行计划 #

TiDB 的聚合算法包括如下两类:

  • Hash Aggregate
  • Stream Aggregate

TiDB 上的 Hash Aggregation 算子采用多线程并发优化,执行速度快,但会消耗较多内存。

一般而言 TiDB 的 Hash Aggregate 会分成两个阶段执行,一个在 TiKV/TiFlash 的 Coprocessor 上,在扫表算子读取数据时计算聚合函数的中间结果。另一个在 TiDB 层,汇总所有 Coprocessor Task 的中间结果后,得到最终结果。其中 explain 表中的 operator info 列还记录了 Hash Aggregation 的其他信息,我们需要关注的信息是 Aggregation 所使用的聚合函数是什么。

TiDB Stream Aggregation 算子通常会比 Hash Aggregate 占用更少的内存,有些场景中也会比 Hash Aggregate 执行得更快。当数据量太大或者系统内存不足时,可以试试 Stream Aggregate 算子。和 Hash Aggregate 类似,一般而言 TiDB 的 Stream Aggregate 也会分成两个阶段执行,一个在 TiKV/TiFlash 的 Coprocessor 上,在扫表算子读取数据时计算聚合函数的中间结果。另一个在 TiDB 层,汇总所有 Coprocessor Task 的中间结果后,得到最终结果。

2.5. 如何阅读Join的执行计划 #

TiDB 的 Join 算法包括如下几类:

  • Hash Join
  • Merge Join
  • Index Join (Index Nested Loop Join)
  • Index Hash Join (Index Nested Loop Hash Join)
  • Index Merge Join (Index Nested Loop Merge Join)

未完待续