ProxySQL Cluster - malongshuai/proxysql GitHub Wiki
ProxySQL集群功能正处于试验阶段,未来的版本和本文描述可能会有所不同,请知悉。
<前言>
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
未来会添加更多的表。
要支持集群监控,ProxySQL引入了几个新的表、命令、变量。
有几个和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_username
和admin-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_rules
、mysql_servers
、mysql_users
、proxysql_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_rules
、mysql_servers
、mysql_users
、proxysql_servers
配置的远程同步。默认值3次,最小值0,表示永不远程同步,最大值1000。
(译注:例如,各实例监控mysql_servers
配置并做校验码检查,如果某实例和本地配置不同,当多次检测到都不同时,将根据load to runtime
的时间戳决定是否要从远端将mysql_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
:注释字段,可随意填写
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表的内容)
正如其它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) )
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
:不生产校验码
-
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配置从内存数据库中持久化保存到磁盘数据库中
新增了3张统计数据表到stats
库中。
该表显示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
,使该节点被选举为该类配置的可信任同步源。
表定义语句:
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目的,但未来可能会作为远程实例的健康指标。
目前未使用该表。
<关于带宽>
在上述描述的架构模式中,每个ProxySQL节点都监控集群中其它所有节点,这是一个完整的点对点网络。
为了减少集群中网络带宽的使用,各节点不会一次性交换所有的checksum列表,而是交换一个由各节点上所有版本、所有checksum值结合生成的全局checksum(译注:是每个节点都有一个全局checksum,而不是所有节点共有一个全局checksum)。当全局checksum改变,将检索该全局checksum对应的checksum列表。
通过该技术,200个节点的ProxySQL集群中,如果每个节点的监控时间间隔为1000ms,每个节点的进/出流量只需50KB的带宽。
由于每个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
。
- 支持MySQL组复制(add support for MySQL Group Replication)
- 支持Scheduler(add support for Scheduler)
译注:这些都已实现。
以下是未来可能要实现的Cluster不完整特性列表。这些特性目前都还未实现,且实现后有可能会与此处描述的有所区别。
- 支持master选举:ProxySQL内部将使用master关键字替代leader
- 只有master节点是可写/可配置的
- 实现类似于MySQL复制的功能:从master复制到slave。这将允许实时推送配置内容,而非现在使用的主动pull机制
- 实现类似于MySQL复制的功能:从master复制到候选master
- 实现类似于MySQL复制的功能:从候选master复制到slave
- 将候选master定义为法定票数节点,slave不参与投票
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,因此很容易监控并探测到不同的配置。
谁负责向所有节点写入配置
目前,ProxySQL集群使用拉取(pull)机制,因此当探测到节点自身需要重新配置时,会从拥有最新配置的节点处拉取配置到本地并应用。
你想如何实现选举?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节点可能暂时会无法获取新的配置,例如网络问题。但是,当该实例探测到新的配置时,它会自动去抓取新配置。
跨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.
注:回答和问题不对应。所以,改为和回答对应的问题。
如何引导启动一个ProxySQL集群
很简单:只需让proxysql_servers
表中多于一个节点即可。
ProxySQL集群中的其它节点如何知道有新节点
无法自动知道,这是为了防止新节点破坏集群。
一个新节点在加入集群时,会立刻从集群中拉取配置,但不会将自己作为可信任的配置源通告出去。
要让其它节点知道有一个新的节点,只需向这些节点的proxysql_servers
中加入新的节点信息,然后执行load proxysql servers to runtime
即可。