TiDB 与 ProxySQL 集成

本文以 CentOS 7 为例,简单介绍 TiDBProxySQL 的集成方法。如果你有其他系统的集成需求,可参考快速体验使用 Docker 及 Docker Compose 部署测试集成环境。你也可以参考以下链接,以获得更多信息:

1. 启动 TiDB

测试环境

1. 下载 TiDB 源码,进入 tidb-server 目录后,使用 go build 进行编译。 shell git clone git@github.com:pingcap/tidb.git cd tidb/tidb-server go build 2. 使用配置文件 tidb-config.toml 来启动 TiDB,命令如下所示: shell ${TIDB_SERVER_PATH} -config ./tidb-config.toml -store unistore -path "" -lease 0s > ${LOCAL_TIDB_LOG} 2>&1 & > 注意: > > - 此处使用 unistore 作为存储引擎,这是 TiDB 的测试存储引擎,请仅在测试时使用它。 > - TIDB_SERVER_PATH:上一步中使用 go build 编译的二进制文件位置,如你在 /usr/local 下进行上一步操作,那么此处的 TIDB_SERVER_PATH 应为 /usr/local/tidb/tidb-server/tidb-server。 > - LOCAL_TIDB_LOG:输出 TiDB 日志的位置。
TiUP 在 TiDB 中承担着包管理器的角色,管理着 TiDB 生态下众多的组件,如 TiDB、PD、TiKV 等。 1. 安装 TiUP shell curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh 2. 启动测试环境 TiDB shell tiup playground

正式环境

在需要托管 TiDB 服务的前提下(如无法自行运维、需要云原生环境等),建议直接使用 TiDB Cloud。你可以参考 TiDB Cloud 的 Create a TiDB Cluster 在 TiDB Cloud 中部署正式环境下的 TiDB。
正式环境相对测试环境会复杂许多,建议参考使用 TiUP 部署 TiDB 集群并根据硬件条件部署。

2. 启动 ProxySQL

yum 安装

  1. 添加 RPM 仓库:

    1. cat > /etc/yum.repos.d/proxysql.repo << EOF
    2. [proxysql]
    3. name=ProxySQL YUM repository
    4. baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/centos/\$releasever
    5. gpgcheck=1
    6. gpgkey=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/repo_pub_key
    7. EOF
  2. 安装:

    1. yum install proxysql
  3. 启动:

    1. systemctl start proxysql

其他安装方式

参考 ProxySQL 的 Github 页面ProxySQL 官方文档进行安装。

3. 配置 ProxySQL

需要将 ProxySQL 内的配置指向 TiDB,以此将 ProxySQL 作为 TiDB 的代理。下面列举必需的配置项,其余配置项可参考 ProxySQL 官方文档

ProxySQL 配置简介

ProxySQL 使用一个单独的端口进行配置管理,另一个端口进行代理。其中,配置管理的入口称为 ProxySQL Admin interface,代理的入口称为 ProxySQL MySQL Interface

  • ProxySQL Admin interface:可以使用具有 admin 权限的用户连接到管理界面,以读取和写入配置,或者使用具有 stats 权限的用户,只能读取某些统计数据(不读取或写入配置)。默认凭证是 admin:adminstats:stats,但出于安全考虑,可以使用默认凭证进行本地连接。要远程连接,需要配置一个新的用户,通常它被命名为 radmin
  • ProxySQL MySQL Interface:用于代理,将 SQL 转发到配置的服务中。

proxysql config flow

ProxySQL 有三层配置:runtimememorydisk。你仅能更改 memory 层的配置。在更改配置后,可以使用 LOAD xxx TO runtime 来生效这个配置,也可以使用 SAVE xxx TO DISK 落盘,防止配置丢失。

proxysql config layer

配置 TiDB 后端

在 ProxySQL 中添加 TiDB 后端,此处如果有多个 TiDB 后端,可以添加多条。请在 ProxySQL Admin interface 进行此操作:

  1. INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (0, '127.0.0.1', 4000);
  2. LOAD mysql servers TO runtime;
  3. SAVE mysql servers TO DISK;

