首页 » MySQL » TiDB介绍

TiDB介绍

 
文章目录

TiDB

TiDB总体介绍

TiDB简介

TiDB 是 PingCAP 公司基于 Google Spanner / F1 论文实现的开源分布式 NewSQL 数据库。

TiDB具备如下NewSQL核心特性:

  • SQL支持(TiDB是兼容mysql协议的)
  • 水平线性弹性扩展
  • 分布式事务
  • 跨数据中心数据强一致性保证
  • 故障自恢复的高可用

TiDB 的设计目标是 100% 的 OLTP (On-line Transaction Processing联机事务处理过程)场景和 80% 的 OLAP (On-line Analytical Processing联机分析处理) 场景。

TiDB 对业务没有任何侵入性,能优雅的替换传统的数据库中间件、数据库分库分表等 Sharding 方案。同时它也让开发运维人员不用关注数据库 Scale 的细节问题,专注于业务开发,极大的提升研发的生产力。

TiDB整体架构

TiDB集群主要分为三个组件:

TiDB Server

TiDB Server 负责接收SQL请求,处理SQL相关的逻辑,并通过PD找到存储计算所需数据的TiKV地址,与TiKV交互获取数据,最终返回结果。TiDB Server是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以无限水平扩展,可以通过负载均衡组件(如LVS,HAProxy或F5)对外提供统一的接入地址。

PD Server

Placement Driver (简称 PD) 是整个集群的管理模块,其主要工作有三个:

  • 一是存储集群的元信息(某个 Key 存储在哪个 TiKV 节点);
  • 二是对 TiKV 集群进行调度和负载均衡(如数据的迁移、Raft group leader 的迁移等);
  • 三是分配全局唯一且递增的事务 ID。

PD 是一个集群,需要部署奇数个节点,一般线上推荐至少部署 3 个节点

TiKV Server

TiKV Server 负责存储数据,从外部看 TiKV 是一个分布式的提供事务的 Key-Value 存储引擎。存储数据的基本单位是 Region,每个 Region 负责存储一个 Key Range (从 StartKey 到 EndKey 的左闭右开区间)的数据,每个 TiKV 节点会负责多个 Region 。TiKV 使用 Raft 协议做复制,保持数据的一致性和容灾。副本以 Region 为单位进行管理,不同节点上的多个 Region 构成一个 Raft Group,互为副本。数据在多个 TiKV 之间的负载均衡由 PD 调度,这里也是以 Region 为单位进行调度。

核心特性

水平扩展

无限水平扩展是TiDB的一大特点,这里说的水平扩展包括两方面:计算能力和存储能力。TiDB Server负责处理 SQL 请求,随着业务的增长,可以简单的添加TiDB Server节点,提高整体的处理能力,提供更高的吞吐。TiKV负责存储数据,随着数据量的增长,可以部署更多的TiKV Server节点解决数据Scale的问题。PD会在TiKV节点之间以 Region 为单位做调度,将部分数据迁移到新加的节点上。所以在业务的早期,可以只部署少量的服务实例(推荐至少部署3个TiKV,3个PD,2个TiDB),随着业务量的增长,按照需求增加TiKV或者TiDB实例。

高可用

高可用是TiDB的另一大特点,TiDB/TiKV/PD这三个组件都能容忍部分实例失效,不影响整个集群的可用性。下面分别说明这三个组件的可用性、单个实例失效后的后果以及如何恢复。

  • TiDB
    TiDB是无状态的,推荐至少部署两个实例,前端能过负载均衡组件对外提供服务。当单个实例失效时,会影响正在这个实例上进行的session,从应用的角度看,会出现单次请求失败的情况,重新连接后即可继续获得服务。单个实例失效后,可以重启这个实例或者部署一个新的实例。
  • PD
    PD是一个集群,能过Raft协保持数据的一致性,单个实例失效时,如果这个实例不是Raft的 leader ,那么服务完全不受影响;如果这个实例是Raft的leader,会重新选出新的 Raft leader,自动恢复服务。PD在选举的过程中无法对外提供服务,这个时间大约是3秒钟。推荐至少部署三个PD实例,单个实例失效后,重启这个实例或者添加新的实例。
  • TiKV
    TiKV 是一个集群,通过Raft 协议保持数据的一致性(副本数量可配置,默认保存三副本),并通过PD 做负载均衡调度。单个节点失效,并且在一段时间内(默认10分钟)无法恢复,PD会将其上的数据迁移到其他的TiKV节点上。

安装或部署

以下都是针对centos 7下的操作
下载压缩包:
wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz
wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256

检查文件完整性,返回 ok 则正确
sha256sum -c tidb-latest-linux-amd64.sha256

手动启的tidb集群,这种不是很规范,没有配置文件,用ansible-playbook来安装的规范,如下:

  • TiDB
nohup ./bin/tidb-server  --store=tikv \
	--path="192.168.7.205:2379,192.168.7.206:2379,192.168.7.207:2379" \
	--log-file=tidb.log  &
  • PD
nohup ./bin/pd-server --name=pd1 \
                --data-dir=pd1 \
                --client-urls="http://192.168.7.205:2379" \
                --peer-urls="http://192.168.7.205:2380" \
                --initial-cluster="pd1=http://192.168.7.205:2380,pd2=http://192.168.7.206:2380,pd3=http://192.168.7.207:2380" \
                --log-file=pd.log  &

nohup ./bin/pd-server --name=pd2 \
                --data-dir=pd2 \
                --client-urls="http://192.168.7.206:2379" \
                --peer-urls="http://192.168.7.206:2380" \
                --initial-cluster="pd1=http://192.168.7.205:2380,pd2=http://192.168.7.206:2380,pd3=http://192.168.7.207:2380" \
                --log-file=pd.log  &

nohup ./bin/pd-server --name=pd3 \
                --data-dir=pd3 \
                --client-urls="http://192.168.7.207:2379" \
                --peer-urls="http://192.168.7.207:2380" \
                --initial-cluster="pd1=http://192.168.7.205:2380,pd2=http://192.168.7.206:2380,pd3=http://192.168.7.207:2380" \
                --log-file=pd.log  &
  • TiKV
nohup ./bin/tikv-server --pd="192.168.7.205:2379,192.168.7.206:2379,192.168.7.207:2379" \
                  --addr="192.168.7.208:20160" \
                  --data-dir=tikv1 \
                  --log-file=tikv.log &
nohup ./bin/tikv-server --pd="192.168.7.205:2379,192.168.7.206:2379,192.168.7.207:2379" \
                  --addr="192.168.7.209:20160" \
                  --data-dir=tikv2 \
                  --log-file=tikv.log &

nohup ./bin/tikv-server --pd="192.168.7.205:2379,192.168.7.206:2379,192.168.7.207:2379" \
                  --addr="192.168.7.210:20160" \
                  --data-dir=tikv3 \
                  --log-file=tikv.log &

参数说明

TiDB(tidb-server)

