ProxySQL Cluster - malongshuai/proxysql GitHub Wiki

ProxySQL集群功能正处于试验阶段,未来的版本和本文描述可能会有所不同,请知悉。

Preface

<前言>

ProxySQL是一个非中心化代理,在拓扑中,建议将它部署在靠近应用程序服务器的位置处。

ProxySQL节点可以很方便地扩展到上百个节点,因为它支持runtim修改配置并立即生效。这意味着可以通过一些配置管理工具来协调、重配置ProxySQL集群中的各实例,例如 Ansible/Chef/Puppet/Salt 等自动化工具,或者Etcd/Consul/ZooKeeper等服务发现软件。

这些特性使得可以高度定制ProxySQL的集群。但尽管如此,这些管理方式还是有些缺点:

  • 需要且依赖于外部软件(配置管理软件)
  • 正因为上面的一点,使得这种管理方式不是原生支持的
  • 管理时间长度不可预测
  • 无法解决网络分区带来的问题

基于此,ProxySQL 1.4.x 版本尝试支持原生集群功能。如前所述,这个功能还处于试验阶段,未来可能会发生一些改变、优化。

目前,ProxySQL有两个主要的组件实现ProxySQL集群:

  • monitoring(译注:这是集群监控组件)
  • re-configuration(remote configuration)

这两个组件中都有4张表:

  • mysql_query_rules
  • mysql_servers
  • mysql_users
  • proxysql_servers

未来会添加更多的表。

Monitoring

要支持集群监控,ProxySQL引入了几个新的表、命令、变量。

Admin variables

有几个和Cluster相关的变量,它们是Admin变量,意味着修改它们需要使用load admin variables to runtime使其生效。

1.用于同步的变量

  • admin-checksum_mysql_query_rules
  • admin-checksum_mysql_servers
  • admin-checksum_mysql_users:如果有数百万的users,则建议禁用该特性且不要依赖于它,因为它会非常慢。

这几个变量都是布尔值。当设置为true(默认值)时,ProxySQL在每次执行load (mysql query rules | mysql servers | mysql users) to runtime时都会生成一个新的配置校验码(configuration checksum)。如果设置为false,则不会生成校验码,新的配置内容不会传播出去,也不会从其它节点同步配置到本机;

2.集群认证凭据相关的变量

  • admin-cluster_usernameadmin-cluster_password:该凭据用于监控其它ProxySQL实例。需要注意,这个用户/密码必须是admin-admin_credentials中已经存在的,否则将会连接失败。如果没有定义集群凭据,ProxySQL集群将不会做任何检查。

3.检查时间间隔/频率相关变量

  • admin-cluster_check_interval_ms:定义校验码检查(checksum check)时间间隔。默认值1000(即1秒),最小值10,最大值300000。
  • admin-cluster_check_status_frequency:该变量定义做了多少次checksum检查后,就执行一次状态检查(status check)。默认值10,最小0,最大10000。

4.同步到磁盘相关的变量

在远程同步配置之后,通常最好的做法是立即将新的更改保存到磁盘。这样重启时,更改的配置不会丢失。

  • admin-cluster_mysql_query_rules_save_to_disk
  • admin-cluster_mysql_servers_save_to_disk
  • admin-cluster_mysql_users_save_to_disk
  • admin-cluster_proxysql_servers_save_to_disk

这几个变量都是布尔值。当设置为true(默认值)时,在远程同步并load到runtime后,新的mysql_query_rulesmysql_serversmysql_usersproxysql_servers配置会持久化到磁盘中。

5.是否要远程同步的变量

由于某些原因,可能多个ProxySQL实例会在同一时间进行重新配置。

例如,每个ProxySQL实例都在监控MySQL的replication,且自动探测到MySQL的故障转移,在一个极短的时间内(可能小于1秒),这些ProxySQL实例可能会自动调整新的配置,而无需通过其它ProxySQL实例来同步新配置。

类似的还有,当所有ProxySQL实例都探测到了和某实例的临时的网络问题,或者某个MySQL节点比较慢(replication lag, 拖后腿),这些ProxySQL实例都会自动地避开这些节点。这时各ProxySQL实例也无需从其它节点处同步配置,而是同时自动完成新的配置。