字段解释:

  • hostgroup_id:ProxySQL 是以 hostgroup 为单位管理后端服务的,可以将需要负载均衡的几个服务配置为同一个 hostgroup,这样 ProxySQL 将均匀地分发 SQL 到这些服务上。而在需要区分不同后端服务时(如读写分离场景等),可将其配置为不同的 hostgroup,以此配置不同的代理条件。
  • hostname:后端服务的 IP 或域名。
  • port:后端服务的端口。

配置 Proxy 登录账号

在 ProxySQL 中添加 TiDB 后端的登录账号。ProxySQL 将允许此账号来登录 ProxySQL MySQL Interface,而且 ProxySQL 将以此创建与 TiDB 之间的连接,因此,请确保此账号在 TiDB 中拥有相应权限。请在 ProxySQL Admin interface 进行此操作:

  1. INSERT INTO mysql_users(username, password, active, default_hostgroup, transaction_persistent) VALUES ('root', '', 1, 0, 1);
  2. LOAD mysql users TO runtime;
  3. SAVE mysql users TO DISK;

字段解释:

  • username:用户名。
  • password:密码。
  • active:是否生效。1 为生效,0 为不生效,仅 active = 1 的用户可登录。
  • default_hostgroup:此账号默认使用的 hostgroup,SQL 将被发送至此 hostgroup 中,除非查询规则将流量发送到不同的 hostgroup。
  • transaction_persistent:值为 1 时,表示事务持久化,即:当该用户在连接中开启了一个事务后,那么在事务提交或回滚之前,所有的语句都路由到同一个 hostgroup 中,避免语句分散到不同 hostgroup。

配置文件配置

除了使用 ProxySQL Admin interface 配置,也可以使用配置文件进行配置。ProxySQL 文档中,配置文件仅应该被视为是一种辅助初始化的方式,而并非主要配置的手段。配置文件仅在 SQLite 数据库未被创建时读取,后续将不会继续读取配置文件。因此,使用配置文件配置时,你应进行 SQLite 数据库的删除,这将丢失你在 ProxySQL Admin interface 中对配置进行的更改:

  1. rm /var/lib/proxysql/proxysql.db

另外,也可以运行 LOAD xxx FROM CONFIG,用配置文件中的配置覆盖当前内存中的配置。

配置文件的位置为 /etc/proxysql.cnf,我们将上方的必需配置转换为配置文件方式,仅更改 mysql_serversmysql_users 这两个配置节点,其余配置可自行查看 /etc/proxysql.cnf

  1. mysql_servers =
  2. (
  3. {
  4. address="127.0.0.1"
  5. port=4000
  6. hostgroup=0
  7. max_connections=2000
  8. }
  9. )
  10. mysql_users:
  11. (
  12. {
  13. username = "root"
  14. password = ""
  15. default_hostgroup = 0
  16. max_connections = 1000
  17. default_schema = "test"
  18. active = 1
  19. transaction_persistent = 1
  20. }
  21. )

随后使用 systemctl restart proxysql 进行服务重启后即可生效,配置生效后将自动创建 SQLite 数据库,后续将不会再次读取配置文件。

其余配置项

仅以上配置为必需配置项,其余配置项并非必需。你可在 ProxySQL Global Variables 中获取全部配置项的名称及作用。

4. 快速体验

在测试环境中,你可以使用 Docker 及 Docker Compose 快速进行集成后的环境体验,请确认 40006033 端口未被占用,然后执行如下命令:

  1. git clone https://github.com/Icemap/tidb-proxysql-integration-test.git
  2. cd tidb-proxysql-integration-test && docker-compose pull # Get the latest Docker images
  3. sudo setenforce 0 # Only on Linux
  4. docker-compose up -d

警告:

请勿在生产环境使用此快速体验方式创建集成环境。

这样就已经完成了一个集成了 TiDB 与 ProxySQL 环境的启动,这将启动两个容器。你可以使用用户名为 root,密码为空的账号,登录到本机的 6033 端口 (ProxySQL)。容器具体配置可见 docker-compose.yaml,ProxySQL 具体配置可见 proxysql-docker.cnf

运行如下命令:

  1. mysql -u root -h 127.0.0.1 -P 6033 -e "SELECT VERSION()"