[root@node1 bin]# ./tidb-server -h
Usage of ./tidb-server:
  -L string
    	log level: info, debug, warn, error, fatal (default "info")
  -P string
    	tidb server port (default "4000")
  -V	print version information and exit
  -binlog-socket string
    	socket file to write binlog
  -cross-join
    	whether support cartesian product or not. (default true)
  -host string
    	tidb server host (default "0.0.0.0")
  -join-concurrency int
    	the number of goroutines that participate joining. (default 5)
  -lease string
    	schema lease duration, very dangerous to change only if you know what you do (default "10s")
  -log-file string
    	log file path
  -metrics-addr string
    	prometheus pushgateway address, leaves it empty will disable prometheus push.
  -metrics-interval int
    	prometheus client push interval in second, set "0" to disable prometheus push. (default 15)
  -path string
    	tidb storage path (default "/tmp/tidb")
  -perfschema
    	If enable performance schema.
  -privilege
    	If enable privilege check feature. This flag will be removed in the future. (default true)
  -report-status
    	If enable status report HTTP service. (default true)
  -retry-limit int
    	the maximum number of retries when commit a transaction (default 10)
  -run-ddl
    	run ddl worker on this tidb-server (default true)
  -skip-grant-table
    	This option causes the server to start without using the privilege system at all.
  -socket string
    	The socket file to use for connection.
  -statsLease string
    	stats lease duration, which inflences the time of analyze and stats load. (default "3s")
  -status string
    	tidb server status port (default "10080")
  -store string
    	registered store name, [memory, goleveldb, boltdb, tikv, mocktikv] (default "goleveldb")

–store

  • 用来指定 TiDB 底层使用的存储引擎
  • 默认: “goleveldb”
  • 你可以选择 “memory”, “goleveldb”, “BoltDB” 或者 “TiKV”。(前面三个是本地存储引擎,而 TiKV 是一个分布式存储引擎)
  • 例如,如果我们可以通过 tidb-server --store=memory 来启动一个纯内存引擎的 TiD

–path

  • 对于本地存储引擎 “goleveldb”, “BoltDB” 来说,path 指定的是实际的数据存放路径
  • 对于 “memory” 存储引擎来说,path 不用设置
  • 对于 “TiKV” 存储引擎来说,path 指定的是实际的 PD 地址。假设我们在 192.168.100.113:2379, 192.168.100.114:2379 和 192.168.100.115:2379 上面部署了 PD,那么 path 为 “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379”
  • 默认: “/tmp/tidb”

-L

  • Log 级别
  • 默认: “info”
  • 我们能选择 debug, info, warn, error 或者 fatal

–log-file

  • Log 文件
  • 默认: “”
  • 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份

–host

  • TiDB 服务监听 host
  • 默认: “0.0.0.0”
  • TiDB 服务会监听这个 host
  • 0.0.0.0 默认会监听所有的网卡 address。如果有多块网卡,可以指定对外提供服务的网卡,譬如192.168.100.113

-P

  • TiDB 服务监听端口
  • 默认: “4000”
  • TiDB 服务将会使用这个端口接受 MySQL 客户端发过来的请求

–status

  • TiDB 服务状态监听端口
  • 默认: “10080”
  • 这个端口是为了展示 TiDB 内部数据用的。包括 prometheus 统计 以及 pprof
  • Prometheus 统计可以通过 “http://host:status_port/metrics” 访问
  • Pprof 数据可以通过 “http://host:status_port/debug/pprof” 访问

–lease

  • Schema 的租约时间,单位:秒
  • 默认: “1”
  • Schema 的 lease 主要用在 online schema changes 上面。这个值会影响到实际的 DDL 的执行时间。千万不要随便改动这个值,除非你能知道相关的内部机制

–socket

  • TiDB 服务使用 unix socket file 方式接受外部连接
  • 默认: “”
  • 譬如我们可以使用 “/tmp/tidb.sock” 来打开 unix socket file

–perfschema

  • 使用 true/false 来打开或者关闭性能 schema
  • 默认: false
  • 值可以是 (true) or (false)。性能 Schema 可以帮助我们在运行时检测内部的执行情况。可以通过 performance schema 获取更多信息。但需要注意,开启性能 Schema,会影响 TiDB 的性能

–privilege

  • 使用 true/false 来打开或者关闭权限功能(用于开发调试)
  • 默认: true
  • 值可以是(true) or (false)。当前版本的权限控制还在完善中,将来会去掉此选项

–skip-grant-table

  • 允许任何人不带密码连接,并且所有的操作不检查权限
  • 默认: false
  • 值可以是(true) or (false)。启用此选项需要有本机的root权限,一般用于忘记密码时重置

–report-status

  • 打开 (true) 或者关闭 (false) 服务状态监听端口
  • 默认: true
  • 值可以为 (true) 或者 (false). (true) 表明我们开启状态监听端口。 (false) 表明关闭

–metrics-addr

  • Prometheus Push Gateway 地址
  • 默认: “”
  • 如果为空,TiDB 不会将统计信息推送给 Push Gateway

–metrics-intervel

  • 推送统计信息到 Prometheus Push Gateway 的时间间隔
  • 默认: 15s
  • 设置为 0 表明不推送统计信息给 Push Gateway

PD(pd-server)