基于此,可以配置ProxySQL集群,让各ProxySQL实例暂时无需从其它实例处同步某些配置,而是等待一定次数的检查之后,再触发远程同步。但是,如果本地和远程节点的这些变量阈值不同,则还是会触发远程同步。

  • admin-cluster_mysql_query_rules_diffs_before_sync
  • admin-cluster_mysql_servers_diffs_before_sync
  • admin-cluster_mysql_users_diffs_before_sync
  • admin-cluster_proxysql_servers_diffs_before_sync

分别定义经过多少次的"无法匹配"检查之后,触发mysql_query_rulesmysql_serversmysql_usersproxysql_servers配置的远程同步。默认值3次,最小值0,表示永不远程同步,最大值1000。

(译注:例如,各实例监控mysql_servers配置并做校验码检查,如果某实例和本地配置不同,当多次检测到都不同时,将根据load to runtime的时间戳决定是否要从远端将mysql_servers同步到本地)

Configuration tables

Table proxysql_servers

proxysql_servers表定义了ProxySQL集群中各ProxySQL实例列表。该表的定义语句如下:

CREATE TABLE proxysql_servers (
    hostname VARCHAR NOT NULL,
    port INT NOT NULL DEFAULT 6032,
    weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0,
    comment VARCHAR NOT NULL DEFAULT '',
    PRIMARY KEY (hostname, port) )

各字段的意义如下:

  • hostname:ProxySQL实例的主机名或IP地址
  • port:ProxySQL实例的端口 (译注:这个端口是ProxySQL示例的admin管理端口)
  • weight:目前未启用该功能。定义集群中各ProxySQL的权重值
  • comment:注释字段,可随意填写
Support for config file

proxysql_servers的配置项可以从传统配置文件中加载。

以下是传统配置文件中定义proxysql_servers的示例:

proxysql_servers =
(
    {
        hostname="172.16.0.101"
        port=6032
        weight=0
        comment="proxysql1"
    },
    {
        hostname="172.16.0.102"
        port=6032
        weight=0
        comment="proxysql2"
    }
)

但注意:ProxySQL只有在磁盘数据库文件不存在,或者使用了--initial选项时才会读取传统配置文件。

  • 配置文件暂时还不支持该表。
  • 因为该ProxySQL Cluster功能仍处于试验阶段,不会自动从磁盘配置文件中读取到该表中。

(译注:也就是说,目前阶段,不支持在配置文件中配置proxysql server表的内容)

Table runtime_proxysql_servers

正如其它runtime_表一样,runtime_proxysql_servers表和proxysql_servers的结构完全一致,只不过它是runtime数据结构中的配置,也就是当前正在生效的配置。

表的定义语句如下:

CREATE TABLE runtime_proxysql_servers (
    hostname VARCHAR NOT NULL,
    port INT NOT NULL DEFAULT 6032,
    weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0,
    comment VARCHAR NOT NULL DEFAULT '',
    PRIMARY KEY (hostname, port) )

Table runtime_checksums_values

runtime_checksums_values表是目前第一个不基于内存数据库中的runtime_表(译注:换句话说,没有checksums_values表)。

该表的定义语句如下:

CREATE TABLE runtime_checksums_values (
    name VARCHAR NOT NULL,
    version INT NOT NULL,
    epoch INT NOT NULL,
    checksum VARCHAR NOT NULL,
    PRIMARY KEY (name))

该表用于显示在执行load to runtime命令时的一些信息:

  • name:模块的名称
  • version:执行了多少次load to runtime操作,包括所有隐式和显式执行的(某些事件会导致ProxySQL内部自动执行load to runtime命令)
  • epoch:最近一次执行load to runtime的时间戳
  • checksum:执行load to runtime时生成的配置校验码(checksum)

该表的一个实例:

Admin> SELECT * FROM runtime_checksums_values;
+-------------------+---------+------------+--------------------+
| name              | version | epoch      | checksum           |
+-------------------+---------+------------+--------------------+
| admin_variables   | 0       | 0          |                    |
| mysql_query_rules | 5       | 1503442167 | 0xD3BD702F8E759B1E |
| mysql_servers     | 1       | 1503440533 | 0x6F8CEF0F4BD6456E |
| mysql_users       | 1       | 1503440533 | 0xF8BDF26C65A70AC5 |
| mysql_variables   | 0       | 0          |                    |
| proxysql_servers  | 2       | 1503442214 | 0x89768E27E4931C87 |
+-------------------+---------+------------+--------------------+
6 rows in set (0,00 sec)