运行结果:

  1. +--------------------+
  2. | VERSION() |
  3. +--------------------+
  4. | 5.7.25-TiDB-v6.1.2 |
  5. +--------------------+

5. 配置示例

配置示例的前提条件:

  • Docker
  • Docker Compose
  • MySQL Client

下载示例源码并进入目录:

  1. git clone https://github.com/Icemap/tidb-proxysql-integration-test.git
  2. cd tidb-proxysql-integration-test

下面的示例均以 tidb-proxysql-integration-test 目录做为根目录。

使用 Admin Interface 配置负载均衡

进入本示例目录:

  1. cd example/proxy-rule-admin-interface

脚本运行

ProxySQL Admin Interface 为配置入口,配置负载均衡场景为例。可使用以下命令运行脚本:

  1. ./test-load-balance.sh

逐步运行

  1. 通过 Docker Compose 启动三个 TiDB 容器实例,容器内部端口均为 4000,映射宿主机端口为 400140024003。TiDB 容器实例启动后,再启动一个 ProxySQL 实例,容器内部 ProxySQL MySQL Interface 端口为 6033,映射宿主机端口为 6034。不暴露 ProxySQL Admin Interface 端口,因为其仅可在本地(即容器内)登录 ProxySQL Admin Interface。此流程被写在 docker-compose.yaml 中。

    1. docker-compose up -d
  2. 在 3 个 TiDB 实例内,创建相同的表结构,但写入不同的数据:'tidb-0''tidb-1''tidb-2',以便分辨不同的数据库实例:

    1. mysql -u root -h 127.0.0.1 -P 4001 << EOF
    2. DROP TABLE IF EXISTS test.test;
    3. CREATE TABLE test.test (db VARCHAR(255));
    4. INSERT INTO test.test (db) VALUES ('tidb-0');
    5. EOF
    6. mysql -u root -h 127.0.0.1 -P 4002 << EOF
    7. DROP TABLE IF EXISTS test.test;
    8. CREATE TABLE test.test (db VARCHAR(255));
    9. INSERT INTO test.test (db) VALUES ('tidb-1');
    10. EOF
    11. mysql -u root -h 127.0.0.1 -P 4003 << EOF
    12. DROP TABLE IF EXISTS test.test;
    13. CREATE TABLE test.test (db VARCHAR(255));
    14. INSERT INTO test.test (db) VALUES ('tidb-2');
    15. EOF
  3. 使用 docker-compose exec 命令,在 ProxySQL Admin Interface 中运行事先准备好的配置 ProxySQL 的 SQL 文件

    1. docker-compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql"

    此 SQL 文件将会运行:

    1. 添加 3 个 TiDB 后端的地址,并且 hostgroup_id 均为 0
    2. 令 TiDB 后端配置生效,并落盘保存。
    3. 添加用户 root,密码为空,default_hostgroup0,对应上方的 TiDB 后端 hostgroup_id
    4. 生效用户配置,并落盘保存。
  4. 使用 root 用户登录 ProxySQL MySQL Interface,连续查询 5 次数据,预期结果将有 'tidb-0''tidb-1''tidb-2' 三种不同的返回。

    1. mysql -u root -h 127.0.0.1 -P 6034 -t << EOF
    2. SELECT * FROM test.test;
    3. SELECT * FROM test.test;
    4. SELECT * FROM test.test;
    5. SELECT * FROM test.test;
    6. SELECT * FROM test.test;
    7. EOF
  5. 停止并清除 Docker Compose 启动的容器、网络拓扑等资源。

    1. docker-compose down

预期输出

