简介
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整体架构
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 为单位进行调度。
安装与部署
单节点方式快速部署(适用于功能测试,预览)
执行步骤:
# 下载压缩包
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
# 解开压缩包
tar -xzf tidb-latest-linux-amd64.tar.gz
cd tidb-latest-linux-amd64
在获取 TiDB 二进制文件包后,我们可以在单机上面,运行和测试 TiDB 集群,请按如下步骤依次启动 PD,TiKV,TiDB。
注意:以下启动各个应用程序组件实例的时候,请选择后台启动,避免前台失效后程序自动退出。
步骤一,启动 PD
./bin/pd-server --data-dir=pd
--log-file=pd.log步骤二,启动 TiKV
./bin/tikv-server --pd="127.0.0.1:2379"
--data-dir=tikv
--log-file=tikv.log步骤三,启动 TiDB
./bin/tidb-server --store=tikv
--path="127.0.0.1:2379"
--log-file=tidb.log步骤四,使用 MySQL 客户端连接 TiDB:
mysql -h 127.0.0.1 -P 4000 -u root -D test
Ansible 部署集群(强烈推荐)
准备机器
测试部署,下列所有机器均由
Virtual Box
生成的虚拟环境,生产环境中请参考官方文档配置。 注意开启虚拟机的 specific IP,eg:config.vm.network "private_network", ip: "192.168.12.10"
。
部署目标机器若干
建议 4 台及以上,TiKV 至少 3 实例(本教程 3 实例),且与 TiDB、PD 模块不位于同一主机,详见部署建议
推荐安装 CentOS 7.3 及以上版本 Linux 操作系统(本教程使用 ubuntu 16.04),x86_64 架构(amd64), 数据盘请使用 ext4 文件系统,挂载 ext4 文件系统时请添加 nodelalloc 挂载参数
编辑
/etc/fstab
文件,添加nodelalloc
挂载参数:# vi /etc/fstab /dev/nvme0n1 /data1 ext4 defaults,nodelalloc,noatime 0 2
使用以下命令 umount 挂载目录并重新挂载:
# umount /data1 # mount -a
通过以下命令确认是否生效:
# mount -t ext4 /dev/nvme0n1 on /data1 type ext4 (rw,noatime,nodelalloc,data=ordered)
机器之间内网互通,防火墙如 iptables 等请在部署时关闭
机器的时间、时区设置一致,开启 NTP 服务且在正常同步时间
注: Ubuntu 系统请安装 ntpstat 软件包
$ ntpstat unsynchronised # NTP 服务未正常同步 $ ntpstat Unable to talk to NTP daemon. Is it running? # NTP 服务未正常运行 sudo systemctl status ntp.service # 查看 ntp 服务运行状态
创建 tidb 普通用户 (本教程使用 vagrant 用户)作为程序运行用户,tidb 用户可以免密码 sudo 到 root 用户
# useradd tidb # passwd tidb # visudo tidb ALL=(ALL) NOPASSWD: ALL
本教程中
vagrant
用户默认免密 sudo 到 root 用户
部署中控机器一台
中控机可以是部署目标机器中的某一台。
推荐安装 CentOS 7.3 及以上版本 Linux 操作系统(默认包含 Python 2.7,本教程使用 ubuntu 16.04)。
该机器需开放外网访问,用于下载 TiDB 及相关软件安装包。
配置 ssh authorized_key 互信,在中控机上可以使用 tidb 用户(本教程使用 vagrant 用户)免密码 ssh 登录到部署目标机器
# vagrant 用户 $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: SHA256:eIBykszR1KyECA/h0d7PRKz4fhAeli7IrVphhte7/So tidb@172.16.10.49 The key's randomart image is: +---[RSA 2048]----+ |=+o+.o. | |o=o+o.oo | | .O.=.= | | . B.B + | |o B * B S | | * + * + | | o + . | | o E+ . | |o ..+o. | +----[SHA256]-----+ sudo cat ~/.ssh/id_rsa.pub authorized_keys # 依次执行以下命令,将 192.168.12.10 替换成目标机器的ip,按提示输入部署目标机器 vagrant 用户密码, # 执行成功后即创建好 ssh 互信,其他机器同理。 ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.12.10 # 验证 ssh 互信 ssh 192.168.12.10 # 不需要输入密码并登录成功
在中控机上下载 TiDB-Ansible
以 vagrant
用户登录中控机并进入 /home/vagrant
目录,使用以下命令从 Github TiDB-Ansible 项目 上下载 TiDB-Ansible 相应版本, 默认的文件夹名称为 tidb-ansible
,以下为各版本下载示例,版本选择可以咨询官方。
# 下载 2.0 GA 版本:
git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git
# 下载 master 版本: git clone https://github.com/pingcap/tidb-ansible.git
本教程为master
版本
在中控机上安装 Ansible 及其依赖
$ sudo apt-get install python-pip curl
$ cd tidb-ansible $ sudo pip install -r ./requirements.txt
pip install
时可能会报Python locale error: unsupported locale setting
,执行下列命令:
export LC_ALL="en_US.UTF-8"
export LC_CTYPE="en_US.UTF-8"
sudo dpkg-reconfigure locales
分配机器资源,编辑 inventory.ini 文件
sudo vim ~/tidb-ansible/inventory.ini
配置如下:(更换ip为你的目标机器ip,192.168.12.22为中控机器ip,其他为目标机器ip)
## TiDB Cluster Part
[tidb_servers]
192.168.12.22
[tikv_servers]
192.168.12.10
192.168.12.2
192.168.12.3
[pd_servers]
192.168.12.22
[spark_master]
[spark_slaves]
## Monitoring Part
# prometheus and pushgateway servers
[monitoring_servers]
192.168.12.22
[grafana_servers]
192.168.12.22
# node_exporter and blackbox_exporter servers
[monitored_servers]
192.168.12.22
192.168.12.10
192.168.12.2
192.168.12.3
[alertmanager_servers]
## Binlog Part [pump_servers:children] tidb_servers ## Group variables [pd_servers:vars] # location_labels = ["zone","rack","host"] ## Global variables [all:vars] deploy_dir = /home/vagrant/deploy ## Connection # ssh via normal user ansible_user = vagrant cluster_name = test-cluster tidb_version = latest # process supervision, [systemd, supervise] process_supervision = systemd # timezone of deployment region timezone = Asia/Shanghai set_timezone = True enable_firewalld = False # check NTP service enable_ntpd = True set_hostname = False ## binlog trigger enable_binlog = False # zookeeper address of kafka cluster, example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" zookeeper_addrs = "" # store slow query log into seperate file enable_slow_query_log = False # enable TLS authentication in the TiDB cluster enable_tls = False # KV mode deploy_without_tidb = False # Optional: Set if you already have a alertmanager server. # Format: alertmanager_host:alertmanager_port alertmanager_target = "" grafana_admin_user = "admin" grafana_admin_password = "admin"
部署任务
确认
tidb-ansible/inventory.ini
文件中ansible_user = vagrant
,本例使用vagrant
用户作为服务运行用户,配置如下:## Connection # ssh via normal user ansible_user = vagrant
执行以下命令如果所有 server 返回 vagrant 表示 ssh 互信配置成功。
ansible -i inventory.ini all -m shell -a 'whoami'
执行以下命令如果所有 server 返回 root 表示 vagrant 用户 sudo 免密码配置成功。
ansible -i inventory.ini all -m shell -a 'whoami' -b
执行
local_prepare.yml
playbook,联网下载 TiDB binary 到中控机:ansible-playbook local_prepare.yml
初始化系统环境,修改内核参数
ansible-playbook bootstrap.yml
部署 TiDB 集群软件
ansible-playbook deploy.yml
启动 TiDB 集群
ansible-playbook start.yml # 返回下列字段时,表示启动成功 Congrats! All goes well. :-)
测试集群
测试连接 TiDB 集群,推荐在 TiDB 前配置负载均衡来对外统一提供 SQL 接口。
使用 MySQL 客户端连接测试,TCP 4000 端口是 TiDB 服务默认端口。
mysql -u root -h 192.168.12.22 -P 4000 # eg vagrant@vagrant [09:48:48 PM] [~/tidb-ansible] [master *] -> % mysql -h192.168.12.22 -uroot -P 4000 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.7.10-TiDB-v2.0.0-rc.4-147-g00d4831 MySQL Community Server (Apache License 2.0) Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
通过浏览器访问监控平台。
地址:
http://192.168.12.22:3000
默认帐号密码是:admin/admin
Docker Compose 部署方案
待补充…
数据同步
由于 TiDB 本身兼容绝大多数的 MySQL 语法,所以对于绝大多数业务来说,最安全的切换数据库方式就是将 TiDB 作为现有数据库的从库接在主 MySQL 库的后方, 这样对业务方实现完全没有侵入性下使用 TiDB 对现有的业务进行备份,应对未来数据量或者并发量增长带来的单点故障风险,如需上线 TiDB, 也只需要简单的将业务的主 MySQL 地址指向 TiDB 即可。
下面我们详细介绍了如何将 MySQL 的数据迁移到 TiDB,并将 TiDB 作为 MySQL 的 Slave 进行数据同步。
这里我们假定 MySQL 以及 TiDB 服务信息如下:
+------------------+-----------------+----------------------------------------+
| Name | Address | Port | User | Password |
+------------------+-----------------+----------------------------------------+
| MySQL | 127.0.0.1 | 3306 | root | | | TiDB | 192.168.12.22 | 4000 | vagrant | | +------------------+-------------+--------+-----------+-----------------------+
下载 TiDB 企业版工具集 (Linux)
注:普通工具集中,无
syncer
,mydumper
等工具
# 下载 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
cd tidb-enterprise-tools-latest-linux-amd64
使用 checker 进行 Schema 检查
在迁移之前,我们可以使用 TiDB 的 checker 工具,checker 是我们开发的一个小工具,用于检测目标 MySQL 库中的表的表结构是否支持无缝的迁移到 TiDB, TiDB 支持绝大多数的 MySQL 常用的原生数据类型,所以大多数情况 checker 的返回应该是 ok。如果 check 某个 table schema 失败,表明 TiDB 当前并不支持, 我们不能对该 table 里面的数据进行迁移。checker 包含在 TiDB 工具集里面。
./bin/checker -host 127.0.0.1 -port 3306 -user root -password password db_name
2016/10/27 13:11:49 checker.go:48: [info] Checking database db_name
2016/10/27 13:11:49 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/db_name?charset=utf8
2016/10/27 13:11:49 checker.go:63: [info] Checking table t1
2016/10/27 13:11:49 checker.go:69: [info] Check table t1 succ
2016/10/27 13:11:49 checker.go:63: [info] Checking table t2 2016/10/27 13:11:49 checker.go:69: [info] Check table t2 succ
使用 mydumper/myloader 全量导入数据
我们使用 mydumper 从 MySQL 导出数据,然后用 myloader 将其导入到 TiDB 里面。
注意,虽然我们也支持使用 MySQL 官方的 mysqldump 工具来进行数据的迁移工作,但相比于 mydumper/myloader,性能会慢很多, 对于大量数据的迁移会花费很多时间,这里我们并不推荐。
mydumper/myloader
是一个更强大的数据迁移工具,具体可以参考https://github.com/maxbube/mydumper。
# 下载 mydumper 压缩包
wget http://download.pingcap.org/mydumper-linux-amd64.tar.gz
wget http://download.pingcap.org/mydumper-linux-amd64.sha256
# 检查文件完整性,返回 ok 则正确
sha256sum -c mydumper-linux-amd64.sha256
# 解开压缩包
tar -xzf mydumper-linux-amd64.tar.gz
cd mydumper-linux-amd64
从 MySQL 导出数据
我们使用 mydumper 从 MySQL 导出数据,如下:
./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 128 -B test -T t1,t2 -o ./guopisql
上面,我们使用-B test
表明是对test
这个database
操作,然后用-T t1,t2
表明只导出t1,t2
两张表。 -t 16
表明使用16
个线程去导出数据。-F 128
是将实际的table
切分成多大的chunk
,这里就是128MB
一个chunk
。
注意:在阿里云一些需要super privilege
的云上面,mydumper
需要加上--no-locks
参数,否则会提示没有权限操作。
给 TiDB 导入数据
我们使用 myloader 将之前导出的数据导入到 TiDB。
./bin/myloader -h 192.168.12.22 -P 4000 -u vagrant -p password -t 16 -q 100 -d ./guopisql
这里-q 100
表明每个事务包含多少个query
,默认是1000
,我们这里使用100
就可以了(数据多的话,可以加大)。
导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看:
vagrant@vagrant [09:48:48 PM] [~/tidb-ansible] [master *]
-> % mysql -h192.168.12.22 -uroot -P 4000
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| t1 |
| t2 |
+----------------+
使用 syncer 增量导入数据实现数据和 MySQL 实时同步
上面我们介绍了如何使用mydumper/myloader
将 MySQL 的数据全量导入到 TiDB,但如果后续 MySQL 的数据有更新,我们仍然希望快速导入, 使用全量的方式就不合适了。
TiDB 提供syncer
工具能方便的将 MySQL 的数据增量的导入到 TiDB 里面。
syncer
也属于 TiDB 企业工具集。
假设我们之前已经使用mydumper/myloader
导入了t1
和t2
两张表的一些数据,现在我们希望这两张表的任何更新, 都是实时的同步到 TiDB 上面。
MySQL 开启 binlog
在使用 syncer 之前,我们必须保证:
MySQL 开启 binlog 功能,参考Setting the Replication Master Configuration
Binlog 格式必须使用
row format
,这也是 MySQL 5.7 之后推荐的binlog
格式sudo vi /etc/mysql/my.cnf
[mysqld] log-bin=mysql-bin server-id=1 binlog-format=ROW
重启mysql
服务
sudo service mysql restart
获取同步 position
我们通过show master status
得到当前binlog
的position
,syncer
的初始同步位置就是从这个地方开始。
show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000001 | 154 | | | | +------------------+----------+--------------+------------------+-------------------+
我们将position
相关的信息保存到一个syncer.meta
文件里面,用于syncer
的同步:
# vim syncer.meta
binlog-name = "mysql-bin.000001"
binlog-pos = 154
启动 syncer
syncer
的配置文件config.toml
:
log-level = "info"
server-id = 1
# meta 文件地址 meta = "./syncer.meta" worker-count = 1 batch = 1 pprof-addr = ":10081" [from] host = "127.0.0.1" user = "root" password = "your password" port = 3306 [to] host = "192.168.12.22" user = "root" password = "" port = 4000
启动syncer
# 后台运行
vagrant@vagrant [10:10:07 PM] [~/tidb-enterprise-tools-latest-linux-amd64]
-> % nohup ./bin/syncer -config config.toml &
[1] 4193
syncer
每隔30s
会输出当前的同步统计,如下:
# cat nohub.out
2018/05/08 15:04:25 syncer.go:821: [info] [syncer]total events = 2, total tps = 0, recent tps = 0, master-binlog = (mysql-bin.000001, 574), master-binlog-gtid=, syncer-binlog = (mysql-bin.000001, 574), syncer-binlog-gtid =
2018/05/08 15:04:55 syncer.go:821: [info] [syncer]total events = 2, total tps = 0, recent tps = 0, master-binlog = (mysql-bin.000001, 574), master-binlog-gtid=, syncer-binlog = (mysql-bin.000001, 574), syncer-binlog-gtid =
2018/05/08 15:05:25 syncer.go:821: [info] [syncer]total events = 2, total tps = 0, recent tps = 0, master-binlog = (mysql-bin.000001, 574), master-binlog-gtid=, syncer-binlog = (mysql-bin.000001, 574), syncer-binlog-gtid =
2018/05/08 15:05:55 syncer.go:821: [info] [syncer]total events = 2, total tps = 0, recent tps = 0, master-binlog = (mysql-bin.000001, 574), master-binlog-gtid=, syncer-binlog = (mysql-bin.000001, 574), syncer-binlog-gtid =
在 MySQL 插入新的数据
INSERT INTO t1 VALUES (4, 4), (5, 5);
登录到 TiDB 查看:
mysql -h127.0.0.1 -P4000 -uroot -p
mysql> select * from t1;
+----+------+
| id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+