注意:目前只有4种模块的配置会生成对应的校验码。

  • LOAD MYSQL QUERY RULES TO RUNTIME:当admin-checksum_mysql_query_rules=true时生成一个新的mysql_query_rules配置校验码
  • LOAD MYSQL SERVERS TO RUNTIME:当admin-checksum_mysql_servers=true时生成一个新的mysql_servers配置校验码
  • LOAD MYSQL USERS TO RUNTIME:当admin-checksum_mysql_users=true时生成一个新的mysql_users配置校验码
  • LOAD PROXYSQL SERVERS TO RUNTIME:总是会生成一个新的proxysql_servers配置校验码
  • LOAD ADMIN VARIABLES TO RUNTIME:不生成校验码
  • LOAD MYSQL VARIABLES TO RUNTIME:不生产校验码

New commands:

  • LOAD PROXYSQL SERVERS FROM MEMORY / LOAD PROXYSQL SERVERS TO RUNTIME
    从内存数据库中加载proxysql servers配置到runtime数据结构
  • SAVE PROXYSQL SERVERS TO MEMORY / SAVE PROXYSQL SERVERS FROM RUNTIME
    将proxysql servers配置从runtime数据结构持久化保存到内存数据库中
  • LOAD PROXYSQL SERVERS TO MEMORY / LOAD PROXYSQL SERVERS FROM DISK
    从磁盘数据库中加载proxysql servers配置到内存数据库中
  • LOAD PROXYSQL SERVERS FROM CONFIG
    从传统配置文件中加载proxysql servers配置到内存数据库中
  • SAVE PROXYSQL SERVERS FROM MEMORY / SAVE PROXYSQL SERVERS TO DISK
    将proxysql servers配置从内存数据库中持久化保存到磁盘数据库中

stats tables

新增了3张统计数据表到stats库中。

Table stats_proxysql_servers_checksums

该表显示ProxySQL实例的checksum信息,以及checksum相关的状态。

表定义语句:

Admin> SHOW CREATE TABLE stats.stats_proxysql_servers_checksums\G
*************************** 1. row ***************************
       table: stats_proxysql_servers_checksums
Create Table: CREATE TABLE stats_proxysql_servers_checksums (
    hostname VARCHAR NOT NULL,
    port INT NOT NULL DEFAULT 6032,
    name VARCHAR NOT NULL,
    version INT NOT NULL,
    epoch INT NOT NULL,
    checksum VARCHAR NOT NULL,
    changed_at INT NOT NULL,
    updated_at INT NOT NULL,
    diff_check INT NOT NULL,
    PRIMARY KEY (hostname, port, name) )
1 row in set (0,00 sec)

各字段意义如下:

  • hostname:ProxySQL实例的主机名
  • port:ProxySQL实例的端口
  • name:对端runtime_checksums_values中报告的模块名称
  • version:对端runtime_checksum_values中报告的checksum的版本
    注意,ProxySQL实例刚启动时version=1:ProxySQL实例将永远不会从version=1的实例处同步配置数据,因为一个刚刚启动的ProxyQL实例不太可能是真相的来源,这可以防止新的连接节点破坏当前集群配置
  • epoch:对端runtime_checksums_values中报告的checksum的时间戳epoch值
  • checksum:对端runtime_checksums_values中报告的checksum值
  • changed_at:探测到checksum发生变化的时间戳
  • updated_at:最近一次更新该类配置的时间戳
  • diff_check:一个计数器,用于记录探测到的对端和本地checksum值已有多少次不同
    需要等待达到阈值后,才会触发重新配置。
    前文已经说明,在多个ProxySQL实例同时或极短时间内同时更改配置时,可以让ProxySQL等待多次探测之后再决定是否从远端同步配置。这个字段正是用于记录探测到的配置不同次数。
    如果diff_checks不断增加却仍未触发同步操作,这意味着对端不是可信任的同步源,例如对端的version=1
    另一方面,如果某对端节点不和ProxySQL集群中的其它实例进行配置同步,这意味着集群没有可信任的同步源。这种情况可能是因为集群中所有实例启动时的配置都不一样,它们无法自动判断哪个配置才是正确的。可以在某个节点上执行load to runtime,使该节点被选举为该类配置的可信任同步源。

