From 744f4128e8bd79b8aceec86f3c596899c1ce502e Mon Sep 17 00:00:00 2001 From: Cheese Date: Tue, 12 Mar 2024 11:38:09 +0800 Subject: [PATCH] Translate ProxySQL Integration Guide to Chinese (#12305) --- TOC.md | 2 +- develop/dev-guide-proxysql-integration.md | 1365 +++++++++++------ media/develop/proxysql-client-side-lb.png | Bin 0 -> 649420 bytes media/develop/proxysql-client-side-rules.png | Bin 0 -> 832467 bytes .../proxysql-client-side-tidb-cloud.png | Bin 0 -> 475008 bytes .../proxysql-windows-docker-install.png | Bin 0 -> 100350 bytes .../develop/proxysql-windows-git-install.png | Bin 0 -> 118020 bytes 7 files changed, 918 insertions(+), 449 deletions(-) create mode 100644 media/develop/proxysql-client-side-lb.png create mode 100644 media/develop/proxysql-client-side-rules.png create mode 100644 media/develop/proxysql-client-side-tidb-cloud.png create mode 100644 media/develop/proxysql-windows-docker-install.png create mode 100644 media/develop/proxysql-windows-git-install.png diff --git a/TOC.md b/TOC.md index 08095860f57e..301860670098 100644 --- a/TOC.md +++ b/TOC.md @@ -104,7 +104,7 @@ - 第三方工具支持 - [TiDB 支持的第三方工具](/develop/dev-guide-third-party-support.md) - [已知的第三方工具兼容问题](/develop/dev-guide-third-party-tools-compatibility.md) - - [TiDB 与 ProxySQL 集成](/develop/dev-guide-proxysql-integration.md) + - [ProxySQL 集成指南](/develop/dev-guide-proxysql-integration.md) - 部署标准集群 - [软硬件环境需求](/hardware-and-software-requirements.md) - [环境与系统配置检查](/check-before-deployment.md) diff --git a/develop/dev-guide-proxysql-integration.md b/develop/dev-guide-proxysql-integration.md index f98256e64bb4..1dd83d9360e6 100644 --- a/develop/dev-guide-proxysql-integration.md +++ b/develop/dev-guide-proxysql-integration.md @@ -1,659 +1,1128 @@ --- -title: TiDB 与 ProxySQL 集成 -summary: 介绍 TiDB 与 ProxySQL 集成的方法。 +title: ProxySQL 集成指南 +summary: 了解如何将本地部署的 TiDB 或 TiDB Cloud 集群与 ProxySQL 集成。 --- -# TiDB 与 ProxySQL 集成 +# ProxySQL 集成指南 -本文以 CentOS 7 为例,简单介绍 **TiDB** 与 **ProxySQL** 的集成方法。如果你有其他系统的集成需求,可参考[快速体验](#4-快速体验)使用 Docker 及 Docker Compose 部署测试集成环境。你也可以参考以下链接,以获得更多信息: +本文简要介绍 ProxySQL,描述如何在[开发环境](#开发环境)和[生产环境](#生产环境)中将 ProxySQL 与 TiDB 集成,并通过[查询规则的场景](#典型场景)展示集成的主要优势。 -- [TiDB 文档](/overview.md) -- [TiDB 应用开发文档](/develop/dev-guide-overview.md) -- [ProxySQL 官方文档](https://proxysql.com/documentation/) -- [TiDB 与 ProxySQL 的集成测试](https://github.com/Icemap/tidb-proxysql-integration-test) +关于 TiDB 和 ProxySQL 的更多信息,请参考以下文档: -## 1. 启动 TiDB +- [TiDB Cloud](https://docs.pingcap.com/tidbcloud) +- [TiDB 开发者指南](/develop/dev-guide-overview.md) +- [ProxySQL 文档](https://proxysql.com/documentation/) -### 测试环境 +## 什么是 ProxySQL? - +[ProxySQL](https://proxysql.com/) 是一个高性能的开源 SQL 代理。它具有灵活的架构,可以通过多种方式部署,适合各类使用场景。例如,ProxySQL 可以通过缓存频繁访问的数据来提高性能。 -
+ProxySQL 的设计目标是快速、高效且易于使用。它完全兼容 MySQL,并支持高质量 SQL 代理的所有功能。此外,ProxySQL 还提供了许多独特功能,使其成为各种应用程序的理想选择。 -请参考[使用 TiDB Serverless 构建 TiDB 集群](/develop/dev-guide-build-cluster-in-cloud.md)。 +## 为什么集成 ProxySQL? + +- ProxySQL 可以通过降低与 TiDB 交互的延迟来提升应用程序性能。无论你构建什么,无论是使用 Lambda 等无服务器函数的可扩展应用程序(其工作负载不确定并且可能激增),还是构建执行大量数据查询的应用程序,都可以利用 ProxySQL 的强大功能(例如[连接池](https://proxysql.com/documentation/detailed-answers-on-faq/)和[缓存常用查询](https://proxysql.com/documentation/query-cache/))。 +- ProxySQL 可以作为应用程序安全防护的附加层,使用[查询规则](#查询规则)防止 SQL 漏洞(例如 SQL 注入)。 +- 由于 [ProxySQL](https://github.com/sysown/proxysql) 和 [TiDB](https://github.com/pingcap/tidb) 都是开源项目,你可以享受到零供应商锁定的好处。 + +## 部署架构 + +将 ProxySQL 与 TiDB 集成的最直接方式是在应用层和 TiDB 之间添加 ProxySQL 作为独立中介。但是,这种方式无法保证可扩展性和容错性,而且可能因为网络跳转而增加延迟。为避免这些问题,一种替代部署架构是将 ProxySQL 作为附属容器部署,如下图所示: + +![proxysql-client-side-tidb-cloud](/media/develop/proxysql-client-side-tidb-cloud.png) + +> **注意:** +> +> 上图仅供参考,你需要根据实际的部署架构进行调整。 + +## 开发环境 + +本节介绍如何在开发环境中将 TiDB 与 ProxySQL 集成。在满足[前提条件](#前提条件)的情况下,你可以根据 TiDB 集群类型选择以下选项之一开始集成 ProxySQL: + +- 选项 1:[集成 TiDB Cloud 与 ProxySQL](#选项-1-集成-tidb-cloud-与-proxysql) +- 选项 2:[集成本地部署的 TiDB 与 ProxySQL](#选项-2-集成本地部署的-tidb-与-proxysql) + +### 前提条件 + +根据选择的方案,你可能需要以下依赖: + +- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +- [Docker](https://docs.docker.com/get-docker/) +- [Python 3](https://www.python.org/downloads/) +- [Docker Compose](https://docs.docker.com/compose/install/linux/) +- [MySQL Client](https://dev.mysql.com/doc/refman/8.0/en/mysql.html) + +你可以按照下面的说明进行安装: + + + +
+ +1. [下载](https://docs.docker.com/get-docker/)并启动 Docker,其中 Docker Desktop 已包含 Docker Compose。 +2. 运行以下命令安装 Python 和 `mysql-client`: + + ```bash + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + brew install python mysql-client + ``` + +
+ +
+ +```bash +curl -fsSL https://get.docker.com | bash -s docker +yum install -y git python39 docker-ce docker-ce-cli containerd.io docker-compose-plugin mysql +systemctl start docker +```
-
+
+ +- 下载并安装 Git。 + + 1. 从 [Download for Windows](https://git-scm.com/download/win) 页面下载 **64-bit Git for Windows Setup** 安装程序。 + 2. 按照安装向导提示安装 Git。你可以多次点击 **Next** 使用默认的安装设置。 + + ![proxysql-windows-git-install](/media/develop/proxysql-windows-git-install.png) + +- 下载并安装 MySQL Shell。 + + 1. 从 [MySQL Community Server Download](https://dev.mysql.com/downloads/mysql/) 页面下载 MySQL Installer 的 ZIP 文件。 + 2. 解压文件,并在 `bin` 文件夹中找到 `mysql.exe`。你需要将该 `bin` 文件夹的路径添加到系统变量中,并在 Git Bash 中将其设置到 `PATH` 变量中。 + + ```bash + echo 'export PATH="(your bin folder)":$PATH' >>~/.bash_profile + source ~/.bash_profile + ``` + + 例如: + + ```bash + echo 'export PATH="/c/Program Files (x86)/mysql-8.0.31-winx64/bin":$PATH' >>~/.bash_profile + source ~/.bash_profile + ``` + +- 下载并安装 Docker。 + + 1. 从 [Docker Download](https://www.docker.com/products/docker-desktop/) 页面下载 Docker Desktop 安装程序。 + 2. 双击安装程序运行。安装完成后,会提示你重新启动。 + + ![proxysql-windows-docker-install](/media/develop/proxysql-windows-docker-install.png) + +- 从 [Python Download](https://www.python.org/downloads/) 页面下载最新版的 Python 3 安装程序并运行。 + +
+ + + +### 选项 1: 集成 TiDB Cloud 与 ProxySQL + +在这个集成中,你将使用 [ProxySQL Docker 镜像](https://hub.docker.com/r/proxysql/proxysql)以及 TiDB Serverless 集群。下面的步骤将在端口 `16033` 上设置 ProxySQL,请确保此端口可用。 + +#### 步骤 1. 创建一个 TiDB Serverless 集群 + +1. 参考[创建一个 TiDB Serverless 集群](https://docs.pingcap.com/tidbcloud/tidb-cloud-quickstart#step-1-create-a-tidb-cluster)文档。记住为集群设置的 root 密码。 +2. 获取集群的 `hostname`、`port` 及 `username` 供后续使用。 + + 1. 在 [Clusters](https://tidbcloud.com/console/clusters) 页面,点击你的集群名称,进入集群概览页面。 + 2. 在集群概览页面的 **Connection** 面板中,复制 `Endpoint`、`Port` 与 `User` 字段,其中 `Endpoint` 是集群的 `hostname`。 + +#### 步骤 2. 生成 ProxySQL 配置文件 + +1. 克隆 TiDB 和 ProxySQL 的集成示例代码仓库 [`tidb-proxysql-integration`](https://github.com/pingcap-inc/tidb-proxysql-integration): + + + +
+ + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git + ``` + +
+ +
+ + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git + ``` + +
+ +
+ + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git + ``` + +
+ +
+ +2. 进入 `tidb-cloud-connect` 目录: + + + +
+ + ```bash + cd tidb-proxysql-integration/example/tidb-cloud-connect + ``` + +
+ +
+ + ```bash + cd tidb-proxysql-integration/example/tidb-cloud-connect + ``` + +
+ +
+ + ```bash + cd tidb-proxysql-integration/example/tidb-cloud-connect + ``` + +
+ +
+ +3. 运行 `proxysql-config.py` 生成 ProxySQL 配置文件: + + + +
+ + ```bash + python3 proxysql-config.py + ``` + +
+ +
+ + ```bash + python3 proxysql-config.py + ``` + +
+ +
+ + ```bash + python proxysql-config.py + ``` + +
-1. 下载 [TiDB](https://github.com/pingcap/tidb) 源码,进入 `tidb-server` 目录后,使用 `go build` 进行编译。 +
- ```shell - git clone git@github.com:pingcap/tidb.git - cd tidb/cmd/tidb-server - go build + 当出现提示时,输入集群的 `Endpoint` 作为 `Serverless Tier Host`,然后输入集群的 `Port` 与 `User`。 + + 下面是一个输出示例。可以看到,在当前的 `tidb-cloud-connect` 目录下生成了三个配置文件。 + + ``` + [Begin] generating configuration files.. + tidb-cloud-connect.cnf generated successfully. + proxysql-prepare.sql generated successfully. + proxysql-connect.py generated successfully. + [End] all files generated successfully and placed in the current folder. + ``` + +#### 步骤 3. 配置 ProxySQL + +1. 启动 Docker。如果 Docker 已经启动,请跳过此步骤: + + + +
+ + 双击已安装的 Docker 的图标来启动它。 + +
+ +
+ + ```bash + systemctl start docker + ``` + +
+ +
+ + 双击已安装的 Docker 的图标来启动它。 + +
+ +
+ +2. 拉取 ProxySQL 镜像,并在后台启动一个 ProxySQL 容器: + + + +
+ + ```bash + docker compose up -d + ``` + +
+ +
+ + ```bash + docker compose up -d + ``` + +
+ +
+ + ```bash + docker compose up -d ``` -2. 使用配置文件 [`tidb-config.toml`](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/tidb-config.toml) 来启动 TiDB,命令如下所示: +
+ +
+ +3. 运行以下命令集成 ProxySQL,该命令会在 **ProxySQL Admin Interface** 内执行 `proxysql-prepare.sql`: - ```shell - ${TIDB_SERVER_PATH} -config ./tidb-config.toml -store unistore -path "" -lease 0s > ${LOCAL_TIDB_LOG} 2>&1 & + + +
+ + ```bash + docker compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" ``` +
+ +
+ + ```bash + docker compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" + ``` + +
+ +
+ + ```bash + docker compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" + ``` + +
+ +
+ > **注意:** > - > - 此处使用 `unistore` 作为存储引擎,这是 TiDB 的测试存储引擎,请仅在测试时使用它。 - > - `TIDB_SERVER_PATH`:上一步中使用 `go build` 编译的二进制文件位置,如你在 `/usr/local` 下进行上一步操作,那么此处的 `TIDB_SERVER_PATH` 应为 `/usr/local/tidb/tidb-server/tidb-server`。 - > - `LOCAL_TIDB_LOG`:输出 TiDB 日志的位置。 + > `proxysql-prepare.sql` 脚本执行以下操作: + > + > 1. 使用集群的用户名和密码添加一个 ProxySQL 用户。 + > 2. 将该用户分配给监控账户。 + > 3. 将你的 TiDB Serverless 集群添加到主机列表中。 + > 4. 在 ProxySQL 和 TiDB Serverless 集群之间启用安全连接。 + > + > 为了更好地理解此处的配置流程,强烈建议查看 `proxysql-prepare.sql` 文件。关于 ProxySQL 配置的更多信息,参考 [ProxySQL 文档](https://proxysql.com/documentation/proxysql-configuration/)。 -
+ 下面是一个输出示例。输出中显示集群的主机名,这意味着 ProxySQL 和 TiDB Serverless 集群之间的连接建立成功。 + + ``` + *************************** 1. row *************************** + hostgroup_id: 0 + hostname: gateway01.us-west-2.prod.aws.tidbcloud.com + port: 4000 + gtid_port: 0 + status: ONLINE + weight: 1 + compression: 0 + max_connections: 1000 + max_replication_lag: 0 + use_ssl: 1 + max_latency_ms: 0 + comment: + ``` + +#### 步骤 4. 通过 ProxySQL 连接到 TiDB 集群 -
+1. 运行 `proxysql-connect.py` 连接到你的 TiDB 集群。该脚本将自动启动 MySQL 客户端并使用你在[步骤 2](#步骤-2-生成-proxysql-配置文件) 中指定的用户名和密码进行连接。 -[TiUP](/tiup/tiup-overview.md) 在 TiDB 中承担着包管理器的角色,管理着 TiDB 生态下众多的组件,如 TiDB、PD、TiKV 等。 + -1. 安装 TiUP +
- ```shell - curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh + ```bash + python3 proxysql-connect.py ``` -2. 启动测试环境 TiDB +
+ +
- ```shell - tiup playground + ```bash + python3 proxysql-connect.py ``` -
+
-
+
-### 正式环境 + ```bash + python proxysql-connect.py + ``` - +
-
+ -在需要托管 TiDB 服务的前提下(如无法自行运维、需要云原生环境等),建议直接使用 TiDB Cloud。你可以参考 [TiDB Cloud 的 Create a TiDB Cluster](https://docs.pingcap.com/tidbcloud/create-tidb-cluster) 在 TiDB Cloud 中部署正式环境下的 TiDB。 +2. 连接 TiDB 集群后,可以使用以下 SQL 语句验证连接: -
+ ```sql + SELECT VERSION(); + ``` -
+ 如果输出了 TiDB 的版本信息,则表示你已经成功通过 ProxySQL 连接到 TiDB Serverless 集群。如需退出 MySQL 客户端,输入 `quit` 并按下 Enter 键。 -正式环境相对测试环境会复杂许多,建议参考[使用 TiUP 部署 TiDB 集群](/production-deployment-using-tiup.md)并根据硬件条件部署。 + > **注意:** + > + > **调试提示:** 如果无法连接到集群,请检查 `tidb-cloud-connect.cnf`、`proxysql-prepare.sql` 和 `proxysql-connect.py` 文件,确保你提供的服务器信息可用且正确。 -
+3. 要停止和删除容器,并返回上一个目录,运行以下命令: - + -## 2. 启动 ProxySQL +
-### yum 安装 + ```bash + docker compose down + cd - + ``` -1. 添加 RPM 仓库: +
- ```shell - cat > /etc/yum.repos.d/proxysql.repo << EOF - [proxysql] - name=ProxySQL YUM repository - baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/centos/\$releasever - gpgcheck=1 - gpgkey=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/repo_pub_key - EOF +
+ + ```bash + docker compose down + cd - ``` -2. 安装: +
+ +
- ```shell - yum install proxysql + ```bash + docker compose down + cd - ``` -3. 启动: +
- ```shell - systemctl start proxysql +
+ +### 选项 2: 集成本地部署的 TiDB 与 ProxySQL + +在这个集成中,你将使用 [TiDB](https://hub.docker.com/r/pingcap/tidb) 和 [ProxySQL](https://hub.docker.com/r/proxysql/proxysql) 的 Docker 镜像设置环境。你也可以尝试[其他方式安装 TiDB](/quick-start-with-tidb.md)。 + +下面的步骤将在端口 `6033` 和 `4000` 上分别设置 ProxySQL 和 TiDB,请确保这些端口可用。 + +1. 启动 Docker。如果 Docker 已经启动,请跳过此步骤: + + + +
+ + 双击已安装的 Docker 的图标来启动它。 + +
+ +
+ + ```bash + systemctl start docker ``` -### 其他安装方式 +
-参考 ProxySQL 的 [Github 页面](https://github.com/sysown/proxysql#installation)或 [ProxySQL 官方文档](https://proxysql.com/documentation/)进行安装。 +
-## 3. 配置 ProxySQL + 双击已安装的 Docker 的图标来启动它。 -需要将 ProxySQL 内的配置指向 TiDB,以此将 ProxySQL 作为 TiDB 的代理。下面列举必需的配置项,其余配置项可参考 [ProxySQL 官方文档](https://proxysql.com/documentation/)。 +
-### ProxySQL 配置简介 +
-ProxySQL 使用一个单独的端口进行配置管理,另一个端口进行代理。其中,配置管理的入口称为 **_ProxySQL Admin interface_**,代理的入口称为 **_ProxySQL MySQL Interface_**。 +2. 克隆 TiDB 和 ProxySQL 的集成示例代码仓库 [`pingcap-inc/tidb-proxysql-integration`](https://github.com/pingcap-inc/tidb-proxysql-integration): -- **_ProxySQL Admin interface_**:可以使用具有 `admin` 权限的用户连接到管理界面,以读取和写入配置,或者使用具有 `stats` 权限的用户,只能读取某些统计数据(不读取或写入配置)。默认凭证是 `admin:admin` 和 `stats:stats`,但出于安全考虑,可以使用默认凭证进行本地连接。要远程连接,需要配置一个新的用户,通常它被命名为 `radmin`。 -- **_ProxySQL MySQL Interface_**:用于代理,将 SQL 转发到配置的服务中。 + -![proxysql config flow](/media/develop/proxysql_config_flow.png) +
-ProxySQL 有三层配置:`runtime`、`memory`、`disk`。你仅能更改 `memory` 层的配置。在更改配置后,可以使用 `LOAD xxx TO runtime` 来生效这个配置,也可以使用 `SAVE xxx TO DISK` 落盘,防止配置丢失。 + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git + ``` -![proxysql config layer](/media/develop/proxysql_config_layer.png) +
-### 配置 TiDB 后端 +
-在 ProxySQL 中添加 TiDB 后端,此处如果有多个 TiDB 后端,可以添加多条。请在 **_ProxySQL Admin interface_** 进行此操作: + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git + ``` -```sql -INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (0, '127.0.0.1', 4000); -LOAD mysql servers TO runtime; -SAVE mysql servers TO DISK; -``` +
-字段解释: +
-- `hostgroup_id`:ProxySQL 是以 **hostgroup** 为单位管理后端服务的,可以将需要负载均衡的几个服务配置为同一个 hostgroup,这样 ProxySQL 将均匀地分发 SQL 到这些服务上。而在需要区分不同后端服务时(如读写分离场景等),可将其配置为不同的 hostgroup,以此配置不同的代理条件。 -- `hostname`:后端服务的 IP 或域名。 -- `port`:后端服务的端口。 + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git + ``` -### 配置 Proxy 登录账号 +
-在 ProxySQL 中添加 TiDB 后端的登录账号。ProxySQL 将允许此账号来登录 **_ProxySQL MySQL Interface_**,而且 ProxySQL 将以此创建与 TiDB 之间的连接,因此,请确保此账号在 TiDB 中拥有相应权限。请在 **_ProxySQL Admin interface_** 进行此操作: +
-```sql -INSERT INTO mysql_users(username, password, active, default_hostgroup, transaction_persistent) VALUES ('root', '', 1, 0, 1); -LOAD mysql users TO runtime; -SAVE mysql users TO DISK; -``` +3. 拉取 ProxySQL 和 TiDB 的最新镜像: -字段解释: + -- `username`:用户名。 -- `password`:密码。 -- `active`:是否生效。`1` 为生效,`0` 为不生效,仅 `active = 1` 的用户可登录。 -- `default_hostgroup`:此账号默认使用的 hostgroup,SQL 将被发送至此 hostgroup 中,除非查询规则将流量发送到不同的 hostgroup。 -- `transaction_persistent`:值为 `1` 时,表示事务持久化,即:当该用户在连接中开启了一个事务后,那么在事务提交或回滚之前,所有的语句都路由到同一个 hostgroup 中,避免语句分散到不同 hostgroup。 +
-### 配置文件配置 + ```bash + cd tidb-proxysql-integration && docker compose pull + ``` -除了使用 **_ProxySQL Admin interface_** 配置,也可以使用配置文件进行配置。[ProxySQL 文档](https://github.com/sysown/proxysql#configuring-proxysql-through-the-config-file)中,配置文件仅应该被视为是一种辅助初始化的方式,而并非主要配置的手段。配置文件仅在 SQLite 数据库未被创建时读取,后续将不会继续读取配置文件。因此,使用配置文件配置时,你应进行 SQLite 数据库的删除,这将**丢失**你在 **_ProxySQL Admin interface_** 中对配置进行的更改: +
-```shell -rm /var/lib/proxysql/proxysql.db -``` +
-另外,也可以运行 `LOAD xxx FROM CONFIG`,用配置文件中的配置覆盖当前内存中的配置。 + ```bash + cd tidb-proxysql-integration && docker compose pull + ``` -配置文件的位置为 `/etc/proxysql.cnf`,我们将上方的必需配置转换为配置文件方式,仅更改 `mysql_servers`、`mysql_users` 这两个配置节点,其余配置可自行查看 `/etc/proxysql.cnf`: +
-``` -mysql_servers = -( - { - address="127.0.0.1" - port=4000 - hostgroup=0 - max_connections=2000 - } -) - -mysql_users: -( - { - username = "root" - password = "" - default_hostgroup = 0 - max_connections = 1000 - default_schema = "test" - active = 1 - transaction_persistent = 1 - } -) -``` +
-随后使用 `systemctl restart proxysql` 进行服务重启后即可生效,配置生效后将自动创建 SQLite 数据库,后续将不会再次读取配置文件。 + ```bash + cd tidb-proxysql-integration && docker compose pull + ``` -### 其余配置项 +
-仅以上配置为必需配置项,其余配置项并非必需。你可在 [ProxySQL Global Variables](https://proxysql.com/documentation/global-variables/) 中获取全部配置项的名称及作用。 +
-## 4. 快速体验 +4. 使用 TiDB 和 ProxySQL 容器启动一个集成环境: -在测试环境中,你可以使用 Docker 及 Docker Compose 快速进行集成后的环境体验,请确认 `4000`、`6033` 端口未被占用,然后执行如下命令: + -```shell -git clone https://github.com/Icemap/tidb-proxysql-integration-test.git -cd tidb-proxysql-integration-test && docker-compose pull # Get the latest Docker images -sudo setenforce 0 # Only on Linux -docker-compose up -d -``` +
-> **警告:** -> -> **请勿**在生产环境使用此快速体验方式创建集成环境。 + ```bash + docker compose up -d + ``` -这样就已经完成了一个集成了 TiDB 与 ProxySQL 环境的启动,这将启动两个容器。你可以使用用户名为 `root`,密码为空的账号,登录到本机的 `6033` 端口 (ProxySQL)。容器具体配置可见 [`docker-compose.yaml`](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/docker-compose.yaml),ProxySQL 具体配置可见 [proxysql-docker.cnf](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/proxysql-docker.cnf)。 +
-运行如下命令: +
-```shell -mysql -u root -h 127.0.0.1 -P 6033 -e "SELECT VERSION()" -``` + ```bash + docker compose up -d + ``` -运行结果: +
-```sql -+--------------------+ -| VERSION() | -+--------------------+ -| 8.0.11-TiDB-v7.6.0 | -+--------------------+ -``` +
-## 5. 配置示例 + ```bash + docker compose up -d + ``` -配置示例的前提条件: +
-- Docker -- Docker Compose -- MySQL Client +
-下载示例源码并进入目录: + 你可以使用 `root` 用户名及空密码登录到 ProxySQL 的 `6033` 端口。 -```shell -git clone https://github.com/Icemap/tidb-proxysql-integration-test.git -cd tidb-proxysql-integration-test -``` +5. 通过 ProxySQL 连接到 TiDB: -下面的示例均以 `tidb-proxysql-integration-test` 目录做为根目录。 + -### 使用 Admin Interface 配置负载均衡 +
-进入本示例目录: + ```bash + mysql -u root -h 127.0.0.1 -P 6033 + ``` -```shell -cd example/proxy-rule-admin-interface -``` +
-#### 脚本运行 +
-以 **_ProxySQL Admin Interface_** 为配置入口,配置负载均衡场景为例。可使用以下命令运行脚本: + ```bash + mysql -u root -h 127.0.0.1 -P 6033 + ``` -```shell -./test-load-balance.sh -``` +
+ +
+ + ```bash + mysql -u root -h 127.0.0.1 -P 6033 + ``` + +
-#### 逐步运行 +
-1. 通过 Docker Compose 启动三个 TiDB 容器实例,容器内部端口均为 `4000`,映射宿主机端口为 `4001`、`4002`、`4003`。TiDB 容器实例启动后,再启动一个 ProxySQL 实例,容器内部 **_ProxySQL MySQL Interface_** 端口为 `6033`,映射宿主机端口为 `6034`。不暴露 **_ProxySQL Admin Interface_** 端口,因为其仅可在本地(即容器内)登录 **_ProxySQL Admin Interface_**。此流程被写在 [`docker-compose.yaml`](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/example/load-balance-admin-interface/docker-compose.yaml) 中。 +6. 连接 TiDB 集群后,可以使用以下 SQL 语句验证连接: - ```shell - docker-compose up -d + ```sql + SELECT VERSION(); ``` -2. 在 3 个 TiDB 实例内,创建相同的表结构,但写入不同的数据:`'tidb-0'`、`'tidb-1'`、`'tidb-2'`,以便分辨不同的数据库实例: + 如果输出了 TiDB 的版本信息,则表示你已经成功通过 ProxySQL 连接到 TiDB 集群。 - ```shell - mysql -u root -h 127.0.0.1 -P 4001 << EOF - DROP TABLE IF EXISTS test.test; - CREATE TABLE test.test (db VARCHAR(255)); - INSERT INTO test.test (db) VALUES ('tidb-0'); - EOF +7. 要停止和删除容器,并返回上一个目录,运行以下命令: - mysql -u root -h 127.0.0.1 -P 4002 << EOF - DROP TABLE IF EXISTS test.test; - CREATE TABLE test.test (db VARCHAR(255)); - INSERT INTO test.test (db) VALUES ('tidb-1'); - EOF + - mysql -u root -h 127.0.0.1 -P 4003 << EOF - DROP TABLE IF EXISTS test.test; - CREATE TABLE test.test (db VARCHAR(255)); - INSERT INTO test.test (db) VALUES ('tidb-2'); - EOF +
+ + ```bash + docker compose down + cd - + ``` + +
+ +
+ + ```bash + docker compose down + cd - ``` -3. 使用 `docker-compose exec` 命令,在 **_ProxySQL Admin Interface_** 中运行事先准备好的配置 ProxySQL 的 [SQL 文件](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/example/load-balance-admin-interface/proxysql-prepare.sql): +
+ +
- ```shell - docker-compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" + ```bash + docker compose down + cd - ``` - 此 SQL 文件将会运行: +
+ +
+ +## 生产环境 + +对于生产环境,建议直接使用 [TiDB Cloud](https://en.pingcap.com/tidb-cloud/) 以获得完全托管的体验。 + +### 前提条件 + +下载并安装一个 MySQL 客户端。例如,[MySQL Shell](https://dev.mysql.com/downloads/shell/)。 + +### 基于 CentOS 集成 TiDB Cloud 与 ProxySQL - 1. 添加 3 个 TiDB 后端的地址,并且 `hostgroup_id` 均为 `0`。 - 2. 令 TiDB 后端配置生效,并落盘保存。 - 3. 添加用户 `root`,密码为空,`default_hostgroup` 为 `0`,对应上方的 TiDB 后端 `hostgroup_id`。 - 4. 生效用户配置,并落盘保存。 +你可以在不同的平台上安装 ProxySQL,下面以 CentOS 为例进行说明。 -4. 使用 `root` 用户登录 **_ProxySQL MySQL Interface_**,连续查询 5 次数据,预期结果将有 `'tidb-0'`、`'tidb-1'`、`'tidb-2'` 三种不同的返回。 +关于 ProxySQL 支持的平台和版本要求的完整列表,见 [ProxySQL 文档](https://proxysql.com/documentation/installing-proxysql/)。 - ```shell - mysql -u root -h 127.0.0.1 -P 6034 -t << EOF - SELECT * FROM test.test; - SELECT * FROM test.test; - SELECT * FROM test.test; - SELECT * FROM test.test; - SELECT * FROM test.test; +#### 步骤 1. 创建一个 TiDB Dedicated 集群 + +具体步骤请参考[创建一个 TiDB Dedicated 集群](https://docs.pingcap.com/tidbcloud/create-tidb-cluster)。 + +#### 步骤 2. 安装 ProxySQL + +1. 将 ProxySQL 添加到 YUM 仓库: + + ```bash + cat > /etc/yum.repos.d/proxysql.repo << EOF + [proxysql] + name=ProxySQL YUM repository + baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/centos/\$releasever + gpgcheck=1 + gpgkey=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/repo_pub_key EOF ``` -5. 停止并清除 Docker Compose 启动的容器、网络拓扑等资源。 +2. 安装 ProxySQL: - ```shell - docker-compose down + ```bash + yum install -y proxysql ``` -#### 预期输出 +3. 启动 ProxySQL: + + ```bash + systemctl start proxysql + ``` -因为负载均衡的原因,预期输出将有 `'tidb-0'`、`'tidb-1'`、`'tidb-2'` 三种不同的返回。但具体顺序未知。其中一种预期输出为: +要了解更多关于 ProxySQL 支持的平台及其安装方法,参考 [ProxySQL README](https://github.com/sysown/proxysql#installation) 或 [ProxySQL 安装文档](https://proxysql.com/documentation/installing-proxysql/)。 -``` -# ./test-load-balance.sh -Creating network "load-balance-admin-interface_default" with the default driver -Creating load-balance-admin-interface_tidb-1_1 ... done -Creating load-balance-admin-interface_tidb-2_1 ... done -Creating load-balance-admin-interface_tidb-0_1 ... done -Creating load-balance-admin-interface_proxysql_1 ... done -+--------+ -| db | -+--------+ -| tidb-2 | -+--------+ -+--------+ -| db | -+--------+ -| tidb-0 | -+--------+ -+--------+ -| db | -+--------+ -| tidb-1 | -+--------+ -+--------+ -| db | -+--------+ -| tidb-1 | -+--------+ -+--------+ -| db | -+--------+ -| tidb-1 | -+--------+ -Stopping load-balance-admin-interface_proxysql_1 ... done -Stopping load-balance-admin-interface_tidb-0_1 ... done -Stopping load-balance-admin-interface_tidb-2_1 ... done -Stopping load-balance-admin-interface_tidb-1_1 ... done -Removing load-balance-admin-interface_proxysql_1 ... done -Removing load-balance-admin-interface_tidb-0_1 ... done -Removing load-balance-admin-interface_tidb-2_1 ... done -Removing load-balance-admin-interface_tidb-1_1 ... done -Removing network load-balance-admin-interface_default -``` +#### 步骤 3. 配置 ProxySQL -### 使用 Admin Interface 配置用户分离 +为了使用 ProxySQL 作为 TiDB 的代理,你需要配置 ProxySQL。你可以[在 ProxySQL Admin Interface 中执行 SQL 语句](#选项-1-使用-admin-interface-配置-proxysql)(推荐)或[使用配置文件](#选项-2-使用配置文件配置-proxysql)进行配置。 -进入本示例目录: +> **注意:** +> +> 以下章节仅列出 ProxySQL 的必要配置项。 +> +> 完整的配置信息,可参考 [ProxySQL 文档](https://proxysql.com/documentation/proxysql-configuration/)。 -```shell -cd example/proxy-rule-admin-interface -``` +##### 选项 1: 使用 Admin Interface 配置 ProxySQL -#### 脚本运行 +1. 使用标准的 ProxySQL Admin Interface 更新 ProxySQL 的配置。你可以通过任何 MySQL 命令行客户端访问(默认端口为 `6032`)。 -以 **_ProxySQL Admin Interface_** 为配置入口,配置负载均衡配置用户分离场景为例,不同用户将使用不同的 TiDB 后端。可使用以下命令运行脚本: + ```bash + mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt 'ProxySQL Admin> ' + ``` -```shell -./test-user-split.sh -``` + 执行以上命令后,系统将显示 `'ProxySQL Admin'` 提示。 -#### 逐步运行 +2. 你可以在当前 MySQL 命令行客户端中向 ProxySQL 添加一个或多个 TiDB 集群。例如,下面的语句将添加一个 TiDB Dedicated 集群。你需要用集群的 `Endpoint` 和 `Port` 替换 `` 和 ``(默认端口为 `4000`)。 -1. 通过 Docker Compose 启动两个 TiDB 容器实例,容器内部端口均为 `4000`,映射宿主机端口为 `4001`、`4002`。TiDB 实例启动后,再启动一个 ProxySQL 实例,容器内部 **_ProxySQL MySQL Interface_** 端口为 `6033`,映射宿主机端口为 `6034`。不暴露 **_ProxySQL Admin Interface_** 端口,因为其仅可在本地(即容器内)登录 **_ProxySQL Admin Interface_**。此流程被写在 [`docker-compose.yaml`](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/example/user-split-admin-interface/docker-compose.yaml) 中。 + ```sql + INSERT INTO mysql_servers(hostgroup_id, hostname, port) + VALUES + ( + 0, + '', + + ); + LOAD mysql servers TO runtime; + SAVE mysql servers TO DISK; + ``` - ```shell - docker-compose up -d + > **注意:** + > + > - `hostgroup_id`:指定一个 **hostgroup** 的 ID。ProxySQL 使用 **hostgroup** 管理集群。如果需要将 SQL 流量均匀地分配给这些集群,你可以将需要负载均衡的几个 TiDB 集群配置到同一个 **hostgroup** 中。另一方面,为了区分不同的集群,例如为了实现读写分离,你可以将它们配置为不同的 **hostgroup** ID。 + > - `hostname`:TiDB 集群的 `Endpoint`。 + > - `port`:TiDB 集群的 `Port`。 + +3. 为配置 ProxySQL 的登录用户,你需要确保用户在 TiDB 集群上有适当的权限。在下面的语句中,你需要把 `` 和 `` 替换为集群的实际用户名和密码。 + + ```sql + INSERT INTO mysql_users( + username, password, active, default_hostgroup, + transaction_persistent + ) + VALUES + ( + '', + '', + 1, 0, 1 + ); + LOAD mysql users TO runtime; + SAVE mysql users TO DISK; ``` -2. 在 2 个 TiDB 实例内,创建相同的表结构,但写入不同的数据`'tidb-0'`、`'tidb-1'`,以便分辨不同的数据库实例: + > **注意:** + > + > - `username`:TiDB 用户名。 + > - `password`:TiDB 密码。 + > - `active`:指定用户是否处于激活状态。`1` 表示该用户是**激活的**,可以用于登录,`0` 表示该用户是非激活的。 + > - `default_hostgroup`:用户使用的默认 `hostgroup`,除非特定的查询规则覆盖了 `hostgroup`,否则 SQL 将会默认路由到 `default_hostgroup`。 + > - `transaction_persistent`:值为 `1` 表示使用持久性事务。即当用户在一个连接中启动一个事务时,所有的查询语句都被路由到同一个 `hostgroup`,直到事务被提交或回滚。 - ```shell - mysql -u root -h 127.0.0.1 -P 4001 << EOF - DROP TABLE IF EXISTS test.test; - CREATE TABLE test.test (db VARCHAR(255)); - INSERT INTO test.test (db) VALUES ('tidb-0'); - EOF +##### 选项 2: 使用配置文件配置 ProxySQL - mysql -u root -h 127.0.0.1 -P 4002 << EOF - DROP TABLE IF EXISTS test.test; - CREATE TABLE test.test (db VARCHAR(255)); - INSERT INTO test.test (db) VALUES ('tidb-1'); - EOF +这个选项只能作为配置 ProxySQL 的备用方案。更多信息,可参考[使用配置文件配置 ProxySQL](https://github.com/sysown/proxysql#configuring-proxysql-through-the-config-file)。 + +1. 删除现有的 SQLite 数据库,即 ProxySQL 存储配置的位置。 + + ```bash + rm /var/lib/proxysql/proxysql.db ``` -3. 为 ProxySQL 在 `tidb-1` 实例中新建一个用户: + > **警告:** + > + > 删除 SQLite 数据库后,通过 ProxySQL Admin Interface 所做的任何配置更改都会丢失。 - ```shell - mysql -u root -h 127.0.0.1 -P 4002 << EOF - CREATE USER 'root1' IDENTIFIED BY ''; - GRANT ALL PRIVILEGES ON *.* TO 'root1'@'%'; - FLUSH PRIVILEGES; - EOF +2. 根据你的需要修改配置文件 `/etc/proxysql.cnf`。例如: + + ``` + mysql_servers: + ( + { + address="" + port= + hostgroup=0 + max_connections=2000 + } + ) + + mysql_users: + ( + { + username = "" + password = "" + default_hostgroup = 0 + max_connections = 1000 + default_schema = "test" + active = 1 + transaction_persistent = 1 + } + ) ``` -4. 使用 `docker-compose exec` 命令,在 **_ProxySQL Admin Interface_** 中运行事先准备好的配置 ProxySQL 的 [SQL 文件](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/example/user-split-admin-interface/proxysql-prepare.sql): + 在上面的例子中: - ```shell - docker-compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" + - `address` 和 `port` 用于指定你的 TiDB Cloud 集群的 `Endpoint` 和 `Port`。 + - `username` 和 `password` 用于指定你的 TiDB Cloud 集群的用户名和密码。 + +3. 重启 ProxySQL: + + ```bash + systemctl restart proxysql ``` - 此 SQL 文件将会运行: + 重新启动后,ProxySQL 将自动创建 SQLite 数据库。 + +> **警告:** +> +> 在生产环境中,不要使用默认的管理员用户运行 ProxySQL。在启动 `proxysql` 服务之前,你可以通过修改 [`admin_credentials`](https://proxysql.com/documentation/global-variables/admin-variables/#admin-admin_credentials) 变量更改 `/etc/proxysql.cnf` 文件中的默认值。 + +## 典型场景 - 1. 添加 2 个 TiDB 后端的地址,其中,`tidb-0` 的 `hostgroup_id` 为 `0`,`tidb-1` 的 `hostgroup_id` 为 `1`。 - 2. 生效 TiDB 后端配置,并落盘保存。 - 3. 添加用户 `root`,密码为空,`default_hostgroup` 为 `0`,即默认将路由至 `tidb-0`。 - 4. 添加用户 `root1`,密码为空,`default_hostgroup` 为 `1`,即默认将路由至 `tidb-1`。 - 5. 生效用户配置,并落盘保存。 +本节以查询规则为例,介绍集成 TiDB 与 ProxySQL 能带来的一些优势。 -5. 分别使用 `root` 用户及 `root1` 用户登录 **_ProxySQL MySQL Interface_**,预期结果将为 `'tidb-0'`、`'tidb-1'`。 +### 查询规则 - ```shell - mysql -u root -h 127.0.0.1 -P 6034 -e "SELECT * FROM test.test;" - mysql -u root1 -h 127.0.0.1 -P 6034 -e "SELECT * FROM test.test;" +数据库可能会因为高流量、错误代码或恶意攻击而过载。因此,审核 SQL 是必要的。使用 ProxySQL 的查询规则,你可以有效地应对这些问题,例如通过重路由、改写 SQL 或者拒绝查询等方式。 + +![proxysql-client-side-rules](/media/develop/proxysql-client-side-rules.png) + +> **注意:** +> +> 以下步骤使用 TiDB 和 ProxySQL 的容器镜像配置查询规则。如果你还没有拉取这些镜像,请参考[集成本地部署的 TiDB 与 ProxySQL](#选项-2-集成本地部署的-tidb-与-proxysql) 部分的详细步骤。 + +1. 克隆 TiDB 和 ProxySQL 的集成示例代码仓库 [`pingcap-inc/tidb-proxysql-integration`](https://github.com/pingcap-inc/tidb-proxysql-integration)。如果你已经在前面的步骤中克隆了它,请跳过这一步。 + + + +
+ + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git ``` -6. 停止并清除 Docker Compose 启动的容器、网络拓扑等资源。 +
+ +
- ```shell - docker-compose down + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git ``` -#### 预期输出 +
-``` -# ./test-user-split.sh -Creating network "user-split-admin-interface_default" with the default driver -Creating user-split-admin-interface_tidb-1_1 ... done -Creating user-split-admin-interface_tidb-0_1 ... done -Creating user-split-admin-interface_proxysql_1 ... done -+--------+ -| db | -+--------+ -| tidb-0 | -+--------+ -+--------+ -| db | -+--------+ -| tidb-1 | -+--------+ -Stopping user-split-admin-interface_proxysql_1 ... done -Stopping user-split-admin-interface_tidb-0_1 ... done -Stopping user-split-admin-interface_tidb-1_1 ... done -Removing user-split-admin-interface_proxysql_1 ... done -Removing user-split-admin-interface_tidb-0_1 ... done -Removing user-split-admin-interface_tidb-1_1 ... done -Removing network user-split-admin-interface_default -``` +
-### 使用 Admin Interface 配置代理规则 + ```bash + git clone https://github.com/pingcap-inc/tidb-proxysql-integration.git + ``` -进入本示例目录: +
-```shell -cd example/proxy-rule-admin-interface -``` +
-#### 脚本运行 +2. 进入 ProxySQL 查询规则的示例目录: -以 **_ProxySQL Admin Interface_** 为配置入口,代理规则场景中,常见的读写分离配置为例,将使用规则匹配将要运行的 SQL,从而将读、写 SQL 转发至不同的 TiDB 后端(若均未匹配,则使用用户的 `default_hostgroup`)。可使用以下命令运行脚本: + -```shell -./proxy-rule-split.sh -``` +
-#### 逐步运行 + ```bash + cd tidb-proxysql-integration/example/proxy-rule-admin-interface + ``` + +
+ +
+ + ```bash + cd tidb-proxysql-integration/example/proxy-rule-admin-interface + ``` + +
+ +
+ + ```bash + cd tidb-proxysql-integration/example/proxy-rule-admin-interface + ``` + +
+ +
+ +3. 运行下面的命令启动两个 TiDB 容器和一个 ProxySQL 容器: + + + +
+ + ```bash + docker compose up -d + ``` + +
+ +
+ + ```bash + docker compose up -d + ``` + +
+ +
+ + ```bash + docker compose up -d + ``` + +
+ +
+ + 如果运行成功,以下容器将被启动: + + - 两个 Docker 容器的 TiDB 集群,端口分别为 `4001` 和 `4002` + - 一个 Docker 容器的 ProxySQL,端口为 `6034` + +4. 在两个 TiDB 容器中,使用 `mysql` 创建一个具有相同 schema 的表,然后插入不同的数据 (`'tidb-server01-port-4001'`, `'tidb-server02-port-4002'`) 以区分这两个容器。 -1. 通过 Docker Compose 启动两个 TiDB 容器实例,容器内部端口均为 `4000`,映射宿主机端口为 `4001`、`4002`。TiDB 实例启动后,再启动一个 ProxySQL 实例,容器内部 **_ProxySQL MySQL Interface_** 端口为 `6033`,映射宿主机端口为 `6034`。不暴露 **_ProxySQL Admin Interface_** 端口,因为其仅可在本地(即容器内)登录 **_ProxySQL Admin Interface_**。此流程被写在 [`docker-compose.yaml`](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/example/proxy-rule-admin-interface/docker-compose.yaml) 中。 + - ```shell - docker-compose up -d +
+ + ```bash + mysql -u root -h 127.0.0.1 -P 4001 << EOF + DROP TABLE IF EXISTS test.tidb_server; + CREATE TABLE test.tidb_server (server_name VARCHAR(255)); + INSERT INTO test.tidb_server (server_name) VALUES ('tidb-server01-port-4001'); + EOF + + mysql -u root -h 127.0.0.1 -P 4002 << EOF + DROP TABLE IF EXISTS test.tidb_server; + CREATE TABLE test.tidb_server (server_name VARCHAR(255)); + INSERT INTO test.tidb_server (server_name) VALUES ('tidb-server02-port-4002'); + EOF ``` -2. 在 2 个 TiDB 实例内,创建相同的表结构,但写入不同的数据 `'tidb-0'`、`'tidb-1'`,以便分辨不同的数据库实例。此处展示向其中一个 TiDB 实例写入数据的命令,另一实例同理: +
- ```shell +
+ + ```bash mysql -u root -h 127.0.0.1 -P 4001 << EOF - DROP TABLE IF EXISTS test.test; - CREATE TABLE test.test (db VARCHAR(255)); - INSERT INTO test.test (db) VALUES ('tidb-0'); + DROP TABLE IF EXISTS test.tidb_server; + CREATE TABLE test.tidb_server (server_name VARCHAR(255)); + INSERT INTO test.tidb_server (server_name) VALUES ('tidb-server01-port-4001'); EOF mysql -u root -h 127.0.0.1 -P 4002 << EOF - DROP TABLE IF EXISTS test.test; - CREATE TABLE test.test (db VARCHAR(255)); - INSERT INTO test.test (db) VALUES ('tidb-1'); + DROP TABLE IF EXISTS test.tidb_server; + CREATE TABLE test.tidb_server (server_name VARCHAR(255)); + INSERT INTO test.tidb_server (server_name) VALUES ('tidb-server02-port-4002'); EOF ``` -3. 使用 `docker-compose exec` 命令,在 **_ProxySQL Admin Interface_** 中运行事先准备好的配置 ProxySQL 的 [SQL 文件](https://github.com/Icemap/tidb-proxysql-integration-test/blob/main/example/proxy-rule-admin-interface/proxysql-prepare.sql): +
+ +
+ + ```bash + mysql -u root -h 127.0.0.1 -P 4001 << EOF + DROP TABLE IF EXISTS test.tidb_server; + CREATE TABLE test.tidb_server (server_name VARCHAR(255)); + INSERT INTO test.tidb_server (server_name) VALUES ('tidb-server01-port-4001'); + EOF - ```shell - docker-compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" + mysql -u root -h 127.0.0.1 -P 4002 << EOF + DROP TABLE IF EXISTS test.tidb_server; + CREATE TABLE test.tidb_server (server_name VARCHAR(255)); + INSERT INTO test.tidb_server (server_name) VALUES ('tidb-server02-port-4002'); + EOF ``` - 此 SQL 文件将会运行: +
+ +
+ +5. 运行下面的命令配置 ProxySQL,该命令会在 ProxySQL Admin Interface 中执行 `proxysql-prepare.sql`,从而在 TiDB 容器和 ProxySQL 之间建立一个代理连接。 - 1. 添加 2 个 TiDB 后端的地址,其中,`tidb-0` 的 `hostgroup_id` 为 `0`,`tidb-1` 的 `hostgroup_id` 为 `1`。 - 2. 生效 TiDB 后端配置,并落盘保存。 - 3. 添加用户 `root`,密码为空,`default_hostgroup` 为 `0`,即默认将路由至 `tidb-0`。 - 4. 生效用户配置,并落盘保存。 - 5. 添加规则 `^SELECT.*FOR UPDATE$`,`rule_id` 为 `1`,`destination_hostgroup` 为 `0`,即匹配此规则的 SQL 语句将被转发至 `hostgroup` 为 `0` 的 TiDB 中(这条规则是为了将 `SELECT ... FOR UPDATE` 语句转发至写的数据库中)。 - 6. 添加规则 `^SELECT`,`rule_id` 为 `2`,`destination_hostgroup` 为 `1`,即匹配此规则的 SQL 语句将被转发至 `hostgroup` 为 `1` 的 TiDB 中。 - 7. 生效规则配置,并落盘保存。 + + +
+ + ```bash + docker compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" + ``` + +
+ +
+ + ```bash + docker compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" + ``` + +
+ +
+ + ```bash + docker compose exec proxysql sh -c "mysql -uadmin -padmin -h127.0.0.1 -P6032 < ./proxysql-prepare.sql" + ``` + +
+ +
> **注意:** > - > 关于匹配规则: - > - > - ProxySQL 将按照 `rule_id` 从小到大的顺序逐一尝试匹配规则。 - > - `^` 匹配 SQL 语句的开头,`$` 匹配 SQL 语句的结尾。 - > - 此处使用的 `match_digest` 进行匹配,用于匹配参数化后的 SQL 语句,语法见 [query_processor_regex](https://proxysql.com/documentation/global-variables/mysql-variables/#mysql-query_processor_regex)。 - > - 重要参数: + > `proxysql-prepare.sql` 脚本完成以下操作: > - > - `digest`:用于匹配参数化后的 Hash 值。 - > - `match_pattern`:用于匹配原始 SQL 语句。 - > - `negate_match_pattern`:设置为 `1` 时,对 `match_digest` 或 `match_pattern` 匹配取反。 - > - `log`:将记录查询日志。 - > - `replace_pattern`:将匹配到的内容,替换为此字段的值,如为空,则不做替换。 + > - 在 ProxySQL 中添加 TiDB 集群,`hostgroup_id` 分别为 `0` 和 `1`。 + > - 添加一个用户 `root`,密码为空,并设置 `default_hostgroup` 为 `0`。 + > - 添加规则 `^SELECT.*FOR UPDATE$`,`rule_id` 为 `1`,`destination_hostgroup` 为 `0`。这代表如果一个 SQL 语句与此规则相匹配,该请求将被转发到 `hostgroup` 为 `0` 的 TiDB 集群。 + > - 添加规则 `^SELECT`,`rule_id` 为 `2`,`destination_hostgroup` 为 `1`。这代表如果一个 SQL 语句与此规则相匹配,该请求将被转发到 `hostgroup` 为 `1` 的 TiDB 集群。 > - > - 完整参数,请见 [mysql_query_rules](https://proxysql.com/documentation/main-runtime/#mysql_query_rules)。 + > 为了更好地理解此处的配置流程,强烈建议查看 `proxysql-prepare.sql` 文件。关于 ProxySQL 配置的更多信息,参考 [ProxySQL 文档](https://proxysql.com/documentation/proxysql-configuration/)。 -4. 使用 `root` 用户登录 **_ProxySQL MySQL Interface_**: + 下面是关于 ProxySQL 匹配 SQL 查询的规则的一些补充信息: - ```shell - mysql -u root -h 127.0.0.1 -P 6034 - ``` + - ProxySQL 尝试按照 `rule_id` 的升序逐一匹配规则。 + - 规则中的 `^` 符号用于匹配 SQL 语句的开头,`$` 符号用于匹配语句的结尾。 - 登录后可运行以下语句: + 关于 ProxySQL 正则表达式和模式匹配的更多信息,参考 ProxySQL 文档 [`mysql-query_processor_regex`](https://proxysql.com/documentation/global-variables/mysql-variables/#mysql-query_processor_regex)。 - - `SELECT` 语句: + 关于完整的参数列表,参考 ProxySQL 文档 [`mysql_query_rules`](https://proxysql.com/documentation/main-runtime/#mysql_query_rules)。 - ```sql - SELECT * FROM test.test; +6. 验证配置并检查查询规则是否有效。 + + 1. 使用 `root` 用户登录 ProxySQL MySQL Interface: + + + +
+ + ```bash + mysql -u root -h 127.0.0.1 -P 6034 ``` - 预计匹配 `rule_id` 为 `2` 的规则,从而转发至 `hostgroup` 为 `1` 的 TiDB 后端 `tidb-1` 中。 +
- - `SELECT ... FOR UPDATE` 语句: +
- ```sql - SELECT * FROM test.test for UPDATE; + ```bash + mysql -u root -h 127.0.0.1 -P 6034 + ``` + +
+ +
+ + ```bash + mysql -u root -h 127.0.0.1 -P 6034 ``` - 预计匹配 `rule_id` 为 `1` 的规则,从而转发至 `hostgroup` 为 `0` 的 TiDB 后端 `tidb-0` 中。 +
- - 事务语句: +
+ + 2. 执行以下 SQL 语句: + + - 执行一个 `SELECT` 语句: + + ```sql + SELECT * FROM test.tidb_server; + ``` + + 这个语句将匹配 `rule_id` 为 `2` 的规则,因此将转发语句到 `hostgroup` 为 `1` 上的 TiDB 集群中。 + + - 执行一个 `SELECT ... FOR UPDATE` 语句: + + ```sql + SELECT * FROM test.tidb_server FOR UPDATE; + ``` + + 这个语句将匹配 `rule_id` 为 `1` 的规则,因此将转发语句到 `hostgroup` 为 `0` 上的 TiDB 集群中。 + + - 启动一个事务: + + ```sql + BEGIN; + INSERT INTO test.tidb_server (server_name) VALUES ('insert this and rollback later'); + SELECT * FROM test.tidb_server; + ROLLBACK; + ``` + + 在这个事务中,`BEGIN` 语句将不会匹配任何规则。因此,它将使用默认的 `hostgroup`(在这个例子中为 `hostgroup 0`)。因为 ProxySQL 默认启用了用户 transaction_persistent,它将在同一事务中,将所有语句都转发至相同的 `hostgroup`,所以 `INSERT` 和 `SELECT * FROM test.tidb_server;` 语句也将被转发到 `hostgroup` 为 `0` 的 TiDB 集群。 + + 下面是一个输出示例。如果你得到类似的输出,表示你已经成功配置了 ProxySQL 的查询规则。 ```sql - BEGIN; - INSERT INTO test.test (db) VALUES ('insert this and rollback later'); - SELECT * FROM test.test; - ROLLBACK; + +-------------------------+ + | server_name | + +-------------------------+ + | tidb-server02-port-4002 | + +-------------------------+ + +-------------------------+ + | server_name | + +-------------------------+ + | tidb-server01-port-4001 | + +-------------------------+ + +--------------------------------+ + | server_name | + +--------------------------------+ + | tidb-server01-port-4001 | + | insert this and rollback later | + +--------------------------------+ ``` - `BEGIN` 语句预计不会匹配所有规则,因此将使用用户的 `default_hostgroup`(为 `0`),从而转发至 `hostgroup` 为 `0` 的 TiDB 后端 `tidb-0` 中。而因为 ProxySQL 默认开启用户的 `transaction_persistent`,这将使同一个事务内的所有语句运行在同一个 `hostgroup` 中,因此,这里的 `INSERT` 语句和 `SELECT * FROM test.test;` 也将转发至 `hostgroup` 为 `0` 的 TiDB 后端 `tidb-0` 中。 + 3. 如需退出 MySQL 客户端,输入 `quit` 并按下 Enter 键。 -5. 停止并清除 Docker Compose 启动的容器、网络拓扑等资源。 +7. 要停止和删除容器,并返回上一个目录,运行以下命令: - ```shell - docker-compose down + + +
+ + ```bash + docker compose down + cd - ``` -#### 预期输出 +
-``` -# ./proxy-rule-split.sh -Creating network "proxy-rule-admin-interface_default" with the default driver -Creating proxy-rule-admin-interface_tidb-1_1 ... done -Creating proxy-rule-admin-interface_tidb-0_1 ... done -Creating proxy-rule-admin-interface_proxysql_1 ... done -+--------+ -| db | -+--------+ -| tidb-1 | -+--------+ -+--------+ -| db | -+--------+ -| tidb-0 | -+--------+ -+--------------------------------+ -| db | -+--------------------------------+ -| tidb-0 | -| insert this and rollback later | -+--------------------------------+ -Stopping proxy-rule-admin-interface_proxysql_1 ... done -Stopping proxy-rule-admin-interface_tidb-0_1 ... done -Stopping proxy-rule-admin-interface_tidb-1_1 ... done -Removing proxy-rule-admin-interface_proxysql_1 ... done -Removing proxy-rule-admin-interface_tidb-0_1 ... done -Removing proxy-rule-admin-interface_tidb-1_1 ... done -Removing network proxy-rule-admin-interface_default -``` +
-### 使用配置文件配置负载均衡 + ```bash + docker compose down + cd - + ``` -以配置文件为配置入口,配置负载均衡场景为例,运行如下命令: +
-```shell -cd example/load-balance-config-file -./test-load-balance.sh -``` +
-此配置实现效果与[使用 Admin Interface 配置负载均衡](#使用-admin-interface-配置负载均衡)完全一致,仅改为使用配置文件进行 ProxySQL 初始化配置。 + ```bash + docker compose down + cd - + ``` -> **注意:** -> -> - ProxySQL 的配置保存在 SQLite 中。配置文件仅在 SQLite 不存在时读取。 -> - ProxySQL **不建议**使用配置文件进行配置更改,仅作为初始化配置时使用,请勿过度依赖配置文件。这是由于使用 **_ProxySQL Admin Interface_** 配置时,会有以下优点: -> -> - 输入校验。 -> - 可使用任意 MySQL Client 进行配置更改。 -> - 更高的可用性(因为无需重启)。 -> - 在使用 [ProxySQL Cluster](https://proxysql.com/documentation/proxysql-cluster/) 时将自动同步至其他 ProxySQL 节点。 +
+ +
\ No newline at end of file diff --git a/media/develop/proxysql-client-side-lb.png b/media/develop/proxysql-client-side-lb.png new file mode 100644 index 0000000000000000000000000000000000000000..46e664a3d289aead9f78f98a573596dff4e0e03a GIT binary patch literal 649420 zcmbS!Wn2?%+cyr75@}FcKsrQe2F#$5kZuH(2I&T;mr1J#ND5L?f+AfKLpr2mAl;o~ z>^-O6&-3ZI#{GW6A8cnF`9JFPrM9LrIVmG49v&XKs>-c9cz9&2czDD?#Am^8GLjj+ zz>hN?ca(476?8H$;^DF5souJ-=WDSt?h|)kKVIa-$8beYfBg2tIvuz6XwfNxr~K8| zmKMYjI_KE!Z-qTdHPU~?3psoCIsrl7g)3eC(W?5X)B4Ikb0gr$3(Z&3Bs>lE5o+`M zD~#t^TR#r&uJ{P=41|D~k{x!sf56ei zT#pfZME}*7&Oii6h*=A{X6FBkov=InGg)-|ln49If$CmC9wP*(%i;gsz0TCz1e}fn z|Jeu+PDe-(X~^Y{|3AMu-9G^N{>!sL1V{n-RA$cpH=F{8A&6W(-I4y6Ee5odP>bjm z^8fwKsbqtgbrk=<{7N1#yKfaoG}Ecp|6lo}gnlFXFTY}>1KaRb7}@h4Bs)NAe=mIPDYDMm!92zPU2*T2pHVvWr%{)9+o+Mi zYLNpfXHY71KG)W$a>Sw+#n`VUBwiK^lLZE#w9jGb=_y3t>Ut`3lo|imN+~FxhB5N? zmpd)48aOxU$Gg?7ly{F%{)7j;SB$Eg9XMX*FbZm~M_E-P9B=tnYM88> zFjeV2Wv;QnbePm~=40B2BI84$3}=#}t0xE}zm#(GbDY9vmEE=~nfm3f z;+XS!;LcQg$=SGA(y$DnpQw9n250vTXq58qb4sR_Duo%VYpvy*!|IB?zxd1PysZ^M zjoJvT)}o)HV*S7MemzEZw<_fJS8ZXOXH5(~m0O@1qzGDp4cvpALib_Z1g)2*9khfs z8w_ILxnlp6)Z!WBUz(f!-uB%hen?n|FKr-dQcZC{w%vUFh=192W=KH#&~J~>fF{_y z9C<>W|91 zLo@v#}ZU`?DHpkgGdJqa@^&? z(P7e~$)fR7h#mW9Zuso?=Gmx+N8)Rbn;kj!uKYfmT^#HXUw*N+EsIM;GM?SN;oT)k zd@|Pg2RXEAxcy>F1Wfwl*8_rITkDQ;e!d|*m$S?Zy~kEwCK3} zFgpne7Gk^F`urdMSZZL*MNVVPKhdk)R0(Zpp6#Ppz9>O2R^YGtmvfB5QO}|cNjYMl zARf1nTSmOoWcMAr6a0n-x4kSDi8>qp?&xS&j5+Y9j={Zrp*A)(3G^eJtQTRnap!}FhlyuUqNyNS818W zbj5~LkEPllNXd~K6Z>_n2(iF6$}*0*d2sXao|cuHiWE6hmf>M;Uv7RGSl>`K3-yPN z@Bv~yrW@YW?v4Xl7GFqN2i1F}PN9d1WP)^3*yG;keIC=sl}j!%pQv~E`-`ccA@-Ez z$Cp0NQnqHXXDRqlyUTxjHR&clpc-?Em7kIP6nH4;H1_%O)jyKfQUVjYbnncJlSs*= z+qXewuhT3-{P9fca$)Vsc^;aq`lorG<7be&A?mJmuC=-&E7w$J|8xTW4;4-!#*(z2+aZmtP) zS@WiXx)hWSpF+RM=~Qk?4_bzxSF>mbsR7Mg7J4rv{vnOgle#CXRB?=GiZ-= z>Zfmr)Xw3w%W!Y%?0G)KW7*ZO*LH6Fv75?PIe6~=OKyj^?(wiodgl{HGA%oL;>HKC z2EyLd+lP)VeLoyX$O|v$jcqh*{D)FTH>@@*wfxl?r8Gs(%rv`PteW_}-u??XpB2ANGg%Em3v9 zD4a4fGCs^~%{Ca7h`gJ0TYZpx3QCHZrw(+x`G+v(@jZ7WaC~2LkDKcczpt`?KG>Pw zNy^@0`LT#75qdr8=4`RX{U2fYztX<(AVWGN6#uF{`-6BALdvV{ zxPaY`AxgiEfLKh`3K?5VM`K%kEwgrST(*74t^3`O|1eYfzGw)ws*mBDPom_2I`8O> zjz8qPcb754G;8f|931Sg5=5fIPXWH~saOepu(6~_{_s?f6b>PM>%IEYxhwGg3aVFf zZ#1au<{AT0;4hXQzwQADzkNI&JdZ^11kX^~H*sKbd}-fMeM8Do)<_Pg>4n_|cB8Gk zyZZ*FpTOLKoR5LtU>aOdFI7yA<&A62Rc~`Q=XR}?JcojN4HZV1MoybH*{-mUt~UBz zWiNpchf^CZ?M%DlNz3i}`uYwnB1)&oSS1}87-Mmp7wspo{14M&sb=RJ^=R%Ce4s4_ zZZcH{et2i)>C*k54O^_4H=ftB+X$`Zm5;jI&Ff9ayV| zk64@yT8^lAjMyD^eP=wkC3ey++R$$ltr@Pa)$M}``*=3lOG<>)`&bKY5Xt^~K zaV#Xuxb(B9mTy2|S;VGIF-y_YTf$TL34j#fgRKWJTzd(C#TpE0`LDPqK_uJ?L#d6TPHOL!7DCp{-$<{U}{;5 zfa@!jQ_DiDRr8njLp#=?oc<>VHB_p-y(Su(k6@yN{0ao`YCnwV5vEm34`ZnmKAOx;0ZR<+bOj8^EGKFPneH#}nd8()$*zqDuO393YSiq0iaQzcaqn>+9LHQa(o&EZP(W=)d-}|#Jy4`( z?`DN4Qm~P+mLlW_2ytF2$_>6lJ1wT2XwjDBnRueHAT>>v1BI+&xwfJee37OhwlP@? zqb@AFEVo1@x{;}yHot+ID-KqqVUN;+x9(T$e4XA=!{ib3fIa6ux<0+fDJ3oOFllY* z)vMGE4GroBBA$s~6!nGSiDVjyn|pB;E1Xmw+lOmhs@7;-RvJ@eKtW&RcJ=E|JW&Gh zRv?wZu_y9q+mLnta)*cU)`XFxcj0o4 z(JO}KIpyzf$etfzOo#}0u#@6uCSF?k99+YZ-Y9U(?FhBwFuzeWx%s{{{LCrTy^Sm^ zB0~5dtzJhbC#NZaG6u{3v4%M8a&$vJ4dJ40of)F&7}r9tYz+lu5GLRjCLVz}!pL3d z>4{!6p;LYYJ0aw6K*WrHbv!WIkirBQ5aCt=B|`ouyf+XR&AIMV@jin27jMp(7KE9z z9XOq-K%0jyv+mD}K3o$>L)G|*=po-y% zB5yA{P=g8S#i3`HV5uJ<+uNdta{|^|k8?Ta<``x49}ulCyddui4s@!v7W;CUKMW7P zM`q(6U&ND=91!ORpHj z0z?Bef+99X)-G#bu6{ajO!tF$+MEV%QA!tN3PLqh+C!HlJ{ zpi08JMlY_$aCG4)OJ3q^r@VB<`AUyQXUuJjRik78lIpDC-sgetjpFuncyJlgbL8ZT zjPe$1jwOaiek|&uv}YiMRB;tMoT7dMO*-$B`BV_Q_SY8IUfmW62|gE=Y?g8+9E3q| zQn)ucc9%JvvIuq|d5h28_7p%<-i+5Ys>_Wo7a&jRhPEjz!(M(lk$B*GWd9E)GtZyR zb9}XXXs0#ZrcYEWa$&(}SBe$jWpJa6?+D;5$=I~pmM{Az4#wz8;uaQZIF~BDg9*R( z>*U9Y$=+3CUDpP~9urfx_6A{SJ#2MwW_d!syt7TU`|5~*8HAOc9;(NMQCj&3z z{1HUfOTQ?T+B@!lX_3fwX!yd$hCiQ7o%Edf=h<;PI1nu|y&9r-jz6|hsgrKGK5q|k zN2p@}nZI{C{8(9)@-Pcq%_dZ2L2qZYx;MVwtR(28&&;W^g_v!NcY|5i@<|x z5U-$qg^O-J3$;07LblzKQxr&Bo_MZ^$w4$eo0tD!m%khf#DGljJlp*4Pn-H_8P{_S zxYH?3)Y;J0GCltB4~MOfR4ueh1O^Y}3H|NMA>gwiM%_L|G*0!QQ&*sf#^(uG^|p3)nwfixY=o%QDBrxto0GvgS!B?G)fal7VvENKd~N)K=+8VY$RwHtPC*#L2bD$XzX&PvMn6 z89^vP+2R4*P#Kl%_c+`)93>NE5H2_-U2THTd{gdWKLZgbX+K#p6!n@4uo)yek+=3P z$g~|#WPy8WLHW;4JiOtluwgOGr*;{rj7944nQ!hNG7=L#MSK$v^D|&LZ^!NkL6I@U z;{WhNjjZHd%zX}%C3~Cc-Bdt<4qB1gP4jm7^00chb}gf5(KVTY#q@}5u<{uRWwtqc zVHPVH>tM~mDZ+YE;m>AeWz6gsv7GyA!vGY9o(!u1Zp%fsO=BIS9PaKF8Txs@8Fntw z!`%rwcd=h#2G|Z#fhYuk4sLf#bDME1c0aLRvbWh`%n(YJ&`*5Z_Zje;)NzLc6xN9N z^%r8kD-IrTu9wNr71+;C_}DRbZ?=_V&Dd36kIrAXc=6@b)YP-C@(~hH<`$Tj#>vFghmih6 z@5Ei*CDKwmMs5(bfJ{UYN*BXCs>STALzvkS2J0m|WNa8`J;8RNWC>D56 zPmc;dVpgDS{SEN%!;<{CarISUZTWuRO;yh}v|sb64(k~RIrY$f42Ge!W+z;9|BI#K zTQ&0cO`rW}7KUUf6Ofw~LmOW)F{Qoz>W^SF1Y7P)fSoiFPxx>mLHIElU?)^Uf*urR z$!^DJWvhpzoRo*+!GDpqA8%xdy3NU2uh#}&20BqjDPsx5htnT3Qx9+&U(fanqG$le z>Q*6s(z`|*Lz$OxV_dyU;A&-8t*Xo}l)su9yYUFdMAD8d=FFVfgb(>GK2H~u>r+ay z&xnRFS#Et@2-poxTmCF7>CR{auskOmn&>a+o0v|Xp@*AeUXWRKm05d)`qOAr!w>Pm zntX%VBRzjBMccM!c<)3|NAg6VGkcV$k5FQ8)n;6la&bW^xlAvpE;>@RG~^&2BOHzI zcKuDk|BGdLO3C{i_6~ShJ$}0H*WVBjA8T42nJT<6we(bKKRIA9BF?+bu9~*3N!0jG zeS#8;bRC)6`Ur?;EK;uq{>LdVscuN=wtcvO^J?s&kl8oku`;Vtq3|d{#!oL{mBj5Q z$8&MM4YD@t^DZxT8f_Th{-k-RP=)Z5saVCXsr{V!&&?b#kno&!9Z_lP93dJbi1hdt z|5hDm`ccf#Dlib*JL!g{WzwUuu}|$vk6>R2=SrO;&DSv+8s}TY#`q%E1Yt}&<}F;7KC6#&&pe3@1)Ie zdVofmlbo%RSWKPWc#tVUB+%K(cg<3dkMi`Nv6-5LXP;&l^3>oCNgTs>ZcH*J;!y26u{p;4p&fl{|DVI_ia zt(1%p(>q<}V6&HX$AKCl=*ptii-lo_EV|CUZzV>|Cm+>TvJc3e=z!?I zBp~;QQ`-)nQ3FqpVSkLs|0#J2&}D_pg1(i7aOzTyFLWO!; zn+}liT?Uoc_wIH_M@L^^Wi7xEh==j|n&H1Q#qC*g{43Hid2g(z$x@hEOo>Q)zHpP!Dy9Z5xzX47-P|bSt<+5U z7gP1;Pq2Q-tnO@cb2A6IuheRpgN!6~OTlmUZ4(u(N*6{PS|VSM%jhdvg+uJ|4j*Y* zFfX(2M!o3l6pxq#fUcNBJ6J&|Momaa^^~REV(!lep3__FeKMvjJ1y^H{E252Q@?un zI0fwG+8j9|BYJD%tKQ~oLUI`v7GA71tb?=)x_O}nBWI`(!9zmX5(Yc`IsJ#KF2*2K z7D|^C#VMyzitw$)=2>mTFQjeJ192+$&tL0~zpY|({fN%CLaYynBc|2F8WpDG-LeHX zc|MtSPphe;!7HH1#!D30muzx)SE_#6dqm$Kx8oiV)IMQcE-ET|S_JH+f63L!qPfg- zuv9BZ#_;eE>QJOP!Z3-=qqaQ5YTPllZk_DonHhM`8=L7Kt%#4V_#6-dcYf_)EoUIH zj}g-2&{o{VmnD%a^71v5zacw7Utgz>n3$qrHwo1;;?RYd2qbiAAuc7(VL|UKPn0q| zq66*LJ=EV56j^zTOBGn3YoJZ#t(F`;RCq_C8;YBrAluRHyJ?SDT<^P53}C_vX**Je zYShx(Wu<&go$A_`VIjTy1SUdJTs_;Li5dsmCN7xoR|n+giYfq{O$xSh=`VGY+AM1( z^pM55U3U%e;mV9+np$twwP3<2!DBV%%VDq@LN!?*#LQDeM1g=j>-HPj?eVZB5-}b2 z;WBv%R`kq52%4m)sJ!sywS-pyZ4!Sy!p3(cdC9i8mGB#t%FX7*mx$R^xBJAy0AhY= zXSC;pgE(uYdQH7(y5BXtJfXBi$JXRh_dQ^7gw|Oj$hBBs-RpbCt>q#EA#k9>ip{)< z8`dA?3(N)Mbmyr;guUHvjPjaVvYLghl!HXftd0@4!%V+qokx{?dw~XbK^1M_N>H3oP>?ihr2)Gl#?#F z`VSD9yn?ujSG-q3+HQe(nM6#F9i&;36{MlxYJgQeeuB>=6I%}= z*=m>oR%$HJ6@IUAI(9o6_|C`aR+>hSa|Wm z8Hf;VTvBL|Wre7V^qe4knqK%xPN+b)Xg7mtA#?ady|PkqK^8!_JWf# zRWf|!7H(T=0P>oMMH2T#l9mp6IpJK1C5~=>_+e6|%_xoLi$zy-s{Z9TkZTwvkU1~U ze*Ppj7mI1HU4pT5LT2{|vB~M`5@S#b`tlKA8C=x7cZZ$)Vpe_lj@nJ8S<6_p42^+Y zUdXEO6@~I^-iasQhPHo%yaK_=>O{c_@r)At;_Ax@1oY}R3sJ^J)fQn0fr&s=u#vFb zs#Nv+!wG)hu@NuHQ)r?!+D;19}u=$ z>Lw+7Cnht;K9lOT%$mZ+w&4uC9qrBSJ}$3JEjKFS(1(SL3Lh?ls#hp%{sU3dJ9XrR zYGrxo>$QT4Fnda%lQh65Pl0yRk+HGAJp=z%DmE&C-M31ovox$;`YxxEN=`6Ws?{tc z5@^0sd9u8?-&lHG*@RvD3ef(}N)~FOkdv*2sx~&-Jik?HyK30chw=xtwKAJ!yUPU- z+{&*Aav#~kDK3eiWZ>ohs|Xm?W|EIt%}gGFVR|?Pi{09L8Ug6n2Tu;am2$) zXDaL$#I-yqeqZwqB|9Y2kX3Iw6k{?Rmyt+H}(_)@x=Q$YYm8J<8xwPLW zg^#lxnQ0`4+;2x8&zQNaV1EI+0i$ELOMNfZChq7!|A%-$muUIGQJY~9DP>2Hzd(}%<5qSgJG)Pt9Z6! zu5WA#)P2aKU^f=hUccT^8o9{8hs+yArHY8=T{82olLcG1HnOf4@t6ah#xb+&T(3qS z433{SmqM5A_fSMGtndo|(@7$B9UJM}^2Ml;r}Vr;kn>2KIh9e=<|Jp%I&-fc*u=LL zTY}mnB|P8cwquIc+mNr~Qo1|@913rwZcpO>s&hoLj)w#yUqm3EPSLXp#aJITuQz?m zN@m`skq#!R7;=Qgmk+UaKhwXzj$&4g@+l zLKb!+AS0Q=&m;O?Cr}NvoC&8U`FY#Qdd9qHIVdIK&{=j#A`@QB*IiUDB4O!kk{8me z6FuhLy6GO%sio1h78!KOyK3(7(<{Zf)r7CTs*5%cwO*ZgSg^7LF^yIlk5k#fVfQzr z$k{0b>%>Vu2R$@y%5i-XP=521TRZh?6Gc2|XT2n587v_XY_ zs!oAF`ZyNXS}pPUxufpFTU|F*6jTOV)HlkaE1Gemp{oK{#KdS90pM@5N5q@+Kb=*v znnNkPVkwkS*h7y>dgzthF}&Q}e{r0m%$9lML#Yy0bowc0pFgMx(sfc;T!}mBysZhd zcymvlbxmfad&qxQ8jECZd3w#I+v!ucl)+{LoO9}Vevq-+243UEt!{Q@{ zK_@WYSq0F!X!*SsqH!Su+h;ILt#TyU+?<|5jSn*TuWvII>nA!8sQq?AKXk)mM_ zfy_Q^o}9G$cxh$_2|yR{PM>I1w6dz#kk-Fe+N|dkPQJ80AA4sAzh|!Hz7-Ed@Ba@6-GS+);NanLC999T^8PinGmuo2G zwcntq2FX_PF*eBZNXaRrDZyqhGv(X8;5QP6smrWBFY)DlgFTTLRw@>jj-)Xs0(apk zt{6t8#f2uSfj4S3`lV0SM){1yr98pc}3kqpGaaaWDN>Bh*+DQp^;;NRz z<}e9Hl&w5H#Q^A{XH>(;L7`(&a|Dr0-yO7Zo5ftn^z?LeGO=OJSt24%Il4~8MPD`uFF>DH5px@p_OAyJDiwl(|daTkJtF&e`Q(; z8Ed^XP+UBsw9ALx=jF`*7;ULIKBC#7X%z#> zxYLf_k}N{cy1uH$9ETW6zd&qpb$fMHHVvqE0Zc6i)w&M~wMXtNzN>_ys5h3G%7gQt zyqgAuySEYhq4@HF*F9PNwQngauj2bYh9!{c1(y{>v*mgGa!YXKTE$(e@&T$OtNG;O ztop{#`AZL#;ViZ_oZjZUFL_rdLNhxEdvzlyju#Yrwili&_Vy*Uxu^&1Hzhk3hMHpL z63qq*7e)wPPplbXzSh3za8;0#0j(*kcYSC;>HalWsgJQkH_=ssNV3n-U;hjm{F@U4 z`B1lwGMx|S<_O#`Ur}JIoWR7#`J;%e_YewQ`irmf%>k%&l{qX-U#C-6Mhw75h*~CT zJZcZTR;p&!t(UeUmD)S+f4*_KUpI9->dEhBu9LxVumQ@Z(<$KW1Dqac~!b8<4J`S}~zNrqr!LZ(e`v)%Njo@PbaG{n`^jiQ2`t z3l;l!JK~BKJv2hLQKFm8wc$b2n2DY8+e3lyHPnRMk+N3AZe)PoEnDSnvMZeMFcQ#P z(F~>?Zs;%8K7amv+2X^b+qfz@ZYtf=|D9>2iEJ}W*L>XOfLY?u<^y3_#Bbw+va!VL zTZ5=ln?E0y{$?i1SPg(trB7uyaw6oUwg~<4i_O|#>8-bFPZ!EtZtuw--7VT(@<<0s zXZrZ->jXD8hPeODDg4dd{{#bNWf5`DT1)D%ZFD*6^0XN_ynHJq_VJDn7ga?>VuGjzN)u*o%*Dpfud-!(H4>U zCWS4@N8UFk{VT%81G9@1_3IHYT1Kb5j7xBh%=9eEgUy>$ysXi+piI#8mADLfN~`jE zX0Jw_Tx!#NqbzDv4dmeeEfN52SaG0ZwaLuKTv-EoP#x#LtY0+0EjbC4U|lEj1zfV4 z!~cA()|ra@nkFC?tZ!V)Ij}$@H>4%0oNmEy0c}0G605wP&Pv}i96c&etC?y5;t-Rj zG2Diq(nu-w>I+c`iEj^=ib6rv5VTW*<^A4x)oZNjVS?n^nL+4lj=m5$q1@R*~h8lEiEeNC@2QK zxOrFyWBROc5#kZdfDnxIagtlV75M{?mpHD-GRTUcR5UC+Z-XLEy6{a#u2D#W2vl4` z9-|uVG!nIX>l8Spn}!h= zi2!Mn-bCq9r+4w|XuC^+Rj85Wk-TfGf|t9!Kq3sA31_n0(Ss3;7^GhHO$@G7KDt}! zZ=ne-$jU6jAs?Xaq@7eu=AY={W;%ll@OW1w?Qa=4M*H6N7j{ptj`X*~HsI`l9!-vG zKlAs4rY%EX_Ow|aEhF2^}`7w7ordK@elq>c9)e>Sm&{n(!9`$XM7DhLAAh?DT5*{x{MhnxOh-0{QQ zu-_rV+I^=tE@ebNyC!sG1thY$znKL-@N{C~<%iddYNz%fx277WCC0=|aQ9pVgKl>~ zxLHp|d2cE(1(QQtS#YSQk%(T4Lw=JR%;ych5C51Yd!#8VApz>63l|nl56}33#CkC5 zo`$*SZ4L9S4=>6O^&_Y21BpGI);gAgZs&f(>)@KK**RN&-ppxS_Y zg=G>2c5||lO^w+0sV-!9v$;dQV7FIcWmDb4kD`;ph_HnfyqoNUknq5DI%wzafHv-Q zsdhe$Q!6<4+u408qujcc$Y6RP8~olOGuw_Vt=rO+3w{UqHj^uF(m~|fcD-cP^jC71 zIolh~*yeVM5RL_8OhxEsLoAvC67K%W?d@{M!b78kLFSAFPe^fPQj z+3wyxV&>3L$$o$0na162ClaT?lQ-7egoWXtllvQ~E;*bZo1Ww3 zlHOGQ-&*t4GCJ%(y#Rkt4|;=$S?7H>-?IKT^%j`UI8?u@{ntvEtu3~(WFcU-2V15Z zuk5%VvRzv)&fOKDwNkZ2Q=VtpQ$pg&Tz2`$0-d%HaJcOl&^=CIB6vkchS7dfs+u6u zwCX}8?!mJy9_@?J0-pnp5Jvva(7K($S|*x?^;ZDYKhuraF1B;b_CV7_zB-Xiq#UQH z8e~-3w8QrBilW0YFJ4Bg+aPx_6L0x$_nN>#<$?)q%gV5vva#@j%idY^0gv|6N0V-J zDlWL|2gHKl95ol1m_qC8uNx77XcpCH+1%+9e8t=1aI<|N`?CxQm#Qaneoge@-j5<- zaHe7Qsd>9Te!g7l5y`9J^r>XV)P}n;{g2*pbG7h-M6|Rc> zjh}%XPCT6DcY|oScbc^ zM$9|pV4HBcDsI&qAZTn4$dGS)UnoiHayuE9YO!|uq}yDq8XTwczy=5y>8e^xQkH(C z)U9-#$a+^T9S@-*EjukY`3sD##=EI{FwM1~-DOM+H*ek~dm0`V)(GZ| z_g?Ag+yz248nF0gtzaQwH54QS5z-_j)v^8`Di2M0e!XKzWJT5Z+MKEAx6T0byJ%2} z+d)ePQD}p~bWHm+NCT|@thv49 zbUpQ}qmNTa|6$Sm7aN_ClILn?z|qLc7NqU`JUu<9Zu%_hclk_y)a$z7ah^Q}Hw>p$ zPu2MlYR$LwO$T7V@Yl}cWmu@aLs2W}&xYr86MH+p zk82p5uyd}0w)&G&H5f2v2(n#F!4)}z0QLUD_d_S=njvW?tqrN?q2DxqnES|z9a(Ju z8ajBLRidRUV{BsOBAi*f+b|ToRW7;6=vNldojCjq3?8pwrfT(#zYW4dNdMf0_;Y&Uff;F(4)6IJzDv=7!P2L9Y(>F88|GghASNGrttmZ9w)sh*BGm~L}B+JCrS z8<Y`q40Js@l)WJr+UQu^Ct zeSNa5M7`%=SUqEC8-!;|*zha?>3SUafcGtcL?7PC8g`Jf&O4OT;_gEG3RJADU%=`l z2KX&QYKQhNS&99o%;{vhpuzxqF1hjW_{QvbsyOs!mkqWPwK}Ep(lv3ukJaGgqmFW; zIZWV!Cbz3`J6UoDyIVtPQ;G?x+JNaDmTMCVAu7xVIiZ}!wFQT75{ecfvYM3uk!^0i z7%tE3a{m5{7?=;+{OtjIPWgXgvHCp0{uB3=z>r=lGnDmDGpYlt8wETQSV+mp%J~;W zO;{w3t$b~Bi|eWrsD1G$LZMT_f0SC#dDI?zsXJV;F9J6UEt&9JGT4yP%FQ^1X3s)q zCpU+NjLw}u|E-FZkkUvHX!e0z&*5{QS2c#Uyb{$1_Eh8M;VIqcguomSdeCO8s?7$Q z6zi4Iun+_yVx8}kTmhn=K8KtbT%L{6t{gDAEf#i00MJL$CDe1rISdC1rMvfhT2t3aj&ZflhRVnf09^~ULU!cTtebAk)S zt@dnZJx82b5Ag70b=S7xzT%KcfQ=ZifhKUZt)bt zwsojy+)-b?A`PDf$6T(Ite~iMb&}to?UD7p6+|RqvPYnnfo=a6J`TR;^+S# zNsow(R6ZhS$2wiM##}_q+bZM1h92C;19lb|jB91QY86iaJ%c2`;GSvPdWE zmcL(>N<&XXIgL;*vthEa)1?CvQCS|Bu3$!2McoFPik5F;co=s1i>0uZ(RjJai{Ce~ zluj4-!!_Mk;YtKTCIewFM-9N^RlDk==tlv~@DyL$-|6nxdBN;jb2qH!E9IGK=FR8< z{BYMPKWHZ;U%}k)Fo>j>;5i)2VxNApG=FIzzZ(I1OD?lqg$wlCLYzlz5`Ji zIpcu4`Q#J5-L3Alr61!escJxH_&;!@P1gw(Etc6TAssELRkeI}DJrhTLi&&g!5Y=O zpRn#4OyA5G6Dcw%11l%xm{h9Cw23wNrRJ%p&;fpI@(eV!8<&+@@KouG7bOt?1YWV~ zszGr9kAGyKuT%A0)xyGP*%tmNwY1Rxi$7|gbcijW>%-zrP>y=-T+3YM5Uz4 z=2{6O2Q}>Qa4I_Jd47yAHlq_4q6e?I`D+2ywsNYO{Asiw8$$o%$V);q0n9rL7B)wK zJpP=ig59=e$zTEa&T2*R;kqLj2m~mDfsqQ@iSb{;8GBILrNZuar|I#FKjgkiV^j^E zK4V#x`F5_cnL+OIk!46AXpS(XSpH!~+z!MAOpf#yf%JTfV)ZMo&xs)1sgBkMoX;x= ztH1%qvFSqqK5bo8X}|shc5&u4PwGJ}JZ~Bh=z7`tq;y2U`A=t$IjGD^p^7Ee^#T;B zfMm9+%@=mH?oa)x{aSd?sQyqs8VEZLB?ACeuy4npYk)nuHF(!20$(A>&2tDXzyD&Kj+3BKo|LAgre!@@s8=C z{7U2WabAKN?xsC@;9yGe#@~vQ(Te+yp(g_n^@HYAKQhV16Z}At8Mtd+Z;QR?W4eN0 z?+Gi|d<(H%-yCyuj=>ULU@~gnZ+E29yMB7l!g3sUS<^QPwy zCJ)Iy#2%8c(=~)g2%&p0M>N(AeHf15-8vp+kVdPBNZG9i2(acx zQ=Thmtbg|GnTu;M$jyOn+<~y@w}G)O@2SXfPg2}dw{q*g0p&1VPJfRCA~Z^_2wuK( znbu!hc!4c=1ZCB5$s9>G9lMr-LF-L-Mm0OkJqB>IILL?tD3In~LxMS>pe)J`=nNLgX( zP3l1->WEJ)4QUG#Uhr!{ zbI81tpDinv#V&rlwzroXh@F3SJ#!Hx5_iVSj+X)b#Ko5zr^Pq@utVPe4g^}#VA6Iv z1syMexxFl&0fc7nIu)Shc4@2mew8D(m;qWbrXBe$Ho(kXCi(Q-Gc0Uj>*X4{X6>B)2^-Uq)Uo=7v$=o)j3S0je?aKHJV7JhLjBP7L-Q zwwO)kWTnNoO`@%S5^3b|0V`pS6SvN0CxFU1nN5c1R8J3h>#5=gBkt$c>|{a5wKdi} zfFKz}<-L}b#P@Ck5pWbpOIE@H>l*=B{Ba~HXI6JtVS!u_;RB@16 zFO2WT`*)sWCqH!nFG7oZ57%|UK)+-5lNg}Xh7t~QEUK5$ z??Su6I%V0Iqq)3NG_lgPmeBermzuYhB5VEoqGX8R3HsC7>eUa}=Y0pRKEmD34W0v~ z&OT@G(JP}?3!lM$6$$6r*)3jja1hrMnbl7VZ}Ky(DE4oG;g&&3{Cnn-Wq z1h&1@q3us()_pz`wwLXtdK(BM2_u#LrZ~9x_a1*xN)b@b*D1EE-iOlYaFs0!vytQq^;X3R?7$Eq z@fiJAqr?8*n$00PRdb-UyCgY<=KwOiN;`=eaNjk`0PQblL-r*>0oDO<{kvn$^~UgjPkSEj6T%7bS>f)cv1Ny4ctXwh=m(559D zO{H+4zvnk6*5HO$-jrCEwBRuOEftXC`js}^`1CIyyjB1oB6M{(P$p4Qva z`=MXtH;xvZkTQ)*>3;fHX%my|;KP~}6p5cEZc#4N2ao9KX9HvGmXw(>a2?nlqBo;E zk6a_=3Qxj^j)N#JI6V=qx{TG&XO8nN;$UTSGMq;35$rtt@bEA$IoZNI{{HY%h~;6a zMIpnuizMRwJIV|B!1mi!CrPk^yI8Ni@j)_FT0C@d3i+;e%XaylwMe92$s~A?Cay4b z+Lg{oz&CJoekP`?Q6MFp2;KL?K>j}J6cTOssBRGsI+D+xE141k;t^OkVv5D0K2$Qc zPLWvalj!&3OZpdQ$C_AbQ|t{Bhhm)WOD_|K5k{K&vEc4EB6b47%}Vf3;8M$6Xmr=v zfz+YvNAJlaEYNzuXr=CcE{R zSefA~t`vcJ3^+yX3}hB~(pXmqgacrI?ruo{Be;l9azkS$OVM_@R>ZaBld=V;(f7@% zYS}lin*WdEz0gbGv(E{3WN<-3@L&_X9MpM}lFZSv*RIj@_4O4|*DUP%_pEx4;(zEH z0XSsvfgULf@Tmt18wNL;P1$x|3bLI7xJjVolZchL1($?3 z0|1qIOX9RSXCTsm0vs1CjP#0=lEJx-W&4my*h+H?srPqwQK5jc0BU}+e`}wLtRRl zvM}pgT3vY61yT z*4WKqEDtXY-j+>|Ro zS!pDe*isgc)NlfJnT@uMrhW(Sh>B_Cb=H-IflEo1$PPFA1Nn0fMFJ%yIeWm#?&?RcNhW zlj;_1>KN|^771FYaDAx~c)E7b&gkYleqSh8>YzH^(8Bh*(ubKUMbF|-Hb1;aD3u{N7zmJtcTi-$!U@ynzPBEDvEc>^MV;r@Y7Uok+18}GX{L6|^7 z^Qg+~Yog}6`^G)7dAOU8h(BVJ1tYh9zWFVecNiUur+I$OSth@<2|1p6@w5s4iW