因为负载均衡的原因,预期输出将有 'tidb-0''tidb-1''tidb-2' 三种不同的返回。但具体顺序未知。其中一种预期输出为:

  1. # ./test-load-balance.sh
  2. Creating network "load-balance-admin-interface_default" with the default driver
  3. Creating load-balance-admin-interface_tidb-1_1 ... done
  4. Creating load-balance-admin-interface_tidb-2_1 ... done
  5. Creating load-balance-admin-interface_tidb-0_1 ... done
  6. Creating load-balance-admin-interface_proxysql_1 ... done
  7. +--------+
  8. | db |
  9. +--------+
  10. | tidb-2 |
  11. +--------+
  12. +--------+
  13. | db |
  14. +--------+
  15. | tidb-0 |
  16. +--------+
  17. +--------+
  18. | db |
  19. +--------+
  20. | tidb-1 |
  21. +--------+
  22. +--------+
  23. | db |
  24. +--------+
  25. | tidb-1 |
  26. +--------+
  27. +--------+
  28. | db |
  29. +--------+
  30. | tidb-1 |
  31. +--------+
  32. Stopping load-balance-admin-interface_proxysql_1 ... done
  33. Stopping load-balance-admin-interface_tidb-0_1 ... done
  34. Stopping load-balance-admin-interface_tidb-2_1 ... done
  35. Stopping load-balance-admin-interface_tidb-1_1 ... done
  36. Removing load-balance-admin-interface_proxysql_1 ... done
  37. Removing load-balance-admin-interface_tidb-0_1 ... done
  38. Removing load-balance-admin-interface_tidb-2_1 ... done
  39. Removing load-balance-admin-interface_tidb-1_1 ... done
  40. Removing network load-balance-admin-interface_default

使用 Admin Interface 配置用户分离

进入本示例目录:

  1. cd example/proxy-rule-admin-interface

脚本运行

ProxySQL Admin Interface 为配置入口,配置负载均衡配置用户分离场景为例,不同用户将使用不同的 TiDB 后端。可使用以下命令运行脚本:

  1. ./test-user-split.sh

逐步运行

  1. 通过 Docker Compose 启动两个 TiDB 容器实例,容器内部端口均为 4000,映射宿主机端口为 40014002。TiDB 实例启动后,再启动一个 ProxySQL 实例,容器内部 ProxySQL MySQL Interface 端口为 6033,映射宿主机端口为 6034。不暴露 ProxySQL Admin Interface 端口,因为其仅可在本地(即容器内)登录 ProxySQL Admin Interface。此流程被写在 docker-compose.yaml 中。

    1. docker-compose up -d
  2. 在 2 个 TiDB 实例内,创建相同的表结构,但写入不同的数据'tidb-0''tidb-1',以便分辨不同的数据库实例:

    1. mysql -u root -h 127.0.0.1 -P 4001 << EOF
    2. DROP TABLE IF EXISTS test.test;
    3. CREATE TABLE test.test (db VARCHAR(255));
    4. INSERT INTO test.test (db) VALUES ('tidb-0');
    5. EOF
    6. mysql -u root -h 127.0.0.1 -P 4002 << EOF
    7. DROP TABLE IF EXISTS test.test;
    8. CREATE TABLE test.test (db VARCHAR(255));
    9. INSERT INTO test.test (db) VALUES ('tidb-1');
    10. EOF
  3. 为 ProxySQL 在 tidb-1 实例中新建一个用户:

    1. mysql -u root -h 127.0.0.1 -P 4002 << EOF
    2. CREATE USER 'root1' IDENTIFIED BY '';
    3. GRANT ALL PRIVILEGES ON *.* TO 'root1'@'%';
    4. FLUSH PRIVILEGES;
    5. EOF
  4. 使用 docker-compose exec 命令,在 ProxySQL Admin Interface 中运行事先准备好的配置 ProxySQL 的 SQL 文件

    1. docker-compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql"

    此 SQL 文件将会运行:

    1. 添加 2 个 TiDB 后端的地址,其中,tidb-0hostgroup_id0tidb-1hostgroup_id1
    2. 生效 TiDB 后端配置,并落盘保存。
    3. 添加用户 root,密码为空,default_hostgroup0,即默认将路由至 tidb-0
    4. 添加用户 root1,密码为空,default_hostgroup1,即默认将路由至 tidb-1
    5. 生效用户配置,并落盘保存。
  5. 分别使用 root 用户及 root1 用户登录 ProxySQL MySQL Interface,预期结果将为 'tidb-0''tidb-1'

    1. mysql -u root -h 127.0.0.1 -P 6034 -e "SELECT * FROM test.test;"
    2. mysql -u root1 -h 127.0.0.1 -P 6034 -e "SELECT * FROM test.test;"
  6. 停止并清除 Docker Compose 启动的容器、网络拓扑等资源。

    1. docker-compose down

