
后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载导读本文深入解析 ProxySQL 高可用集群ProxySQL Cluster的内部工作原理以本仓库 doc/proxysql_cluster/proxysql_cluster_working.md 为骨架结合 include/ProxySQL_Cluster.hpp 与 lib/ProxySQL_Cluster.cpp 的源码实现展开。你将掌握集群节点模型ProxySQL_Node_Entry/ProxySQL_Node_Address等核心类的职责、节点列表加载与监控线程生命周期、基于全局校验和 模块校验和的配置变化检测机制、以及diffs_before_sync/save_to_disk等关键变量如何驱动配置从发现差异到拉取 → 校验 → 应用到运行时 → 持久化的完整收敛闭环。本文面向已了解 ProxySQL Cluster 基本概念proxysql_servers表、cluster_*变量、Admin 接口互连等的读者聚焦内部如何工作这一层。一、ProxySQL Cluster 的核心类模型Cluster 功能在代码中由ProxySQL_Cluster类体系承载全部定义于 include/ProxySQL_Cluster.hpp实现位于 lib/ProxySQL_Cluster.cpp约 6000 行。整个体系围绕 5 个核心类组织。1.1 ProxySQL_Cluster集群主控ProxySQL_Cluster是集群功能的门面与协调者include/ProxySQL_Cluster.hpp#L594。它持有与每个模块对应的pthread_mutex_t update_module_mutex如update_mysql_query_rules_mutex、update_runtime_mysql_servers_mutex、update_mysql_servers_v2_mutex保证同一模块不会并发同步集群凭据cluster_username/cluster_password以及本节点对外广播的admin_mysql_ifaces在admin_mysql_ifaces_mutex保护下读写一组cluster_*_diffs_before_sync原子整数变量与cluster_*_save_to_disk布尔变量控制每个模块的同步触发阈值与持久化行为nodes成员ProxySQL_Cluster_Nodes即全量节点表的封装每个模块的pull_module_from_peer()系列方法如 lib/ProxySQL_Cluster.cpp#L1177 的pull_mysql_query_rules_from_peer负责实际从远端拉取配置。此外类内还定义了一组被 Admin 接口拦截的CLUSTER_QUERY_*宏见 include/ProxySQL_Cluster.hpp#L71-L239例如-- 运行时 MySQL 服务器列表的校验和查询 PROXY_SELECT hostgroup_id, hostname, port, gtid_port, status, weight, compression, max_connections, max_replication_lag, use_ssl, max_latency_ms, comment FROM runtime_mysql_servers WHERE statusOFFLINE_HARD ORDER BY hostgroup_id, hostname, port这些查询由ProxySQL_Admin拦截文件头部注释明确说明其结果集既用于生成校验和也用于拉取配置后计算期望校验和因此必须保持相同的过滤与排序条件——这是校验和对比能够成立的前提。1.2 ProxySQL_Node_Entry单个节点的信息容器ProxySQL_Node_Entryinclude/ProxySQL_Cluster.hpp#L288代表集群中的一个节点持有hostname/port/weight/comment等注册信息以及解析出的ip_addr活跃标志active在load_servers_list中被批量标记一个checksums_values结构体内含每个模块的ProxySQL_Checksum_Value_2admin_variables、mysql_variables、ldap_variables、mysql_query_rules、mysql_servers、mysql_users、proxysql_servers、mysql_servers_v2以及 PostgreSQL 侧的pgsql_query_rules/pgsql_servers/pgsql_users/pgsql_servers_v2/pgsql_variables节点级的global_checksum全局校验和一个环形指标缓冲区ProxySQL_Node_Metrics *metrics[]长度PROXYSQL_NODE_METRICS_LEN 5include/ProxySQL_Cluster.hpp#L16用于滚动记录相邻两次采样的节点状态指标。1.3 ProxySQL_Node_Address线程间传递的节点地址ProxySQL_Node_Addressinclude/ProxySQL_Cluster.hpp#L271封装hostname、port、uuid、admin_mysql_ifaces与可选ip_addr并包含线程句柄thrid。它的典型用途是作为监控线程的参数每次新节点入表时load_servers_list会构造一个ProxySQL_Node_Address并传给新创建的ProxySQL_Cluster_Monitor_thread。1.4 ProxySQL_Cluster_Nodes节点集合管理器ProxySQL_Cluster_Nodesinclude/ProxySQL_Cluster.hpp#L395是节点总表核心是std::unordered_mapuint64_t, ProxySQL_Node_Entry * umap_proxy_nodes——以generate_hash(hostname, port)生成的 64 位哈希为键。它提供load_servers_list(SQLite3_result *, bool _lock)加载proxysql_servers结果集Update_Global_Checksum()/Update_Node_Checksums()接收监控线程拉回的校验和结果集并落到对应节点一组get_peer_to_sync_module()遍历 map选出版本大于 1 且 epoch 最大的节点作为同步源。值得注意lib/ProxySQL_Cluster.cpp#L4585 的get_peer_to_sync_variables_module采用数据驱动的统一实现用一张ModuleConfig表把模块名、对应的diffs_before_sync变量、校验和字段访问器、是否携带双校验和V2 类模块同时返回mysql_servers_v2与runtime_mysql_servers两份校验和统一映射起来取代了历史上每个模块一套独立函数。1.5 ProxySQL_GlobalVariables 与 ProxySQL_Checksum_ValueProxySQL_GlobalVariables聚合当前实例各模块的 checksum、epoch、version代码中即GloVars.uuid所引用的全局对象并提供对外访问入口监控线程注册节点时使用的正是ProxySQL_GlobalVariables::uuid。ProxySQL_Checksum_Value及其子类ProxySQL_Checksum_Value_2include/ProxySQL_Cluster.hpp#L241除version/epoch/checksum外_2版本还增加last_updated、last_changed、diff_check三个时间/计数字段——diff_check即连续检测到差异的次数是diffs_before_sync阈值机制的核心输入。二、节点列表加载与监控线程初始化2.1 触发时机与数据来源两个时机触发节点列表加载ProxySQL 实例启动在 Admin 接口执行LOAD PROXYSQL SERVERS TO RUNTIME。届时proxysql_servers表的最新记录hostname, port, weight, comment按hostname, port排序被取出结果集交给ProxySQL_Cluster::load_servers_list后者直接转发给ProxySQL_Cluster_Nodes::load_servers_listinclude/ProxySQL_Cluster.hpp#L656。2.2 load_servers_list 的六步流程ProxySQL_Cluster_Nodes::load_servers_list的完整实现位于 lib/ProxySQL_Cluster.cpp#L4380流程与文档描述完全吻合加锁pthread_mutex_lock(mutex)随后调用set_all_inactive()lib/ProxySQL_Cluster.cpp#L4347把umap_proxy_nodes中所有节点标记为 inactive遍历结果集对每一行取fields[0..3]作为 host、port、weight、comment用generate_hash(h_, p_)计算键查 map若键存在则对该节点执行resolve_hostname()、set_active(true)并更新set_weight()/set_comment()若键不存在new ProxySQL_Node_Entry(h_, p_, w_, c_)插入 map 并set_active(true)随后创建ProxySQL_Node_Address并pthread_create一个 detached 的ProxySQL_Cluster_Monitor_threadlib/ProxySQL_Cluster.cpp#L4404把节点 host/port 作为参数传入删除 inactive 节点remove_inactives()lib/ProxySQL_Cluster.cpp#L4355把仍处于 inactive 的条目delete并从 maperase解锁。由此得到一个关键语义每个集群节点对应一个常驻监控线程且线程只在节点首次入表时创建之后该节点每次LOAD PROXYSQL SERVERS TO RUNTIME只会被更新属性而不会重复开线程。若某节点从proxysql_servers表中被删除下一次加载时它会被标记 inactive 并连同其监控线程通过GloProxyCluster-Update_Node_Metrics(..., NULL, 0)的哨兵调用判定节点已不存在见 lib/ProxySQL_Cluster.cpp#L402一起被清理。文档给出的整体流程图mermaid可归纳为三、监控线程的工作循环ProxySQL_Cluster_Monitor_thread入口位于 lib/ProxySQL_Cluster.cpp#L170是每个节点的专职监控者。它启动后先通过proxysql_startup_gate_wait_for_runtime等待插件生命周期完成随后进入while (glovars.shutdown 0 rc_bool true)主循环。每一轮循环按以下顺序执行。3.1 版本核对SELECT version线程以get_credentials()拿到的cluster_username/cluster_password连接远端MYSQL_OPT_CONNECT_TIMEOUT 1秒然后发送版本查询。在启用PROXYSQL40宏的构建中实际发送的是SELECT version, proxysql_plugin_set_hash宏PROXYSQL_CLUSTER_PEER_IDENTITY_QUERY见 include/ProxySQL_ClusterPluginHash.h#L37除了比对版本字符串还会比对插件集哈希确保双方插件集合兼容lib/ProxySQL_Cluster.cpp#L244-L258。版本/插件集不一致打印告警日志关闭连接并硬编码sleep30 秒后重试lib/ProxySQL_Cluster.cpp#L283一致进入注册与同步阶段。3.2 节点注册PROXYSQL CLUSTER_NODE_UUID版本匹配后线程发送命令PROXYSQL CLUSTER_NODE_UUID ProxySQL_GlobalVariables::uuid ProxySQL_Cluster::admin_mysql_ifaces其中uuid来自全局对象GloVars.uuidadmin_mysql_ifaces在admin_mysql_ifaces_mutex保护下读取lib/ProxySQL_Cluster.cpp#L264-L269。该命令让远端把当前节点登记为集群客户端从而实现双向识别。3.3 全局校验和比对SELECT GLOBAL_CHECKSUM()线程发送SELECT GLOBAL_CHECKSUM()结果集交给ProxySQL_Cluster_Nodes::Update_Global_Checksumlib/ProxySQL_Cluster.cpp#L4442。该函数在 map 中定位本节点取出结果集第一行的 64 位校验和v与node-global_checksum比较相同返回false本轮只做轻量检查不同覆盖本地保存的node-global_checksum并返回true表示至少一个模块的配置发生了变化需要继续拉取模块明细。3.4 模块校验和明细SELECT * FROM runtime_checksums_values当全局校验和变化时线程执行SELECT * FROM runtime_checksums_values ORDER BY namequery3lib/ProxySQL_Cluster.cpp#L192把结果交给Update_Node_Checksums→ProxySQL_Node_Entry::set_checksums。runtime_checksums_values的表结构定义在 include/ProxySQL_Admin_Tables_Definitions.h#L43CREATE TABLE runtime_checksums_values ( name VARCHAR NOT NULL, version INT NOT NULL, epoch INT NOT NULL, checksum VARCHAR NOT NULL, PRIMARY KEY (name) );set_checksums的处理逻辑对应文档的详细流程图对每个模块执行若结果集中存在该模块记录用远端值更新本地version、epoch、last_updated比较本地模块校验和与远端校验和相同则diff_check 1连续差异计数递增不同则更新校验和、置last_changed为当前时间并把diff_check重置为 1若本地自身模块校验和 远端校验和即自己已经是最新则把diff_check清零若结果集中不存在某模块记录resultset NULL分支对每个模块置last_updated now并按本地校验和 自身版本校验和决定diff_check置 0 或自增。3.5 同步判定diffs_before_sync 阈值set_checksums之后进入同步判定条件严格按文档描述串行执行cluster_module_diffs_before_sync ! 0为 0 则跳过该模块本地模块version 1version 为 1 表示模块配置刚从初始状态加载通常不参与抢占式同步own_version 1 || local epoch own_epoch即实例刚启动、或远端 epoch 更新local diff_check cluster_module_diffs_before_sync只有四个条件全部满足该模块才进入真正的拉取阶段。这就是文档所述差值累积到一定次数才同步的去抖设计diff_check必须连续超过阈值默认 3 次避免瞬时抖动触发频繁的全量同步。3.6 选择同步源最大 epoch 节点同步源选择由ProxySQL_Cluster_Nodes::get_peer_to_sync_module统一走get_peer_to_sync_variables_modulelib/ProxySQL_Cluster.cpp#L4585完成。算法遍历umap_proxy_nodes过滤条件模块version 1择优条件epoch 最大的节点且要求其diff_check diff_threshold记录该节点的 host/port、IP以及对带校验和的模块其校验和值。选出的节点即事实来源source of truth。V2 类模块mysql_servers_v2还会额外携带runtime_mysql_servers的次级校验和用于双表一致性校验。3.7 拉取配置、校验并应用选中同步源后线程用get_credentials()建立新连接调用ProxySQL_Cluster::pull_module_from_peer如 lib/ProxySQL_Cluster.cpp#L1177 的pull_mysql_query_rules_from_peer拉取该模块最新配置。关键安全步骤本地对拉回的配置重新计算校验和与同步源返回的校验和比较一致才应用清空本地模块配置表 → 插入远端数据 → 发出内部LOAD module TO RUNTIME不一致则丢弃防止拉取过程中远端又变更导致数据错位。3.8 持久化save_to_disk配置成功应用到运行时后检查cluster_module_save_to_disktrue发出内部SAVE module TO DISK把配置写入磁盘数据库保证重启后依然生效false仅保留在内存运行时重启后丢失。3.9 周期性的状态指标采样每轮循环末尾还有一个独立于校验和逻辑的指标通道详见 3.10 流程图cluster_check_status_frequency_count每轮自增当累计达到cluster_check_status_frequency时清零并执行SELECT * FROM stats_mysql_global ORDER BY Variable_Name结果交给Update_Node_Metrics→ProxySQL_Node_Entry::set_metricslib/ProxySQL_Cluster.cpp#L4482提取Client_Connections_connected、Client_Connections_created、ProxySQL_Uptime、Questions、Servers_table_version五项写入环形指标缓冲区metrics_idx在 0..4 间滚动。这些指标被用于stats_proxysql_servers_metrics统计表以及 Prometheus 指标p_cluster_nodes_dyn_*include/ProxySQL_Cluster.hpp#L362-L384。3.10 完整循环与节流每轮循环结束后计算耗时若小于cluster_check_interval_ms则usleep补齐保证轮询频率受控lib/ProxySQL_Cluster.cpp#L371-L379连接异常时也会按该间隔 sleep 后重连。文档提供的详细流程图mermaid完整描述了上述全部状态核心链路可压缩为四、关键配置变量与默认值集群行为由 Admin 变量控制全部可在GLOBAL VARIABLES中查看与修改在 lib/ProxySQL_Admin.cpp 中解析默认值在 lib/ProxySQL_Cluster.cpp#L5888-L5917 的构造函数中初始化。变量默认值含义cluster_username空字符串监控/同步时用于连接远端节点的用户名为空则线程不执行任何监控lib/ProxySQL_Cluster.cpp#L206cluster_password空字符串对应密码cluster_interface/admin_mysql_ifaces空节点注册时向远端广播的 Admin 接口地址cluster_check_interval_ms1000每轮轮询的最小间隔毫秒实际间隔为该值与单轮耗时的较大者cluster_check_status_frequency10每多少次轮询执行一次节点状态指标stats采样cluster_module_diffs_before_sync3各模块mysql_query_rules、mysql_servers、mysql_users、proxysql_servers、mysql_variables、admin_variables、ldap_variables、pgsql_query_rules、pgsql_servers、pgsql_users、pgsql_variables连续检测到差异的阈值0 表示禁用该模块同步cluster_module_save_to_disktrue模块配置应用到运行时后是否SAVE TO DISK持久化cluster_mysql_servers_sync_algorithm1runtime_mysql_servers与mysql_servers_v2的同步算法选择详见下节4.1 mysql_servers_sync_algorithm 的三种模式enum class mysql_servers_sync_algorithminclude/ProxySQL_Cluster.hpp#L556定义了服务器模块的特殊同步策略runtime_mysql_servers_and_mysql_servers_v2 1同时同步运行时服务器状态与配置Monitor 产生的运行时变更如连接池状态变化也会触发同步mysql_servers_v2 2只同步mysql_servers_v2静态配置仅用户显式执行的配置变更触发同步auto_select 3依据是否以-M标志启动决定——未带-M选模式 1带-M选模式 2。该模块也因此是唯一携带双校验和mysql_servers_v2校验和 runtime_mysql_servers校验和的同步对象。五、从源码看设计要点5.1 校验和是同步的唯一事实整个同步系统不依赖时间戳对账而是以校验和 epoch version 三元组为唯一事实来源。runtime_checksums_values表见 include/ProxySQL_Admin_Tables_Definitions.h#L43保存的就是这三个维度。这也解释了为何文档与代码反复强调拉取配置后必须在本地重新计算校验和并与远端比对——它是防止同步过程中数据错位、半更新状态污染集群的最后防线。5.2 去抖与收敛diff_check 的双重角色diff_check既在set_checksums中单调递增连续发现差异又在节点自身已与远端一致时清零。这构成一个软状态只有差异持续存在超过diffs_before_sync轮次才触发拉取从而容忍单次网络抖动或瞬时不一致同时保证配置最终收敛到 epoch 最大节点所代表的最新状态。5.3 并发安全模块级互斥锁每个模块在ProxySQL_Cluster中都有独立的update_module_mutex多个节点的监控线程可能同时尝试同步同一模块锁保证了同一时刻只有一个拉取应用操作在执行避免配置表被并发写入撕裂。5.4 线程生命周期与故障自愈监控线程以 detached 方式创建lib/ProxySQL_Cluster.cpp#L4403连接失败时解析主机名并 sleep 后重试lib/ProxySQL_Cluster.cpp#L390-L398节点从proxysql_servers表消失后通过Update_Node_Metrics(..., NULL, 0)哨兵调用感知并终止线程lib/ProxySQL_Cluster.cpp#L402对应 bug #1323 的修复。这保证了集群拓扑变化后监控资源能自动回收。六、验证与观测集群的健康状态与同步进度可以从以下入口观测均为仓库中已确认的实现stats_proxysql_servers_checksums()include/ProxySQL_Cluster.hpp#L433各节点的模块版本、epoch、diff_check等校验和维度stats_proxysql_servers_metrics()include/ProxySQL_Cluster.hpp#L434节点连接数、uptime、Questions 等状态指标Prometheus 指标族proxysql_servers_checksums_*/proxysql_servers_metrics_*include/ProxySQL_Cluster.hpp#L362-L384以及pulled_module_success/failure系列计数器include/ProxySQL_Cluster.hpp#L453-L530可用于监控同步成败日志层面ProxySQL_Cluster_Monitor_thread在连接、版本比对、注册、每轮同步的关键节点都输出proxy_info/proxy_warning/proxy_errorlib/ProxySQL_Cluster.cpp#L186-L391是排查集群同步问题最直接的手段。结语ProxySQL Cluster 的内部机制可以概括为一条清晰的链路proxysql_servers表驱动节点地图与监控线程 → 每轮以GLOBAL_CHECKSUM()做轻量比对 → 变化时拉取runtime_checksums_values明细 → 以diff_check与diffs_before_sync做去抖判定 → 从最大 epoch 节点拉取配置 → 本地校验和复核 →LOAD TO RUNTIME→SAVE TO DISK。本文所有流程均与 doc/proxysql_cluster/proxysql_cluster_working.md 及 lib/ProxySQL_Cluster.cpp 中的实际实现相互印证读者可结合这两份材料深入每一处细节并借助第六节的统计表与日志对生产集群进行观测验证。赞分享后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载相关推荐Valdi Renderer 内部机制解析虚拟节点树、增量 Diffing 与原生同步Valdi Renderer 内部机制解析虚拟节点树、增量 Diffing 与原生同步 Valdi 是一个跨平台 UI 框架其 Renderer 承担着元素跨平台UI组件前端移动开发鸣潮自动战斗与刷声骸完全指南ok-wuthering-waves 部署与用法实战鸣潮自动战斗与刷声骸完全指南ok wuthering waves 部署与用法实战 ok wuthering waves简称 ok ww是一款基于图像识别的GUI 自动化计算机视觉RPA人工智能零配置向量生成AnythingLLM原生嵌入器的技术实现路径零配置向量生成AnythingLLM原生嵌入器的技术实现路径 在构建本地知识库系统时向量生成往往成为技术门槛最高的环节。传统方案依赖第三方API服务不仅带人工智能AI 应用RAGAI Agent后端前端上一篇Redis RDB Tools终极兼容性指南从RDB v5到v9的完整解析下一篇IceCubesApp的编译错误快速定位Xcode日志分析技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考