[root@node1 tidb-latest-linux-amd64]# ./bin/pd-server -h
Usage of pd:
  -L string
    	log level: debug, info, warn, error, fatal (default 'info')
  -V	print version information and exit
  -advertise-client-urls string
    	advertise url for client traffic (default '${client-urls}')
  -advertise-peer-urls string
    	advertise url for peer traffic (default '${peer-urls}')
  -client-urls string
    	url for client traffic (default "http://127.0.0.1:2379")
  -config string
    	Config file
  -data-dir string
    	path to the data directory (default 'default.${name}')
  -initial-cluster string
    	initial cluster configuration for bootstrapping, e,g. pd=http://127.0.0.1:2380
  -join string
    	join to an existing cluster (usage: cluster's '${advertise-client-urls}'
  -log-file string
    	log file path
  -log-rotate
    	rotate log (default true)
  -name string
    	human-readable name for this pd member (default "pd")
  -peer-urls string
    	url for peer traffic (default "http://127.0.0.1:2380")
  -version
    	print version information and exit
[root@node1 tidb-latest-linux-amd64]#

-L

  • Log 级别
  • 默认: “info”
  • 我们能选择 debug, info, warn, error 或者 fatal

–log-file

  • Log 文件
  • 默认: “”
  • 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份

–config

  • 配置文件
  • 默认: “”
  • 如果你指定了配置文件,PD 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,PD 就会使用命令行参数的配置来覆盖配置文件里面的

–name

  • 当前 PD 的名字
  • 默认: “pd”
  • 如果你需要启动多个 PD,一定要给 PD 使用不同的名字

–data-dir

  • PD 存储数据路径
  • 默认: “default.${name}”

–client-urls

  • 处理客户端请求监听 URL 列表
  • 默认: “http://127.0.0.1:2379”
  • 如果部署一个集群,–client-urls 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:2379″,如果是运行在 docker 则需要指定为 “http://0.0.0.0:2379”

–advertise-client-urls

  • 对外客户端访问 URL 列表
  • 默认: ${client-urls}
  • 在某些情况下,譬如 docker,或者 NAT 网络环境,客户端并不能通过 PD 自己监听的 client URLs 来访问到 PD,这时候,你就可以设置 advertise urls 来让客户端访问
  • 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 2379:2379,那么可以设置为 –advertise-client-urls=”http://192.168.100.113:2379″,客户端可以通过 http://192.168.100.113:2379 来找到这个服务

–peer-urls

  • 处理其他 PD 节点请求监听 URL 列表。
  • default: “http://127.0.0.1:2380”
  • 如果部署一个集群,–peer-urls 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:2380″,如果是运行在 docker 则需要指定为 “http://0.0.0.0:2380”

–advertise-peer-urls

  • 对外其他 PD 节点访问 URL 列表。
  • 默认: ${peer-urls}
  • 在某些情况下,譬如 docker,或者 NAT 网络环境,其他节点并不能通过 PD 自己监听的 peer URLs 来访问到 PD,这时候,你就可以设置 advertise urls 来让其他节点访问
  • 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 2380:2380,那么可以设置为 –advertise-peer-urls=”http://192.168.100.113:2380″,其他 PD 节点可以通过 http://192.168.100.113:2380 来找到这个服务

–initial-cluster

  • 初始化 PD 集群配置。
  • 默认: “{name}=http://{advertise-peer-url}”
  • 例如,如果 name 是 “pd”, 并且 advertise-peer-urls 是 “http://192.168.100.113:2380”, 那么 initial-cluster 就是 pd=http://192.168.100.113:2380
  • 如果你需要启动三台 PD,那么 initial-cluster 可能就是pd1=http://192.168.100.113:2380, pd2=http://192.168.100.114:2380, pd3=192.168.100.115:2380

–join

  • 动态加入 PD 集群
  • 默认: “”
  • 如果你想动态将一台 PD 加入集群,你可以使用 --join="${advertise-client-urls}"advertise-client-url 是当前集群里面任意 PD 的advertise-client-url,你也可以使用多个 PD 的,需要用逗号分隔

TiKV(tikv-server)

[root@node1 tidb-latest-linux-amd64]# bin/tikv-server -h
TiKV 
PingCAP Inc. <info@pingcap.com>
A Distributed transactional key-value database powered by Rust and Raft

USAGE:
    tikv-server [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -A, --addr               Sets listening address
        --advertise-addr     Sets advertise listening address for client communication
        --capacity          Sets the store capacity
    -C, --config                Sets config file
    -s, --data-dir              Sets the path to store directory
        --labels <key=value>...       Sets server labels
    -f, --log-file              Sets log file
    -L, --log-level            Sets log level [values: trace, debug, info, warn, error, off]
        --pd-endpoints ...    Sets PD endpoints

TiKV 在命令行参数上面支持一些可读性好的单位转换。

  • 文件大小(以 bytes 为单位): KB, MB, GB, TB, PB(也可以全小写)
  • 时间(以毫秒为单位): ms, s, m, h

-A, –addr

  • TiKV 监听地址
  • 默认: “127.0.0.1:20160”
  • 如果部署一个集群,–addr 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:20160″,如果是运行在 docker 则需要指定为 “http://0.0.0.0:20160”

–advertise-addr

  • TiKV 对外访问地址。
  • 默认: ${addr}
  • 在某些情况下,譬如 docker,或者 NAT 网络环境,客户端并不能通过 TiKV 自己监听的地址来访问到 TiKV,这时候,你就可以设置 advertise addr 来让 客户端访问
  • 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 20160:20160,那么可以设置为 –advertise-addr=”192.168.100.113:20160″,客户端可以通过 192.168.100.113:20160 来找到这个服务

-L, –log

  • Log 级别
  • 默认: “info”
  • 我们能选择 trace, debug, info, warn, error, 或者 off

–log-file

  • Log 文件
  • 默认: “”
  • 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份

-C, –config

  • 配置文件
  • 默认: “”
  • 如果你指定了配置文件,TiKV 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,TiKV 就会使用命令行参数的配置来覆盖配置文件里面的

–data-dir

  • TiKV 数据存储路径
  • 默认: “/tmp/tikv/store”

–capacity

  • TiKV 存储数据的容量
  • 默认: 0 (无限)
  • PD 需要使用这个值来对整个集群做 balance 操作。(提示:你可以使用 10GB 来替代 10737418240,从而简化参数的传递)

–pd

  • PD 地址列表。
  • 默认: “”
  • TiKV 必须使用这个值连接 PD,才能正常工作。使用逗号来分隔多个 PD 地址,例如: 192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379

TiDB权限管理

1. 用户账户操作

更改密码

set password for 'root'@'%' = 'xxx';

添加用户

create user 'test'@'127.0.0.1' identified by 'xxx';

用户名是大小写敏感的。host则支持模糊匹配,比如:

create user 'test'@'192.168.10.%';

允许test用户从192.168.10子网的任何一个主机登陆。

如果没有指定host,则默认是所有IP均可登陆。如果没有指定密码,默认为空:

create user 'test';

等价于

create user 'test'@'%' identified by '';

删除用户

drop user 'test'@'%';

这个操作会清除用户在mysql.user表里面的记录项,并且清除在授权表里面的相关记录。

忘记root密码

使用一个特殊的启动参数启动TiDB(需要root权限):

sudo ./tidb-server -skip-grant-table=true

这个参数启动,TiDB会跳过权限系统,然后使用root登陆以后修改密码:

mysql -h 127.0.0.1 -P 4000 -u root

2. 权限相关操作

授予权限

授予xxx用户对数据库test的读权限:

grant Select on test.* to 'xxx'@'%';

为test用户授予所有数据库,全部权限:

grant all privileges on *.* to 'xxx'@'%';

如果grant的目标用户不存在,TiDB会自动创建用户。

mysql> select * from mysql.user where user='xxxx';
Empty set (0.00 sec)

mysql> grant all privileges on test.* to 'xxxx'@'%' identified by 'yyyyy';
Query OK, 0 rows affected (0.00 sec)

mysql> select user,host from mysql.user where user='xxxx';
+------|------+
| user | host |
+------|------+
| xxxx | %    |
+------|------+
1 row in set (0.00 sec)
#这个创建和mysql的授权是一模一样的。

例子中xxxx@%就是自动添加进去的用户。

grant对于数据库或者表的授权,不检查数据库或表是否存在。

mysql> select * from test.xxxx;
ERROR 1146 (42S02): Table 'test.xxxx' doesn't exist

mysql> grant all privileges on test.xxxx to xxxx;
Query OK, 0 rows affected (0.00 sec)

mysql> select user,host from mysql.tables_priv where user='xxxx';
+------|------+
| user | host |
+------|------+
| xxxx | %    |
+------|------+
1 row in set (0.00 sec)

grant可以模糊匹配地授予数据库和表

mysql> grant all privileges on `te%`.* to genius;
Query OK, 0 rows affected (0.00 sec)

mysql> select user,host,db from mysql.db where user='genius';
+--------|------|-----+
| user   | host | db  |
+--------|------|-----+
| genius | %    | te% |
+--------|------|-----+
1 row in set (0.00 sec)

这个例子中通过%模糊匹配,所有te开头的数据库,都被授予了权限。

收回权限

revoke语句与grant对应(与mysql一样的):

revoke all privileges on `test`.* from 'genius'@'localhost';

注意revoke收回权限时只做精确匹配,若找不到记录则报错。而grant授予权限时可以使用模糊匹配。

关于模糊匹配和转义,字符串和identifier

mysql> grant all privileges on `te\%`.* to 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec)

这个例子是精确匹配名叫te%的数据库,注意到用了\转义字符。

以单引号包含的,是一个字符串。以反引号包含的,是一个identifier。注意下面区别:

“` mysql> grant all privileges on ‘test’.* to ‘genius’@’localhost’; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ”test’.* to ‘genius’@’localhost” at line 1

mysql> grant all privileges on test.* to ‘genius’@’localhost’; Query OK, 0 rows affected (0.00 sec) “`

如果一些特殊的关键字想做为表名,可以用反引号包含起来。比如:

mysql> create table `select` (id int); Query OK, 0 rows affected (0.27 sec)

查看为用户分配的权限

show grant语句可以查看为用户分配了哪些权限。

show grants for 'root'@'%';

更精确的方式,可以通过直接查看授权表的数据实现。比如想知道,test@%该用户是否拥有对db1.t的Insert权限。

先查看该用户是否拥有全局Insert权限:

select Insert_priv from mysql.user where user='test' and host='%';

如果没有,再查看该用户是否拥有db1数据库级别的Insert权限:

select Insert_priv from mysql.db where user='test' and host='%';

如果仍然没有,则继续判断是否拥有db1.t这张表的Insert权限:

select table_priv from mysql.tables_priv where user='test' and host='%' and db='db1';

3. 权限系统的实现

授权表

有几张系统表是非常特殊的表,权限相关的数据全部存储在这几张表内。

  • mysql.user 用户账户,全局权限
  • mysql.db 数据库级别的权限
  • mysql.tables_priv 表级别的权限
  • mysql.columns_priv 列级别的权限

这几张表包含了数据的生效范围和权限信息。例如,mysql.user表的部分数据:

MySQL [mysql]> select User,Host,Select_priv,Insert_priv from mysql.user limit 1;
+------+------+-------------+-------------+
| User | Host | Select_priv | Insert_priv |
+------+------+-------------+-------------+
| root | %    | Y           | Y           |
+------+------+-------------+-------------+
1 row in set (0.00 sec)

MySQL [mysql]>

这条记录中,Host和User决定了root用户从任意主机(%)发送过来的连接请求可以被接受,而Selectpriv和Insertpriv表示用户拥有全局的Select和Insert权限。mysql.user这张表里面的生效范围是全局的。

mysql.db表里面包含的Host和User决定了用户可以访问哪些数据库,权限列的生效范围是数据库。

理论上,所有权限管理相关的操作,都可以通过直接对授权表的CRUD操作完成。

实现层面其实也只是包装了一层语法糖。例如删除用户会执行:

delete from mysql.user where user='test'; 

但是不推荐用户手动修改授权表。

连接验证

当客户端发送连接请求时,TiDB服务器会对登陆操作进行验证。验证过程先检查mysql.user表,当某条记录的User和Host和连接请求匹配上了,再去验证Password。用户身份基于两部分信息,发起连接的客户端的Host,以及用户名User。如果User不为空,则用户名必须精确匹配。

User+Host可能会匹配user表里面多行,为了处理这种情况,user表的行是排序过的,客户端连接时会依次去匹配,并使用首次匹配到的那一行做权限验证。排序是按Host在前,User在后。

请求验证

连接成功之后,请求验证会检测执行操作是否拥有足够的权限。

对于数据库相关请求(INSERT,UPDATE),先检查mysql.user表里面的用户全局权限,如果权限够,则直接可以访问。如果全局权限不足,则再检查mysql.db表。

user表的权限是全局的,并且不管默认数据库是哪一个。比如user里面有DELETE权限,任何一行,任何的表,任何的数据库。

db表里面,User为空是匹配匿名用户,User里面不能有通配符。Host和Db列里面可以有%和_,可以模式匹配。

user和db读到内存也是排序的。

tables_priv 和 columns_priv 中使用%是类似的,但是在Db, Table_name, Column_name 这些列不能包含%。加载进来时排序也是类似的。

生效时机

TiDB启动时,将一些权限检查的表加载到内存,之后使用缓存的数据来验证权限。系统会周期性的将授权表从数据库同步到缓存,生效则是由同步的周期决定,目前这个值设定的是5分钟。

修改了授权表,如果需要立即生效,可以手动调用: flush privileges;

4.限制和约束

一些使用频率偏低的权限当前版本的实现中还未做检查,比如FILE/USAGE/SHUTDOWN/EXECUTE/PROCESS/INDEX等等,未来会陆续完善。

现阶段对权限的支持还没有做到column级别。

TiKV性能优化

本文档用于描述如何根据机器配置情况来调整 TiKV 的参数,使 TiKV 的性能达到最优。

TiKV 最底层使用的是 RocksDB 做为持久化存储,所以 TiKV 的很多性能相关的参数都是与 RocksDB 相关的。

TiKV 使用了 RocksDB 的 Column Falimies 特性,数据最终存储在 RocksDB 内部的 raftdefaultlockwrite 4 个 CF 内。

raft CF 主要存储的是 raft log,与其对应的参数位于 [rocksdb.raftcf] 项中; default CF 存储的是真正的数据,与其对应的参数位于[rocksdb.defaultcf] 项中; write CF 存储的是数据的版本信息(MVCC)以及索引相关的数据,相关的参数位于 [rocksdb.write] 项中; lock CF 存储的是锁信息,系统使用默认参数。

每个 CF 都有单独的 block-cache,用于缓存数据块,加速 RocksDB 的读取速度,block-cache 的大小通过参数 block-cache-size 控制,block-cache-size 越大,能够缓存的热点数据越多,对读取操作越有利,同时占用的系统内存也会越多。

每个 CF 有各自的 write-buffer,大小通过 write-buffer-size 控制。

参数说明

[server]
# 监听地址
# addr = "127.0.0.1:20160"

# 数据目录
# data-dir = "/tmp/tikv/store"

# 可以给 TiKV 实例打标签,用于副本的调度
# labels = "zone=cn-east-1,host=118"

# 日志级别,可选值为:trace,debug,info,warn,error,off
log-level = "info"

# 建议使用默认值
# notify-capacity = 40960
# messages-per-tick = 4096

# socket 的发送/接收缓冲区大小
# send-buffer-size = "128KB"
# recv-buffer-size = "128KB"

# TiDB 过来的大部分读请求都会发送到 TiKV 的 coprocessor 进行处理,该参数用于设置
# coprocessor 线程的个数,如果业务是读请求比较多,增加 coprocessor 的线程数,但应比系统的
# CPU 核数小。例如:TiKV 所在的机器有 32 core,在重读的场景下甚至可以将该参数设置为 30。在没有
# 设置该参数的情况下,TiKV 会自动将该值设置为 CPU 总核数乘以 0.8。
# end-point-concurrency = 8

[metric]
# 将 metrics 推送给 Prometheus pushgateway 的时间间隔
interval = "15s"
# Prometheus pushgateway 的地址
address = ""
job = "tikv"

[raftstore]
# 默认为 true,表示强制将数据刷到磁盘上。如果是非金融安全级别的业务场景,建议设置成 false,
# 以便获得更高的性能。
sync-log = true

region-max-size = "80MB"
# region 分裂阈值
region-split-size = "64MB"
# 当 region 写入的数据量超过该阈值的时候,TiKV 会检查该 region 是否需要分裂。为了减少检查过程
# 中扫描数据的成本,数据过程中可以将该值设置为32MB,正常运行状态下使用默认值即可。
region-split-check-diff = "8MB"

[pd]
# pd 的地址
# endpoints = "127.0.0.1:2379"

[rocksdb]
# RocksDB 进行后台任务的最大线程数,后台任务包括 compaction 和 flush。具体 RocksDB 为什么需要进行 compaction,
# 请参考 RocksDB 的相关资料。在写流量比较大的时候(例如导数据),建议开启更多的线程,
# 但应小于 CPU 的核数。例如在导数据的时候,32 核 CPU 的机器,可以设置成 28。
# max-background-jobs = 8

# RocksDB 能够打开的最大文件句柄数。
# max-open-files = 40960

# RocksDB MANIFEST 文件的大小限制.
# 更详细的信息请参考:https://github.com/facebook/rocksdb/wiki/MANIFEST
max-manifest-file-size = "20MB"

# RocksDB write-ahead logs 目录。如果机器上有两块盘,可以将 RocksDB 的数据和 WAL 日志放在
# 不同的盘上,提高 TiKV 的性能。
# wal-dir = "/tmp/tikv/store"

# 下面两个参数用于怎样处理 RocksDB 归档 WAL。
# 更多详细信息请参考:https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F
# wal-ttl-seconds = 0
# wal-size-limit = 0

# RocksDB WAL 日志的最大总大小,通常情况下使用默认值就可以了。
# max-total-wal-size = "4GB"

# 可以通过该参数打开或者关闭 RocksDB 的统计信息。
# enable-statistics = true

# 开启 RocksDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。
# compaction-readahead-size = "2MB"

[rocksdb.defaultcf]
# 数据块大小。RocksDB 是按照 block 为单元对数据进行压缩的,同时 block 也是缓存在 block-cache
# 中的最小单元(类似其他数据库的 page 概念)。
block-size = "64KB"
# RocksDB 每一层数据的压缩方式,可选的值为:no,snappy,zlib,bzip2,lz4,lz4hc。
# no:no:lz4:lz4:lz4:lz4:lz4 表示 level0 和 level1 不压缩,level2 到 level6 采用 lz4 压缩算法。
# no 表示没有压缩,lz4 是速度和压缩比较为中庸的压缩算法,zlib 的压缩比很高,对存储空间比较友
# 好,但是压缩速度比较慢,压缩的时候需要占用较多的 CPU 资源。不同的机器需要根据 CPU 以及 IO 资
# 源情况来配置怎样的压缩方式。例如:如果采用的压缩方式为"no:no:lz4:lz4:lz4:lz4:lz4",在大量
# 写入数据的情况下(导数据),发现系统的 IO 压力很大(使用 iostat 发现 %util 持续 100% 或者使
# 用 top 命令发现 iowait 特别多),而 CPU 的资源还比较充裕,这个时候可以考虑将 level0 和
# level1 开启压缩,用 CPU 资源换取 IO 资源。如果采用的压缩方式
# 为"no:no:lz4:lz4:lz4:lz4:lz4",在大量写入数据的情况下,发现系统的 IO 压力不大,但是 CPU
# 资源已经吃光了,top -H 发现有大量的 bg 开头的线程(RocksDB 的 compaction 线程)在运行,这
# 个时候可以考虑用 IO 资源换取 CPU 资源,将压缩方式改成"no:no:no:lz4:lz4:lz4:lz4"。总之,目
# 的是为了最大限度地利用系统的现有资源,使 TiKV 的性能在现有的资源情况下充分发挥。
compression-per-level = "no:no:lz4:lz4:lz4:lz4:lz4"
# RocksDB memtable 的大小。
write-buffer-size = "128MB"
# 最多允许几个 memtable 存在。写入到 RocksDB 的数据首先会记录到 WAL 日志里面,然后会插入到
# memtable 里面,当 memtable 的大小到达了 write-buffer-size 限定的大小的时候,当前的
# memtable 会变成只读的,然后生成一个新的 memtable 接收新的写入。只读的 memtable 会被
# RocksDB 的 flush 线程(max-background-flushes 参数能够控制 flush 线程的最大个数)
# flush 到磁盘,成为 level0 的一个 sst 文件。当 flush 线程忙不过来,导致等待 flush 到磁盘的
# memtable 的数量到达 max-write-buffer-number 限定的个数的时候,RocksDB 会将新的写入
# stall 住,stall 是 RocksDB 的一种流控机制。在导数据的时候可以将 max-write-buffer-number
# 的值设置的更大一点,例如 10。
max-write-buffer-number = 5

# 当 level0 的 sst 文件个数到达 level0-slowdown-writes-trigger 指定的限度的时候,
# RocksDB 会尝试减慢写入的速度。因为 level0 的 sst 太多会导致 RocksDB 的读放大上升。
# level0-slowdown-writes-trigger 和 level0-stop-writes-trigger 是 RocksDB 进行流控的
# 另一个表现。当 level0 的 sst 的文件个数到达 4(默认值),level0 的 sst 文件会和 level1 中
# 有 overlap 的 sst 文件进行 compaction,缓解读放大的问题。
level0-slowdown-writes-trigger = 20
# 当 level0 的 sst 文件个数到达 level0-stop-writes-trigger 指定的限度的时候,RocksDB 会
# stall 住新的写入。
level0-stop-writes-trigger = 36
# 当 level1 的数据量大小达到 max-bytes-for-level-base 限定的值的时候,会触发 level1 的
# sst 和 level2 种有 overlap 的 sst 进行 compaction。
# 黄金定律:max-bytes-for-level-base 的设置的第一参考原则就是保证和 level0 的数据量大致相
# 等,这样能够减少不必要的 compaction。例如压缩方式为"no:no:lz4:lz4:lz4:lz4:lz4",那么
# max-bytes-for-level-base 的值应该是 write-buffer-size 的大小乘以 4,因为 level0 和
# level1 都没有压缩,而且 level0 触发 compaction 的条件是 sst 的个数到达 4(默认值)。在
# level0 和 level1 都采取了压缩的情况下,就需要分析下 RocksDB 的日志,看一个 memtable 的压
# 缩成一个 sst 文件的大小大概是多少,例如 32MB,那么 max-bytes-for-level-base 的建议值就应
# 该是 32MB * 4 = 128MB。
max-bytes-for-level-base = "512MB"
# sst 文件的大小。level0 的 sst 文件的大小受 write-buffer-size 和 level0 采用的压缩算法的
# 影响,target-file-size-base 参数用于控制 level1-level6 单个 sst 文件的大小。
target-file-size-base = "32MB"
# 在不配置该参数的情况下,TiKV 会将该值设置为系统总内存量的 40%。如果需要在单个物理机上部署多个
# TiKV 节点,需要显式配置该参数,否则 TiKV 容易出现 OOM 的问题。
# block-cache-size = "1GB"

[rocksdb.writecf]
# 保持和 rocksdb.defaultcf.compression-per-level 一致。
compression-per-level = "no:no:lz4:lz4:lz4:lz4:lz4"
# 保持和 rocksdb.defaultcf.write-buffer-size 一致。
write-buffer-size = "128MB"
max-write-buffer-number = 5
min-write-buffer-number-to-merge = 1
# 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。
max-bytes-for-level-base = "512MB"
target-file-size-base = "32MB"
# 在不配置该参数的情况下,TiKV 会将该值设置为系统总内存量的 15%。如果需要在单个物理机上部署多个
# TiKV 节点,需要显式配置该参数。版本信息(MVCC)相关的数据以及索引相关的数据都记录在 write 这
# 个 cf 里面,如果业务的场景下单表索引较多,可以将该参数设置的更大一点。
# block-cache-size = "256MB"

[rocksdb.raftcf]
# 保持和 rocksdb.defaultcf.compression-per-level 一致。
compression-per-level = "no:no:lz4:lz4:lz4:lz4:lz4"
# 保持和 rocksdb.defaultcf.write-buffer-size 一致。
write-buffer-size = "128MB"
max-write-buffer-number = 5
min-write-buffer-number-to-merge = 1
# 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。
max-bytes-for-level-base = "512MB"
target-file-size-base = "32MB"
# 通常配置在 256MB 到 2GB 之间,通常情况下使用默认值就可以了,但如果系统资源比较充足可以适当调大点。
block-cache-size = "256MB"

[storage]
# 通常情况下使用默认值就可以了。在导数据的情况下建议将改参数设置为 1024000。
# scheduler-concurrency = 102400
# 该参数控制写入线程的个数,当写入操作比较频繁的时候,需要把该参数调大。使用 top -H -p tikv-pid
# 发现名称为 sched-worker-pool 的线程都特别忙,这个时候就需要将 scheduler-worker-pool-size
# 参数调大,增加写线程的个数。
# scheduler-worker-pool-size = 4

备份、导入、增量、check工具

概述

在数据迁移过程中,会使用到下面四个工具:

  • checker(tidb开发) 检查 schema 能否被TiDB兼容
  • mydumper 从 MySQL导出数据
  • loader(tidb开发) 导入数据到 TiDB
  • syncer 增量同步 MySQL 数据到 TiDB

两种迁移场景

  • 第一种场景:只全量导入历史数据(需要 checker + mydumper + loader )
  • 第二种场景:全量导入历史数据后,通过增量的方式同步新的数据(需要 checker + mydumper + loader + syncer ) 。该场景需要提前开启 binlog 且格式必须为 ROW 。

下载 TiDB 工具集

在迁移之前,我们可以使用 TiDB 的 checker 工具,来预先检查 TiDB 是否能支持需要迁移的 table schema 。如 果 check 某个 table schema 失败,表明 TiDB 当前并不支持,我们不能对该 table 里面的数据进行迁移。 checker 包 含在 TiDB 工具集里面,我们可以直接下载。

下载 tool 压缩包
wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz
wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256
检查文件完整性,返回 ok 则正确
sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256
解开压缩包
tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz

checker 使用

  • 使用 checker 检查 test database 里面所有的 table

./bin/checker -host 127.0.0.1 -port 3306 -user root test

  • 使用 checker 检查 test database 里面某一个 table 这里,假设我们只需要迁移 table t1
./bin/checker -host 127.0.0.1 -port 3306 -user root test t1
2016/10/27 13:13:56 checker.go:48: [info] Checking database test
2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=
,→ utf8
2016/10/27 13:13:56 checker.go:63: [info] Checking table t1
2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ
Check database succ!

mydumper 导出数据

mydumper 是一个更强大的数据迁移工具,具体可以参考 https://github.com/maxbube/mydumper
我们使用 mydumper 从 MySQL 导出数据,然后用 loader 将其导入到 TiDB 里面。

注意:虽然 TiDB 也支持使用 MySQL 官方的 mysqldump 工具来进行数据的迁移工作,但相比于 mydumper / loader,性能会慢很多,大量数据的迁移会花费很多时间,这里我们并不推荐。

从 MySQL 导出数据

我们使用 mydumper 从 MySQL 导出数据,如下:

./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test

上面,我们使用 -B test 表明是对 test 这个 database 操作,然后用 -T t1,t2 表明只导出 t1t2 两张表。

-t 16 表明使用 16 个线程去导出数据。-F 64 是将实际的 table 切分成多大的 chunk,这里就是 64MB 一个 chunk。

--skip-tz-utc 添加这个参数忽略掉 MySQL 与导数据的机器之间时区设置不一致的情况,禁止自动转换。

注意:在阿里云等一些需要 super privilege 的云上面,mydumper 需要加上 --no-locks 参数,否则会提示没有权限操作。

mydumper及myloader(与mydumper一起的,用于mysql) 参数说明:

 mydumper  --help
Usage:
  mydumper [OPTION...] multi-threaded MySQL dumping

Help Options:
  -?, --help                  Show help options

Application Options:
  -B, --database              需要备份的数据库,一个数据库一条命令备份,要不就是备份所有数据库,包括mysql。
  -T, --tables-list           需要备份的表,用逗号分隔。
  -o, --outputdir             备份文件目录
  -s, --statement-size        生成插入语句的字节数,默认1000000,这个参数不能太小,不然会报 Row bigger than statement_size for tools.t_serverinfo
  -r, --rows                  试图用行块来分割表,该参数关闭--chunk-filesize
  -F, --chunk-filesize        行块分割表的文件大小,单位是MB
  -c, --compress              压缩输出文件
  -e, --build-empty-files     即使表没有数据,也产生一个空文件
  -x, --regex                 正则表达式匹配,如'db.table'
  -i, --ignore-engines        忽略的存储引擎,用逗号分隔 
  -m, --no-schemas            不导出表结构
  -d, --no-data               不导出表数据
  -G, --triggers              导出触发器
  -E, --events                导出事件
  -R, --routines              导出存储过程
  -k, --no-locks              不执行共享读锁 警告:这将导致不一致的备份
  --less-locking              减到最小的锁在innodb表上.
  -l, --long-query-guard      设置长查询时间,默认60秒,超过该时间则会报错:There are queries in PROCESSLIST running longer than 60s, aborting dump
  -K, --kill-long-queries kill掉长时间执行的查询,备份报错:Lock wait timeout exceeded; try restarting transaction

  -D, --daemon                启用守护进程模式
  -I, --snapshot-interval     dump快照间隔时间,默认60s,需要在daemon模式下
  -L, --logfile               使用日志文件,默认标准输出到终端
  --tz-utc                    备份的时候允许备份Timestamp,这样会导致不同时区的备份还原会出问题,默认关闭,参数:--skip-tz-utc to disable.
  --skip-tz-utc               
  --use-savepoints            使用保存点记录元数据的锁信息,需要SUPER权限
  --success-on-1146           Not increment error count and Warning instead of Critical in case of table doesn't exist
  --lock-all-tables           锁全表,代替FLUSH TABLE WITH READ LOCK
  -U, --updated-since         Use Update_time to dump only tables updated in the last U days
  --trx-consistency-only      Transactional consistency only
  -h, --host                  The host to connect to
  -u, --user                  Username with privileges to run the dump
  -p, --password              User password
  -P, --port                  TCP/IP port to connect to
  -S, --socket                UNIX domain socket file to use for connection
  -t, --threads               备份执行的线程数,默认4个线程
  -C, --compress-protocol     在mysql连接上使用压缩协议
  -V, --version               Show the program version and exit
  -v, --verbose               更多输出, 0 = silent, 1 = errors, 2 = warnings, 3 = info, default 2

myloader (用于mysql的导入)参数说明:

myloader --help
Usage:
  myloader [OPTION...] multi-threaded MySQL loader

Help Options:
  -?, --help                        Show help options

Application Options:
  -d, --directory                   备份文件所在的目录
  -q, --queries-per-transaction     每个事务的query数量, 默认1000
  -o, --overwrite-tables            如果表存在则先删除,使用该参数,需要备份时候要备份表结构,不然还原会找不到表
  -B, --database                    指定需要还原的数据库
  -s, --source-db                   还原的数据库
  -e, --enable-binlog               启用二进制日志恢复数据
  -h, --host                        The host to connect to
  -u, --user                        Username with privileges to run the dump
  -p, --password                    User password
  -P, --port                        TCP/IP port to connect to
  -S, --socket                      UNIX domain socket file to use for connection
  -t, --threads                     使用的线程数量,默认4
  -C, --compress-protocol           连接上使用压缩协议
  -V, --version                     Show the program version and exit
  -v, --verbose                     更多输出, 0 = silent, 1 = errors, 2 = warnings, 3 = info, default 2

向 TiDB 导入数据 loader

Loader是什么

是由 PingCAP 开发的数据导入工具,可以用于向 TiDB 中导入数据。

Loader 暂不支持 MySQL。

Binary 下载
当数据量比较大的时候,如果用 mysqldump 这样的工具迁移数据会比较慢。我们尝试了 Percona 的 mydumper/myloader 套件,能够多线程导出和导入数据。在使用过程中,mydumper 问题不大,但是 myloader 由于缺乏出错重试、断点续传这样的功能,使用起来很不方便。所以我们开发了 loader,能够读取 mydumper 的输出数据文件,通过 mysql protocol 向 TiDB/MySQL 中导入数据。

Loader有哪些优点

  • 多线程导入
  • 支持表级别的并发导入,分散写入热点
  • 支持对单个大表并发导入,分散写入热点
  • 支持 mydumper 数据格式
  • 出错重试
  • 断点续导
  • 通过 system variable 优化 TiDB 导入数据速度

参数说明

 -L string
      log 级别设置,可以设置为 debug, info, warn, error, fatal (默认为 "info")
  -P int
      TiDB/MySQL 的端口 (默认为 4000)
  -V
      打印 loader 版本
  -c string
      指定配置文件启动 loader 
  -checkpoint-schema string
      checkpoint 数据库名,loader 在运行过程中会不断的更新这个数据库,在中断并恢复后,会通过这个库获取上次运行的进度 (默认为 "tidb_loader")
  -d string
      Directory of the dump to import (default "./")
  -h string
      The host to connect to (default "127.0.0.1")
  -p string
      TiDB/MySQL 账户密码
  -pprof-addr string
      Loader 的 pprof 地址,用于对 Loader 进行性能调试 (默认为 ":10084")
  -skip-unique-check 
      是否跳过 unique index 检查,0 表示不跳过,1 表示跳过(能够提高导入数据的速度),注意只有在向 TiDB 中导入数据时,才需要打开这个选项 (默认为1)
  -t int
      线程数 (默认为 16). 每个线程同一时刻只能操作一个数据文件。
  -u string
      TiDB/MySQL 的用户名 (默认为 "root")

配置文件

除了使用命令行参数外,还可以使用配置文件来配置,配置文件的格式如下:

# Loader log level
log-level = "info"

# Loader log file
log-file = ""

# Directory of the dump to import
dir = "./"

# Loader pprof addr
pprof-addr = ":10084"

# We saved checkpoint data to tidb, which schema name is defined here.
checkpoint-schema = "tidb_loader"

# Number of threads restoring concurrently for worker pool. Each worker restore one file at a time, increase this as TiKV nodes increase
pool-size = 16

# Skip unique index check
skip-unique-check = 0

# An alternative database to restore into
#alternative-db = ""
# Database to restore
#source-db = ""

# DB config
[db]
host = "127.0.0.1"
user = "root"
password = ""
port = 4000

# [[route-rules]]
# pattern-schema = "shard_db_*"
# pattern-table = "shard_table_*"
# target-schema = "shard_db"
# target-table = "shard_table"

使用示例

通过命令行参数:

./bin/loader -d ./test -h 127.0.0.1 -u root -P 4000

或者使用配置文件 “config.toml”:

./bin/loader -c=config.toml

注意事项

如果使用默认的 checkpoint-schema 参数,在导完一个 database 数据库后,请 drop database tidb_loader 后再开始导入下一个 database。
推荐数据库开始导入的时候,明确指定checkpoint-schema = "tidb_loader"参数。

mydumper/loader 全量导入数据最佳实践

为了快速的迁移数据 (特别是数据量巨大的库), 可以参考下面建议

  • 使用 mydumper 导出来的数据文件尽可能的小, 最好不要超过 64M, 可以设置参数 -F 64
  • loader的 -t 参数可以根据 tikv 的实例个数以及负载进行评估调整,例如 3个 tikv 的场景, 此值可以设为 3 *(1 ~ n);当 tikv 负载过高,loader 以及 tidb 日志中出现大量 backoffer.maxSleep 15000ms is exceeded 可以适当调小该值,当 tikv 负载不是太高的时候,可以适当调大该值。

某次导入示例,以及相关的配置

  • mydumper 导出后总数据量 214G,单表 8 列,20 亿行数据
  • 集群拓扑
    • TIKV * 12
    • TIDB * 4
    • PD * 3
  • mydumper -F 设置为 16, loader -t 参数 64

结果:导入时间 11 小时左右,19.4 G/小时

问题总结(微信群)

同时有多个ddl,是怎么执行的

答:实际只有一个唯一的tidb执行ddl,其他tidb会把ddl转发到实际执行ddl的tidb上,ddl的job是串行执行的。

tikv用ansible安装的

启动不了 TiKV,报以下错误:

Error { inner: ErrorInner { kind: Custom, line: None, col: 0, message: "invalid type: string \"\", expected a map", key: ["server", "labels"] } }

从错误上看是配置文件有问题,只需要看message就可以了,从上面可以看出,无效的空格字符类似,key是指配置文件中的[server]及值lables配置有问题。

原因是:ansible文件没有变化,但安装文件(tidb 软件)变成了最新的,所以导致 配置文件有问题,两都文件比较如下:
第一个是报错的文件

[root@node6 data]# diff tikv.toml  tidb/deploy/conf/tikv.toml 
3c3
< #   File size(based on byte): KB, MB, GB, TB, PB (or lowercase)
---
> #   File size(based on byte): KB, MB, GB, TB, PB
8,9c8
< [server]
< labels = ""
---
> # log level: trace, debug, info, warn, error, off.
10a10,14
> # file to store log, write to stderr if it's empty.
> # log-file = ""
> 
> [server]
> labels = {}
13a18,19
> [storage]
> 
16c22
< endpoints = ""
---
> endpoints = []
32c38
< split-region-check-tick-interval = "5s"
---
> split-region-check-tick-interval = "10s"
38c44
< stats-dump-period-sec = 600
---
> stats-dump-period = "10m"
50d55
< [storage]

错误的配置文件(也不能说是错误的,只是它对应的是旧版本的软件)如下:

[root@node6 data]# cat tikv.toml 
# TiKV config template
#  Human-readable big numbers:
#   File size(based on byte): KB, MB, GB, TB, PB (or lowercase)
#    e.g.: 1_048_576 = "1MB"
#   Time(based on ms): ms, s, m, h
#    e.g.: 78_000 = "1.3m"

[server]
labels = ""
log-level = "info"
messages-per-tick = 4096
notify-capacity = 40960

[pd]
# This section will be overwritten by command line parameters
endpoints = ""

[metric]
address = "192.168.7.232:9091"
interval = "2s"
job = "tikv"

[raftstore]
max-peer-down-duration = "5m"
messages-per-tick = 4096
notify-capacity = 40960
pd-heartbeat-tick-interval = "60s"
pd-store-heartbeat-tick-interval = "10s"
region-max-size = "384MB"
region-split-check-diff = "32MB"
region-split-size = "256MB"
split-region-check-tick-interval = "5s"
sync-log = false

[rocksdb]
create-if-missing = true
max-manifest-file-size = "20MB"
stats-dump-period-sec = 600
wal-dir = ""
wal-recovery-mode = 2

[rocksdb.defaultcf]

[rocksdb.lockcf]

[rocksdb.raftcf]

[rocksdb.writecf]

[storage]

正确的配置文件(新版本)

[root@node6 data]# cat tidb/deploy/conf/tikv.toml 
# TiKV config template
#  Human-readable big numbers:
#   File size(based on byte): KB, MB, GB, TB, PB
#    e.g.: 1_048_576 = "1MB"
#   Time(based on ms): ms, s, m, h
#    e.g.: 78_000 = "1.3m"

# log level: trace, debug, info, warn, error, off.
log-level = "info"
# file to store log, write to stderr if it's empty.
# log-file = ""

[server]
labels = {}
messages-per-tick = 4096
notify-capacity = 40960

[storage]

[pd]
# This section will be overwritten by command line parameters
endpoints = []

[metric]
address = "192.168.7.232:9091"
interval = "2s"
job = "tikv"

[raftstore]
max-peer-down-duration = "5m"
messages-per-tick = 4096
notify-capacity = 40960
pd-heartbeat-tick-interval = "60s"
pd-store-heartbeat-tick-interval = "10s"
region-max-size = "384MB"
region-split-check-diff = "32MB"
region-split-size = "256MB"
split-region-check-tick-interval = "10s"
sync-log = false

[rocksdb]
create-if-missing = true
max-manifest-file-size = "20MB"
stats-dump-period = "10m"
wal-dir = ""
wal-recovery-mode = 2

[rocksdb.defaultcf]

[rocksdb.lockcf]

[rocksdb.raftcf]

[rocksdb.writecf]

tidb 程序连接报错

报错内容如下:

backoffer.maxSleep 5000ms is exceeded, errors: get timestamp failed: rpc error: code = Unknown desc = rpc error: code = Unavailable desc = not leader get timestamp failed: rpc error: code = Unknown desc = rpc error: code = Unavailable desc = not leader get timestamp failed: rpc error: code = Unknown desc = rpc error: code = Unavailable desc = not leader

SQLSTATE[HY000] [1105] [try again later]: backoffer.maxSleep 5000ms is exceeded, errors: get timestamp failed: rpc error: code = Unknown desc = rpc error: code = Unavailable desc = not leader get timestamp failed: rpc error: code = Unknown desc = rpc error: code = Unavailable desc = not leader get timestamp failed: rpc error: code = Unknown desc = rpc error: code = Unavailable desc = not leader

原因:从上面报错信息可以看出,是pd-server之间获取不到leader的pd,所以导致通信超时过5s,导致连接失败。从pd的leader节点获取timestamp失败,后面从监控中查看到pd leader节点的磁盘io爆满,所以导致通信失败。

 

docker启动一个集群的命令

#!/bin/bash
#start pd-cluster
#docker network create --subnet 172.18.0.0/16 --driver bridge clc

docker run -d --name pd1 \
  -p 192.168.0.230:22379:2379 \
  --network clc \
  --ip 172.18.0.201 \
  -v /etc/localtime:/etc/localtime:ro \
  -v /data/docker_work/tidb_cluster/data_pd1:/data \
  pingcap/pd:pre-ga \
  --name="pd1" \
  --data-dir="/data/pd1" \
  --client-urls="http://0.0.0.0:2379" \
  --advertise-client-urls="http://172.18.0.201:2379" \
  --peer-urls="http://0.0.0.0:2380" \
  --advertise-peer-urls="http://172.18.0.201:2380" \
  --initial-cluster="pd1=http://172.18.0.201:2380,pd2=http://172.18.0.202:2380,pd3=http://172.18.0.203:2380"

docker run -d --name pd2 \
  -p 192.168.0.230:22389:2379 \
  --network clc \
  --ip 172.18.0.202 \
  -v /etc/localtime:/etc/localtime:ro \
  -v /data/docker_work/tidb_cluster/data_pd2:/data \
  pingcap/pd:pre-ga \
  --name="pd2" \
  --data-dir="/data/pd2" \
  --client-urls="http://0.0.0.0:2379" \
  --advertise-client-urls="http://172.18.0.202:2379" \
  --peer-urls="http://0.0.0.0:2380" \
  --advertise-peer-urls="http://172.18.0.202:2380" \
  --initial-cluster="pd1=http://172.18.0.201:2380,pd2=http://172.18.0.202:2380,pd3=http://172.18.0.203:2380"

docker run -d --name pd3 \
  -p 192.168.0.230:22399:2379 \
  --network clc \
  --ip 172.18.0.203 \
  -v /etc/localtime:/etc/localtime:ro \
  -v /data/docker_work/tidb_cluster/data_pd3:/data \
  pingcap/pd:pre-ga \
  --name="pd3" \
  --data-dir="/data/pd3" \
  --client-urls="http://0.0.0.0:2379" \
  --advertise-client-urls="http://172.18.0.203:2379" \
  --peer-urls="http://0.0.0.0:2380" \
  --advertise-peer-urls="http://172.18.0.203:2380" \
  --initial-cluster="pd1=http://172.18.0.201:2380,pd2=http://172.18.0.202:2380,pd3=http://172.18.0.203:2380"



#start tikv-cluster
docker run -d --name tikv1 \
  -p 192.168.0.230:20160:20160 \
  --network clc \
  --ip 172.18.0.204 \
  --ulimit nofile=1000000:1000000 \
  -v /etc/localtime:/etc/localtime:ro \
  -v /data/docker_work/tidb_cluster/data_tikv1:/data \
  pingcap/tikv:pre-ga \
  --addr="0.0.0.0:20160" \
  --advertise-addr="172.18.0.204:20160" \
  --data-dir="/data/tikv1" \
  --pd="172.18.0.201:2379,172.18.0.202:2379,172.18.0.203:2379"

docker run -d --name tikv2 \
  -p 192.168.0.230:20161:20160 \
  --network clc \
  --ip 172.18.0.205 \
  --ulimit nofile=1000000:1000000 \
  -v /etc/localtime:/etc/localtime:ro \
  -v /data/docker_work/tidb_cluster/data_tikv2:/data \
  pingcap/tikv:pre-ga \
  --addr="0.0.0.0:20160" \
  --advertise-addr="172.18.0.205:20160" \
  --data-dir="/data/tikv2" \
  --pd="172.18.0.201:2379,172.18.0.202:2379,172.18.0.203:2379"

docker run -d --name tikv3 \
  -p 192.168.0.230:20162:20160 \
  --network clc \
  --ip 172.18.0.206 \
  --ulimit nofile=1000000:1000000 \
  -v /etc/localtime:/etc/localtime:ro \
  -v /data/docker_work/tidb_cluster/data_tikv3:/data \
  pingcap/tikv:pre-ga \
  --addr="0.0.0.0:20160" \
  --advertise-addr="172.18.0.206:20160" \
  --data-dir="/data/tikv3" \
  --pd="172.18.0.201:2379,172.18.0.202:2379,172.18.0.203:2379"


#start tidb
docker run -d --name tidb \
  -p 192.168.0.230:4000:4000 \
  -p 192.168.0.230:10080:10080 \
  --network clc \
  --ip 172.18.0.207 \
  -v /etc/localtime:/etc/localtime:ro \
  pingcap/tidb:pre-ga \
  --store=tikv \
  --path="172.18.0.201:2379,172.18.0.202:2379,172.18.0.203:2379"

 

 

原文链接:TiDB介绍,转载请注明来源!

0