预期输出

  1. # ./test-user-split.sh
  2. Creating network "user-split-admin-interface_default" with the default driver
  3. Creating user-split-admin-interface_tidb-1_1 ... done
  4. Creating user-split-admin-interface_tidb-0_1 ... done
  5. Creating user-split-admin-interface_proxysql_1 ... done
  6. +--------+
  7. | db |
  8. +--------+
  9. | tidb-0 |
  10. +--------+
  11. +--------+
  12. | db |
  13. +--------+
  14. | tidb-1 |
  15. +--------+
  16. Stopping user-split-admin-interface_proxysql_1 ... done
  17. Stopping user-split-admin-interface_tidb-0_1 ... done
  18. Stopping user-split-admin-interface_tidb-1_1 ... done
  19. Removing user-split-admin-interface_proxysql_1 ... done
  20. Removing user-split-admin-interface_tidb-0_1 ... done
  21. Removing user-split-admin-interface_tidb-1_1 ... done
  22. Removing network user-split-admin-interface_default

使用 Admin Interface 配置代理规则

进入本示例目录:

  1. cd example/proxy-rule-admin-interface

脚本运行

ProxySQL Admin Interface 为配置入口,代理规则场景中,常见的读写分离配置为例,将使用规则匹配将要运行的 SQL,从而将读、写 SQL 转发至不同的 TiDB 后端(若均未匹配,则使用用户的 default_hostgroup)。可使用以下命令运行脚本:

  1. ./proxy-rule-split.sh

逐步运行

  1. 通过 Docker Compose 启动两个 TiDB 容器实例,容器内部端口均为 4000,映射宿主机端口为 40014002。TiDB 实例启动后,再启动一个 ProxySQL 实例,容器内部 ProxySQL MySQL Interface 端口为 6033,映射宿主机端口为 6034。不暴露 ProxySQL Admin Interface 端口,因为其仅可在本地(即容器内)登录 ProxySQL Admin Interface。此流程被写在 docker-compose.yaml 中。

    1. docker-compose up -d
  2. 在 2 个 TiDB 实例内,创建相同的表结构,但写入不同的数据 'tidb-0''tidb-1',以便分辨不同的数据库实例。此处展示向其中一个 TiDB 实例写入数据的命令,另一实例同理:

    1. mysql -u root -h 127.0.0.1 -P 4001 << EOF
    2. DROP TABLE IF EXISTS test.test;
    3. CREATE TABLE test.test (db VARCHAR(255));
    4. INSERT INTO test.test (db) VALUES ('tidb-0');
    5. EOF
    6. mysql -u root -h 127.0.0.1 -P 4002 << EOF
    7. DROP TABLE IF EXISTS test.test;
    8. CREATE TABLE test.test (db VARCHAR(255));
    9. INSERT INTO test.test (db) VALUES ('tidb-1');
    10. EOF
  3. 使用 docker-compose exec 命令,在 ProxySQL Admin Interface 中运行事先准备好的配置 ProxySQL 的 SQL 文件

    1. docker-compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql"

    此 SQL 文件将会运行:

    1. 添加 2 个 TiDB 后端的地址,其中,tidb-0hostgroup_id0tidb-1hostgroup_id1
    2. 生效 TiDB 后端配置,并落盘保存。
    3. 添加用户 root,密码为空,default_hostgroup0,即默认将路由至 tidb-0
    4. 生效用户配置,并落盘保存。
    5. 添加规则 ^SELECT.*FOR UPDATE$rule_id1destination_hostgroup0,即匹配此规则的 SQL 语句将被转发至 hostgroup0 的 TiDB 中(这条规则是为了将 SELECT ... FOR UPDATE 语句转发至写的数据库中)。
    6. 添加规则 ^SELECTrule_id2destination_hostgroup1,即匹配此规则的 SQL 语句将被转发至 hostgroup1 的 TiDB 中。
    7. 生效规则配置,并落盘保存。

      注意:

      关于匹配规则:

      • ProxySQL 将按照 rule_id 从小到大的顺序逐一尝试匹配规则。
      • ^ 匹配 SQL 语句的开头,$ 匹配 SQL 语句的结尾。
      • 此处使用的 match_digest 进行匹配,用于匹配参数化后的 SQL 语句,语法见 query_processor_regex
      • 重要参数:

        • digest:用于匹配参数化后的 Hash 值。
        • match_pattern:用于匹配原始 SQL 语句。
        • negate_match_pattern:设置为 1 时,对 match_digestmatch_pattern 匹配取反。
        • log:将记录查询日志。
        • replace_pattern:将匹配到的内容,替换为此字段的值,如为空,则不做替换。
      • 完整参数,请见 mysql_query_rules

  4. 使用 root 用户登录 ProxySQL MySQL Interface

    1. mysql -u root -h 127.0.0.1 -P 6034

    登录后可运行以下语句:

    • SELECT 语句:

      1. SELECT * FROM test.test;

      预计匹配 rule_id2 的规则,从而转发至 hostgroup1 的 TiDB 后端 tidb-1 中。

    • SELECT ... FOR UPDATE 语句:

      1. SELECT * FROM test.test for UPDATE;

      预计匹配 rule_id1 的规则,从而转发至 hostgroup0 的 TiDB 后端 tidb-0 中。

    • 事务语句:

      1. BEGIN;
      2. INSERT INTO test.test (db) VALUES ('insert this and rollback later');
      3. SELECT * FROM test.test;
      4. ROLLBACK;

      BEGIN 语句预计不会匹配所有规则,因此将使用用户的 default_hostgroup(为 0),从而转发至 hostgroup0 的 TiDB 后端 tidb-0 中。而因为 ProxySQL 默认开启用户的 transaction_persistent,这将使同一个事务内的所有语句运行在同一个 hostgroup 中,因此,这里的 INSERT 语句和 SELECT * FROM test.test; 也将转发至 hostgroup0 的 TiDB 后端 tidb-0 中。

  5. 停止并清除 Docker Compose 启动的容器、网络拓扑等资源。

    1. docker-compose down