Table stats_proxysql_servers_metrics

表定义语句:

Admin> SHOW CREATE TABLE stats.stats_proxysql_servers_metrics\G
*************************** 1. row ***************************
       table: stats_proxysql_servers_metrics
Create Table: CREATE TABLE stats_proxysql_servers_metrics (
    hostname VARCHAR NOT NULL,
    port INT NOT NULL DEFAULT 6032,
    weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0,
    comment VARCHAR NOT NULL DEFAULT '',
    response_time_ms INT NOT NULL,
    Uptime_s INT NOT NULL,
    last_check_ms INT NOT NULL,
    Queries INT NOT NULL,
    Client_Connections_connected INT NOT NULL,
    Client_Connections_created INT NOT NULL,
    PRIMARY KEY (hostname, port) )
1 row in set (0,00 sec)

当执行show mysql status语句时,显示一些已检索到的指标。字段意义如下:

  • hostname:ProxySQL实例主机名
  • port:ProxySQL实例端口
  • weight:报告结果同proxysql_servers.weight字段
  • comment:报告结果同proxysql_servers.comment字段
  • response_time_ms:执行show mysql status的响应时长,单位毫秒
  • Uptime_s:ProxySQL实例的uptime,单位秒
  • last_check_ms:最近一次执行check距现在已多久,单位毫秒
  • Queries:该实例已执行query的数量
  • Client_Connections_connected:number of client's connections connected
  • Client_Connections_created:number of client's connections created

注意:当前这些状态只为debug目的,但未来可能会作为远程实例的健康指标。

Table stats_proxysql_servers_status

目前未使用该表。

Bandwidth consideration

<关于带宽>

在上述描述的架构模式中,每个ProxySQL节点都监控集群中其它所有节点,这是一个完整的点对点网络。

为了减少集群中网络带宽的使用,各节点不会一次性交换所有的checksum列表,而是交换一个由各节点上所有版本、所有checksum值结合生成的全局checksum(译注:是每个节点都有一个全局checksum,而不是所有节点共有一个全局checksum)。当全局checksum改变,将检索该全局checksum对应的checksum列表。

通过该技术,200个节点的ProxySQL集群中,如果每个节点的监控时间间隔为1000ms,每个节点的进/出流量只需50KB的带宽。

Re-configuration

由于每个ProxySQL节点都监控集群中的其它实例,它们可以快速探测到某个实例的配置是否发生改变。

如果某实例的配置发生改变,其它实例会检查这个配置和自身的配置是否相同,因为其它节点的配置可能和本节点的配置同时(或在极短时间差范围)发生了改变。

如果比较结果不同:

  • 如果本节点version=1,则从version > 1的节点处找出epoch最大值的节点,并从该节点拉取配置应用到本地。
  • 如果本节点version > 1,则开始对探测到的不同配置进行计数。
    • 当探测到不同配置的次数超过cluster_name_diffs_before_sync,且cluster_name_diffs_before_sync大于0时,找出version > 1且epoch值最大的节点,并从该节点拉取配置禁用应用。

同步配置的过程如下:

  • 用于健康检查的连接,也用来执行一系列类似于select _list_of_columns from runtime_module的select语句。例如:
SELECT hostgroup_id, hostname, port, status, weight, compression, max_connections, max_replication_lag, use_ssl, max_latency_ms, comment FROM runtime_mysql_servers;
SELECT writer_hostgroup, reader_hostgroup, comment FROM runtime_mysql_replication_hostgroups;
  • 删除本地配置。例如:
DELETE FROM mysql_servers;
DELETE FROM mysql_replication_hostgroups;
  • 向本地配置表中插入已从远端节点检索到的新配置。
  • 在内部执行LOAD module_name TO RUNTIME:这会递增版本号,并创建一个新的checksum。
  • 如果cluster_name_save_to_disk=true,再在内部执行SAVE module_name TO DISK

