12_ProxySQL配置之ProxySQL_Cluster
备注:文章编写时间201904-201905期间,后续官方在github的更新没有被写入
~
~
注意:ProxySQL群集实现可能会发生变化,因为roadmap(设计规划图)中的所有功能尚未实现。
一、前言[Preface]
ProxySQL是一个分散式的代理,通常建议将其部署在应用程序附近。这种方法似乎可以很好地扩展到数百个节点,因为它被设计为在运行时可以轻松重新配置。
它也允许你使用配置管理软件(如Ansible/Chef/Puppet/Salt(按字母顺序))或服务发现软件(如Etcd/Consul/ZooKeeper)来协调和重新配置ProxySQL实例。
这使得ProxySQL可以高度自定义,并可以在任何使用这些技术的设置中采用,甚至可以通过自制工具重新配置。当然,使用这种管理方式来组建集群也有一些缺点:
- 1)这使得ProxySQL需要并依赖外部软件(配置管理软件本身);
- 2)前一点也意味着这种方法本身不受支持;
- 3)整个管理系统中的任务执行时长是不可预测的;
- 4)没有防止网络分裂的保护;
因此,ProxySQL 1.4.x尝试本机支持群集。但,正如开头已经指出的那样,这些功能可能会发生变化,因为并未实现(roadmap)设计规划图中的所有功能。
目前,ProxySQL集群解决方案中有两个主要组件:
- 1)monitoring
- 2)re-configuration
这两个组件(monitoring和remote reconfiguration)可用于4个表:
mysql_query_rules
mysql_servers
mysql_users
proxysql_servers
将来会添加更多内容,请参阅roadmap(设计规划图)
二、Monitoring
为了支持对群集的监控,引入了几个新的表、命令和变量。
1、Admin变量[Admin variables]
添加了与Cluster解决方案相关的几个新变量。它们都是Admin的变量,这意味着要加载它们,需要LOAD ADMIN VARIABLES TO RUNTIME命令。
1)定义了同步内容的变量
admin-checksum_mysql_query_rules ==>布尔类型变量。当为true(默认)时,每次执行LOAD MYSQL QUERY RULES TO RUNTIME时,ProxySQL都会生成新的配置校验和。如果设置为false,则不会自动传播新配置,也不会从远程节点同步;
admin-checksum_mysql_servers ==>布尔类型变量。当为true(默认)时,每次执行LOAD MYSQL SERVERS TO RUNTIME时,ProxySQL都会生成新的配置校验和。如果设置为false,则不会自动传播新配置,也不会从远程节点同步;
admin-checksum_mysql_users ==>布尔类型变量。如果为true(默认),则每次执行LOAD MYSQL USERS TO RUNTIME时,ProxySQL都会生成新的配置校验和。如果设置为false,则不会自动传播新配置,也不会从远程节点同步。如果您有数百万用户,请禁用此功能并且不要依赖它,因为它可能非常慢;
2)定义凭证的变量
admin-cluster_username 和 admin-cluster_password ==>监视其他proxysql实例使用此凭据。请注意,对username/password也应该出现在admin-admin_credentials中,否则连接将失败。如果未定义admin-cluster_username,则Clustering不会执行任何检查;
3)定义检查间隔/频率的变量
admin-cluster_check_interval_ms ==>此变量定义前后2次校验和检查之间的时间间隔,单位毫秒。默认值:1000 最小值:10 最大值:300000
admin-cluster_check_status_frequency ==>如果大于0,则此变量定义了在每次执行状态检查时,需要执行多少次校验和检查。默认值:10 最小值:0 最大值:10000
在远程同步完成后,立即将新的更改信息保存到磁盘通常是个好主意。这样,服务重启后配置将是已经同步过的。
与同步到磁盘相关的变量:
admin-cluster_mysql_query_rules_save_to_disk ==>布尔类型变量。当为true(默认)时,如果在远程同步并加载到RUNTIME层之后,则新的mysql查询规则也会保存到磁盘;
admin-cluster_mysql_servers_save_to_disk ==>布尔类型变量。当为true(默认)时,如果在远程同步并加载到RUNTIME层之后,则新的mysql服务器也会保存到磁盘;
admin-cluster_mysql_users_save_to_disk ==>布尔类型变量。当为true(默认)时,如果在远程同步并加载到RUNTIME层之后为,则新的mysql用户也会保存到磁盘;
admin-cluster_proxysql_servers_save_to_disk ==>布尔类型变量。当为true(默认)时,如果在远程同步并加载到RUNTIME层之后为,则新的proxysql服务器也会保存到磁盘;
由于各种不同的原因,可能会出现同时重新配置多个ProxSQL实例的情况。
例如,每个proxysql实例都可能监视一个mysql复制拓扑结构,它会自动检测MySQL的故障转移,并且在很短的时间内(可能不到一秒钟)各个proxysql实例都会将最新信息聚合到相同的配置,而不需要彼此同步。
类似地,对于临时的网络问题或处理速度较慢的MySQL实例,当被所有代理检测到时,它们可能会自动避开问题节点。所有代理将采取相同的操作,而无需彼此同步。或者,如果由于复制滞后而导致从属设备滞后,则所有代理将自动避开该节点,并相互独立地执行相同的规避处理操作。
因此,可以将ProxySQL Cluster配置为不与远程节点即刻同步信息,而是在触发远程同步之前等待一定次数的检查(确认)。如果在此阈值之后本地和远程配置仍然不同,则会触发同步。
4)定义信息同步前执行检查的变量
admin-cluster_mysql_query_rules_diffs_before_sync ==>定义出现多少次不匹配的检查时将触发mysql_query_rules的同步。默认值:3 最小值:0(从不同步)最大值:1000
admin-cluster_mysql_servers_diffs_before_sync ==>定义出现多少次不匹配的检查时触发mysql_servers的同步。默认值:3 最小值:0(从不同步)最大值:1000
admin-cluster_mysql_users_diffs_before_sync ==>定义出现多少次不匹配的检查时触发mysql_users的同步。默认值:3 最小值:0(从不同步)最大值:1000
admin-cluster_proxysql_servers_diffs_before_sync ==>定义出现多少次不匹配的检查时触发proxysql_servers的同步。默认值:3 最小值:0(从不同步)最大值:1000
2、Configuration tables
1)表 proxysql_servers
表结构如下:
Admin>SHOW CREATE TABLE proxysql_servers \G
*************************** 1. row ***************************
table: proxysql_servers
Create Table: 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) )
1 row in set (0.00 sec)
该表是配置表,定义了集群中互相监控着的ProxySQL实例的列表。
hostname ==>集群中同伴ProxySQL实例的主机名
port ==>集群中同伴ProxySQL实例的端口
weight ==>集群中同伴ProxySQL实例的权重
comment ==>集群中同伴ProxySQL实例的备注信息
以上信息也支持配置文件中设置:
proxysql_servers =
(
{
hostname="172.16.0.101"
port=6032
weight=0
comment="proxysql1"
},
{
hostname="172.16.0.102"
port=6032
weight=0
comment="proxysql2"
}
)
2)表 runtime_proxysql_servers
表结构如下:
Admin>SHOW CREATE TABLE runtime_proxysql_servers \G
*************************** 1. row ***************************
table: runtime_proxysql_servers
Create Table: 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) )
1 row in set (0.00 sec)
与其他runtime_类的表一样,这是基表proxysql_servers 运行太下对应得表。
3)表 runtime_checksums_values
表结构如下:
Admin>SHOW CREATE TABLE runtime_checksums_values \G
*************************** 1. row ***************************
table: runtime_checksums_values
Create Table: CREATE TABLE runtime_checksums_values (
name VARCHAR NOT NULL,
version INT NOT NULL,
epoch INT NOT NULL,
checksum VARCHAR NOT NULL,
PRIMARY KEY (name))
1 row in set (0.00 sec)
表 runtime_checksums_values 是第一个runtime_类的表,但它不是基表的RUNTIME时的表示,而是记录了LOAD TO RUNTIME命令执行时间的日志类记录表。
它的内容类似如下这样:
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)
注意:
在6个LOAD RUNTIME命令中,只有4个可以生成校验和信息:
LOAD MYSQL QUERY RULES TO RUNTIME ==>如果 admin-checksum_mysql_query_rules 参数为true,则生成新的校验和。
LOAD MYSQL SERVERS TO RUNTIME ==>如果 admin-checksum_mysql_servers 参数为true,则生成新的校验和。(mysql_group_replication_hostgroups表例外)
LOAD MYSQL USERS TO RUNTIME ==>如果 admin-checksum_mysql_users 参数为true,则生成新的校验和。
LOAD PROXYSQL SERVERS TO RUNTIME ==>始终生成新的校验和。
LOAD ADMIN VARIABLES TO RUNTIME ==>不生成校验和。
LOAD MYSQL VARIABLES TO RUNTIME ==>不生成校验和。
新命令:
LOAD PROXYSQL SERVERS FROM MEMORY / LOAD PROXYSQL SERVERS TO RUNTIME ==>将ProxySQL服务器信息从MEMORY层数据库加载到RUNTIME层数据结构中。
SAVE PROXYSQL SERVERS TO MEMORY / SAVE PROXYSQL SERVERS FROM RUNTIME ==>将ProxySQL服务器信息从RUNTIME层数据结构持久保存到MEMORY层数据库。
LOAD PROXYSQL SERVERS TO MEMORY / LOAD PROXYSQL SERVERS FROM DISK ==>将ProxySQL服务器信息从DISK层数据库加载到MEMORY层数据库。
LOAD PROXYSQL SERVERS FROM CONFIG ==>将ProxySQL服务器信息从配置文件加载到MEMORY层数据库。
SAVE PROXYSQL SERVERS FROM MEMORY / SAVE PROXYSQL SERVERS TO DISK ==>将ProxySQL服务器信息从MEMORY层数据库持久保存到DISK层数据库。
3、stats tables
在 stats 库中新增了3个表。
1)表 stats_proxysql_servers_checksums
表结构如下:
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实例,默认6032;
name ==>在表 runtime_checksums_values 中记录的模块名称;
version ==>在表 runtime_checksums_values 中记录的模块版本号;请注意,刚刚启动的ProxySQL实例将具有version = 1的版本号:而ProxySQL实例是永远不会与具有version = 1的另一个实例同步的, 因为刚启动的ProxyQL实例不太可能是真实信息的来源。这可以防止新的加入节点破坏当前的群集配置。
epoch ==>在表 runtime_checksums_values 中记录的模块epoch号;
checksum ==>在表 runtime_checksums_values 中记录的模块校验和(checksum);
changed_at ==>检测到校验和被更改的时间戳;
updated_at ==>此条目最近一次刷新的时间戳;
diff_check ==>一个计数器,用于存放在对与当前ProxySQL实例进行状态监控、信息交互的远程ProxySQL实例(集群中的同伴实例)的校验和与本地校验和进行检查时出现结果不同的次数。当该值达到重新配置算法的阀值时,将触发重新配置。如果同一配置同时应用于多个代理,或者在发生故障转移时代理正在重新配置自己,并且它们很可能在不需要重新同步的情况下对配置进行了汇总,则此功能非常有用。(另请参见参数变量 cluster_*_diffs_before_sync )如果diff_check在增加了很多的情况下却没有触发同步,则意味着远程对等方不是真实信息的可靠来源,例如,version=1。另一方面,如果远程对等机与集群的其他部分不同步,这意味着集群没有可靠的真实信息来源。当集群中的所有代理以不同的配置启动时,会发生这种情况,并且无法自动确定哪个配置正确。这时在其中一个节点上运行 LOAD module TO RUNTIME 命令,将自动"选择"该节点以成为该特定模块的真实来源。
2)表 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实例的权重与proxysql_servers.weight相同;
comment ==>集群中同伴ProxySQL实例的备注与proxysql_servers.comment相同;
response_time_ms ==>运行SHOW MYSQL STATUS时的响应时间,以毫秒为单位;
Uptime_s ==>集群中同伴的正常运行时间(秒);
last_check_ms ==>上次执行检测的时间(毫秒);
Queries ==>同伴执行的查询数;
Client_Connections_connected ==>连接同伴的客户端连接数;
Client_Connections_created ==>同伴创建的客户端连接数;
注意:
所有的状态变量都是由同伴实例检索的,但是只有很少的一部分被监视,以便能够检查同伴实例是否启动、运行和处理流量。
目前,此功能仅用于调试目的,但未来版本将使用这些指标来了解远程同伴的运行状况。
3)表 stats_proxysql_servers_status
目前尚未使用
4、带宽考虑[Bandwidth consideration]
在上述架构中,所有节点都监视所有其他节点。是完全网状的点对点网络。
为了减少网络使用,节点并不总是交换整个校验和列表;相反,交换一个由所有版本和所有校验和组合而成的校验和。如果此全局校验和被更改,则再检索校验和的详细列表。使用这种技术,在一个200个节点的集群中,每1000毫秒相互监视,每个节点需要50KBpb的带宽。
三、重新配置[Re-configuration]
由于代理是互相监视的,所以它们可以立即知道配置的校验和何时被更改了,这也意味着自身的配置也需要更改。如果某个配置发生了更改,则会对照其自身的配置进
行检查,因为远程同伴机的配置及自己的配置可能同时或在短时间内发生了更改。
如果他们不同:
- 1)如果自己的version是1,与找到的同伴的version是大于1并且拥有最高的epoch,则立即进行同步。
- 2)如果自己的version大于1,则开始计算它们之间的检查差异数。当它们的差异检查数大于
clusternamediffs_before_sync 并且 clusternamediffs_before_sync
自身也大于0时,则查找version >1且具有最高epoch的同伴,找到后并立即同步(注意:可能出现检测到的节点和执行同步的节点不一样;即检测到一个的节点,但同步是对另一个节点执行的。这是因为同步是用具有最高epoch的节点完成的,所以所有节点都将聚合为一致的配置。如果在检测和执行同步的中间发生了聚合,那么就会出现这样的情况,但这不影响最后的结果)
执行同步的过程如下:
1)同一个连接在执行健康检测时会执行一系列的类似 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;
2)删除本地配置表。
例如:DELETE FROM mysql_servers; DELETE FROM mysql_replication_hostgroups;
3)将从远程同伴机上检索到的内容插入到本地配置表中。
4)执行一个内部的 LOAD module_name TO RUNTIME 命令,这将增加版本号并创建一个新的校验和。
5)如果 clusternamesave_to_disk is true 为true,则发出内部的 SAVE module_name TO DISK 。
四、研发中的功能[TODO]
- 1)添加对MySQL Group Replication的支持。
- 2)添加对Scheduler(调度)的支持。
1、设计规划图[Roadmap]
这只是与群集相关的功能的概述,而不是完整列表。以下列表尚未实现。
实际实施可能与现在列出的不同:
- 1)主从Master的选举:这里有意选择Master这个词而不是leader;
- 2)只有master代理是可写/可配置的;
- 3)实现从主服务器到从服务器的类似MySQL的复制,允许实时推送配置而不是拉动配置;
- 4)实现从主服务器到候选主服务器的类似MySQL的复制;
- 5)实现从候选主服务器到从服务器的类似MySQL的复制;
- 6)创建一个只包含候选master的法定人数:普通Slave不是法定人数的一部分。
五、疑问即答案[Q&A]
1、如果在每个proxysql服务器上同时加载不同的配置,那么需要将哪个配置"传播"到所有其他节点上呢?是最后一个吗?
master的概念和master的选举还没有实施。这意味着一个 LOAD 命令可以同时在多个节点上执行(拿多主做个类比),并且每个节点都将触发一个基于时间戳的冲突解决方案的自动重新配置。
如果在多个proxysql实例上同时加载相同的配置,那么它们应该自动聚合为一致的配置。
如果是在不同的时刻在多个proxysql实例上分别加载了不同的配置,则最终最后一个被加载的配置将胜出。
如果同时在多个proxysql实例上加载不同的配置,那么这些不同的配置都将开始传播,直到它们因为冲突解决方式不可行而导致无法收敛到一个点为止(聚合为一致的配置)。
好在,每个proxysql都知道其他每个节点的配置校验和,因此很容易检测和监视不匹配的配置。
2、谁将此配置写入所有这些节点?
目前使用的是拉取机制,因此检测到需要重新配置的节点将从具有最新配置的节点中拉取配置并在本地应用。
3、你打算如何实施选举?RAFT协议?
选举的实施是写入设计规划图中的,但可能不是RAFT共识协议。
ProxySQL使用表来存储配置信息,它使用MySQL协议来为查询其健康状况和配置信息的同伴实例执行请求,它使用MySQL协议来实现心跳等等:由于这些原因,在ProxySQL场景下,MySQL协议本身可能比RAFT协议更通用。
4、如果由于某种原因,在重新配置的情况下,其中一个节点将无法获取新的配置,会发生什么情况?
变更是异步传播的。因此,其中一个节点是有可能无法获取新的配置;例如,在ProxySQL开始重新启动时发生了网络问题情的况下。然而,一但环境正常后,当ProxySQL实例检测到它的一个同伴实例有一个更新的配置时,它将自动获取这个最新的配置信息。
5、CrossDC怎么样?在每个Docker中都有一个集群,它的最佳实践是什么?
集群没有边界,因此可以跨多个DC拥有单个集群,或者在同一个DC拥有多个集群,或者跨多个DC拥有多个集群。这实际上取决于具体的使用场景。唯一的限制是每个proxysql实例都必须且只能属于一个集群。集群没有名称,为了确保节点不会错误地加入错误的集群,确保每个集群使用不同的凭证是很重要的。请查看admin-admin_credentials,
admin-cluster_username and admin-cluster_password.
6、在某种程度上通过复制拷贝的方式来配置crossdc可能是一个很好的特性,但它更喜欢将流量发送到最接近本地proxysql服务器的后端服务器。因而,我现在用权重来做流量分配管控。
对于这个特定的情况,我认为为每个DC创建一个不同的集群更有意义,因为配置会有所不同。
7、新的proxysql如何加入群集?
引导非常简单:在ProxySQL集群中至少有一个同伴实例(对等机)在运行即可。
8、所有的其他ProxySQL服务器如何知道有一个新节点?
他们不会自动知道,这是为了防止新节点损坏集群。换句话说,一个新的节点可以在连接后立即提取配置,但不能将自己作为真实信息的来源进行传播。为了让其他proxysql实例知道存在一个新节点,只需在当前集群的任何节点的PROXYSQL服务器中添加该新节点,并执行 LOAD PROXYSQL SERVERS TO RUNTIME 即可。
~
~
完毕!