预期输出

  1. # ./proxy-rule-split.sh
  2. Creating network "proxy-rule-admin-interface_default" with the default driver
  3. Creating proxy-rule-admin-interface_tidb-1_1 ... done
  4. Creating proxy-rule-admin-interface_tidb-0_1 ... done
  5. Creating proxy-rule-admin-interface_proxysql_1 ... done
  6. +--------+
  7. | db |
  8. +--------+
  9. | tidb-1 |
  10. +--------+
  11. +--------+
  12. | db |
  13. +--------+
  14. | tidb-0 |
  15. +--------+
  16. +--------------------------------+
  17. | db |
  18. +--------------------------------+
  19. | tidb-0 |
  20. | insert this and rollback later |
  21. +--------------------------------+
  22. Stopping proxy-rule-admin-interface_proxysql_1 ... done
  23. Stopping proxy-rule-admin-interface_tidb-0_1 ... done
  24. Stopping proxy-rule-admin-interface_tidb-1_1 ... done
  25. Removing proxy-rule-admin-interface_proxysql_1 ... done
  26. Removing proxy-rule-admin-interface_tidb-0_1 ... done
  27. Removing proxy-rule-admin-interface_tidb-1_1 ... done
  28. Removing network proxy-rule-admin-interface_default

使用配置文件配置负载均衡

以配置文件为配置入口,配置负载均衡场景为例,运行如下命令:

  1. cd example/load-balance-config-file
  2. ./test-load-balance.sh

此配置实现效果与使用 Admin Interface 配置负载均衡完全一致,仅改为使用配置文件进行 ProxySQL 初始化配置。

注意:

  • ProxySQL 的配置保存在 SQLite 中。配置文件仅在 SQLite 不存在时读取。
  • ProxySQL 不建议使用配置文件进行配置更改,仅作为初始化配置时使用,请勿过度依赖配置文件。这是由于使用 ProxySQL Admin Interface 配置时,会有以下优点:

    • 输入校验。
    • 可使用任意 MySQL Client 进行配置更改。
    • 更高的可用性(因为无需重启)。
    • 在使用 ProxySQL Cluster 时将自动同步至其他 ProxySQL 节点。