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 内部的 raft
、default
、lock
和 write
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
表明只导出 t1
,t2
两张表。
-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介绍,转载请注明来源!