Dashuang Du.
Dashuang Du.

study and practice, years of it.

TiDB 部署及数据同步

2018, May 08    

官方文档

简介

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"

部署任务

  1. 确认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
    
  2. 执行local_prepare.yml playbook,联网下载 TiDB binary 到中控机:

    ansible-playbook local_prepare.yml
    
  3. 初始化系统环境,修改内核参数

    ansible-playbook bootstrap.yml
    
  4. 部署 TiDB 集群软件

    ansible-playbook deploy.yml
    
  5. 启动 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导入了t1t2两张表的一些数据,现在我们希望这两张表的任何更新, 都是实时的同步到 TiDB 上面。

MySQL 开启 binlog

在使用 syncer 之前,我们必须保证:

# 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得到当前binlogpositionsyncer的初始同步位置就是从这个地方开始。

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 |
+----+------+