TODO

  • 支持MySQL组复制(add support for MySQL Group Replication)
  • 支持Scheduler(add support for Scheduler)

译注:这些都已实现。

Roadmap

以下是未来可能要实现的Cluster不完整特性列表。这些特性目前都还未实现,且实现后有可能会与此处描述的有所区别。

  • 支持master选举:ProxySQL内部将使用master关键字替代leader
  • 只有master节点是可写/可配置的
  • 实现类似于MySQL复制的功能:从master复制到slave。这将允许实时推送配置内容,而非现在使用的主动pull机制
  • 实现类似于MySQL复制的功能:从master复制到候选master
  • 实现类似于MySQL复制的功能:从候选master复制到slave
  • 将候选master定义为法定票数节点,slave不参与投票

Q&A

What if a different configuration is loaded at the same time on each of the proxysql servers, which configuration is the one that needs to be "propagated" to all other nodes ? The last one?

如果不同节点在同一时刻加载了不同配置会如何,最后一个才生效吗

目前还未实现master和master选举的机制。这意味着多个节点上可能会潜在地同时执行load命令(就像是多个master一样),每个实例都会基于时间戳来检测配置冲突,然后再触发自动重新配置。

如果所有节点在同一时刻加载的是相同的配置,则不会出现问题。

如果所有节点在不同时刻加载了不同的配置,则最后一个配置生效。

如果所有节点在同一时刻加载了不同配置,这些不同配置会正常进行传播。直到出现冲突,然后回滚。

庆幸的是,每个ProxySQL节点都知道其它每个节点的checksum,因此很容易监控并探测到不同的配置。

who is writing this configuration to all those nodes?

谁负责向所有节点写入配置

目前,ProxySQL集群使用拉取(pull)机制,因此当探测到节点自身需要重新配置时,会从拥有最新配置的节点处拉取配置到本地并应用。

How are you going to implement election ? Raft consensus protocol ?

你想如何实现选举?Raft协议吗

关于选举,正在实现计划中,但应该不会采用Raft共识协议。

ProxySQL使用表来存储配置信息,使用MySQL协议来执行对端健康检查、配置信息的查询请求,以及使用MySQL协议实现心跳等等。所以对于ProxySQL来说,MySQL协议本身相比Raft协议要更多才多艺。

What will happen if for some reason one of the nodes will be unable to grab the new configuration in an event of re-configuration?

某些原因下,如果某个节点无法从远端抓取新的配置会发生什么

配置更改是异步传播的。因此,某个ProxySQL节点可能暂时会无法获取新的配置,例如网络问题。但是,当该实例探测到新的配置时,它会自动去抓取新配置。

What about crossdc ? what will be the best practice , having a cluster in each DC?

跨DC的ProxySQL集群是否实现?最佳实践是怎样的,每个DC一个ProxySQL集群吗

ProxySQL集群没有边界限制,因此一个ProxySQL集群可以跨多个DC,一个DC内也可以有多个ProxySQL集群。这依赖于实际应用场景。

唯一的限制是,每个ProxySQL实例只能属于单个ProxySQL集群。

ProxySQL集群没有名称,为了确保ProxySQL实例不会加入到错误的集群中,可以让每个ProxySQL集群采用不同的集群认证凭据。

Could be a nice feature to somehow replicate the configuration crossdc but prefer traffic to the backend server that is closest to the local proxysql server. I am doing it now using weight.

For this specific case I think it makes more sense to create a different cluster for each DC, as configuration will be different.

How is a new proxysql going to join the cluster ?

注:回答和问题不对应。所以,改为和回答对应的问题。

如何引导启动一个ProxySQL集群

很简单:只需让proxysql_servers表中多于一个节点即可。

How will all other proxysql server know there is a new node ?

ProxySQL集群中的其它节点如何知道有新节点

无法自动知道,这是为了防止新节点破坏集群。

一个新节点在加入集群时,会立刻从集群中拉取配置,但不会将自己作为可信任的配置源通告出去。

要让其它节点知道有一个新的节点,只需向这些节点的proxysql_servers中加入新的节点信息,然后执行load proxysql servers to runtime即可。

⚠️ **GitHub.com Fallback** ⚠️