☰
ProxySQL DuckDB 插件五分钟上手教程:从源码构建到 MySQL/PostgreSQL 双协议接入
2026/10/8 8:16:15 网站建设 项目流程
  • 后端
  • 数据库
  • 负载均衡

【免费下载链接】proxysql

High-performance proxy for MySQL and PostgreSQL

项目地址:https://gitcode.com/gh_mirrors/pr/proxysql
点击查看免费下载

本教程带你从当前仓库源码出发,构建 ProxySQL v4.0 Plugin Chassis 层(PROXYSQL40=1),加载 DuckDB 嵌入式分析引擎插件,并通过 MySQL 与 PostgreSQL 两种客户端协议接入同一个嵌入式数据库。读完本文,你将掌握插件从编译、启动加载、用户配置到持久化与运行期校验的完整实操链路,并理解其底层实现细节。本文主体基于仓库中的 doc/duckdb/quickstart.md 编写,并融合 doc/duckdb/ 目录下的安装、配置、管理、协议兼容、安全与运维文档及插件源码佐证。

背景:什么是 ProxySQL DuckDB 插件

ProxySQL DuckDB 插件将 DuckDB 直接嵌入 ProxySQL 进程,并通过两个独立的监听端点对外提供服务:一个走 MySQL 客户端协议,一个走 PostgreSQL 客户端协议。应用和运维人员可以继续使用熟悉的mysql、psql客户端,而查询实际执行在进程内部的 DuckDB 引擎中,整个过程不涉及任何 MySQL 或 PostgreSQL 后端服务器。

从 doc/duckdb/index.md 可知,该插件定位于嵌入式分析负载、本地运维数据、原型验证,以及"相比在每个客户端应用里链接 DuckDB,提供一个 SQL 端点更方便"的场景。插件属于 v4.0 Plugin Chassis 层,仅通过PROXYSQL40=1编译,不编译进 ProxySQL 核心可执行文件,而是以共享对象(.so)形式在 ProxySQL 启动时加载。

默认端点如下:

协议监听地址端口凭据来源
MySQL0.0.0.06031mysql_users
PostgreSQL0.0.0.06034pgsql_users

上述端口与 ProxySQL Admin(6032)以及常规 MySQL 代理监听端口(6033)相互独立,互不干扰。默认值与插件源码 plugins/duckdb/src/duckdb_config.cpp 中的kDefaultMysqlIfaces = "0.0.0.0:6031"、kDefaultPgsqlIfaces = "0.0.0.0:6034"、kDefaultDatabasePath = ":memory:"、kDefaultMemoryLimit = "1GB"一一对应。

第一步:从源码构建 v4.0 层

验证并构建

插件构建依赖仓库内直接 vendored 的 DuckDB 源码。当前 vendored 引擎版本为 DuckDB 1.4.5(见 doc/duckdb/installation.md),源码归档直接存放在 git 中,因此源码构建只需要 ProxySQL 常规的 C/C++ 工具链。

在仓库根目录执行:

deps/duckdb/verify-source.bash PROXYSQL40=1 make

verify-source.bash负责校验 vendored 源码包的完整性;PROXYSQL40=1是开启 v4.0 Plugin Chassis 层的开关。构建产物位于:

plugins/duckdb/ProxySQL_DuckDB_Plugin.so

进行系统安装时,make install会把插件放到标准路径:

/usr/lib/proxysql/plugins/ProxySQL_DuckDB_Plugin.so

构建注意事项(来自源码的细节)

从 plugins/duckdb/Makefile 可以看到几个关键约束:

  • Tier 级联:PROXYSQL40=1会自动级联开启PROXYSQL31、PROXYSQLFFTO、PROXYSQLTSDB,插件与libproxysql.a必须用同一套 feature-tier 标志编译,否则ProxySQL_PluginDescriptor/ProxySQL_PluginServices的布局不一致,加载器会读越界。
  • ABI 耦合:DEBUG 与 release 构建不能混用。插件加载器在dlopen时即拒绝 DEBUG/release 不匹配的插件/核心组合(对应include/ProxySQL_Plugin.h中的PROXYSQL_PLUGIN_ABI_DEBUG_BIT)。从 DEBUG 切换到 release(或反之)时,应先清理旧对象文件。
  • 符号隐藏:插件源码以-fvisibility=hidden编译,仅导出extern "C"的入口proxysql_plugin_descriptor_v1,避免与核心产生 ODR 冲突。
  • DuckDB 静态库数量校验:DuckDB 1.4.5 在 Linux 上会产生 16 个静态归档(macOS 为 15 个),Makefile 在链接时校验数量,防止部分构建残留导致.so缺符号、仅在dlopen(RTLD_NOW)时才暴露失败。

第二步:在启动时加载插件

插件不支持热加载。需要把共享对象加入proxysql.cnf的plugins数组:

plugins = ( "/usr/lib/proxysql/plugins/ProxySQL_DuckDB_Plugin.so" )

修改该数组后,必须启动或重启 ProxySQL才能生效。若直接从源码树运行,则把路径改为该 checkout 中plugins/duckdb/ProxySQL_DuckDB_Plugin.so的绝对路径;包管理器或自定义安装同样必须在proxysql.cnf中使用产物的精确绝对路径。

如果已有其他插件,按现有 libconfig 语法依次列出即可。ProxySQL 按列表顺序加载插件,且不会解析插件之间的依赖关系(见 doc/duckdb/installation.md)。

第三步:确保端点用户存在

插件本身不定义独立的用户表。MySQL 协议端点使用mysql_users中的有效用户进行认证,PostgreSQL 协议端点使用pgsql_users中的有效用户。可以直接复用现有有效用户;若通过 ProxySQL Admin 新增用户,请使用对应协议的常规用户命令完成加载与保存(例如 MySQL 的LOAD MYSQL USERS TO RUNTIME)。

本教程使用duckuser作为占位用户名。生产环境中不要把真实密码直接写在命令行上。

第四步:通过 MySQL 协议连接并执行分析查询

MySQL 协议默认端口为 6031:

mysql -h 127.0.0.1 -P 6031 -u duckuser -p

创建一个小数据集并运行聚合分析查询:

CREATE OR REPLACE TABLE sales ( region VARCHAR, amount DECIMAL(12,2) ); INSERT INTO sales VALUES ('north', 125.50), ('south', 200.00), ('north', 74.50); SELECT region, SUM(amount) AS total FROM sales GROUP BY region ORDER BY region;

期望结果:

north 200.00 south 200.00

这里的 SQL 是DuckDB SQL,不是 MySQL 方言。插件只对少量客户端发现类查询(版本、当前数据库、SHOW 元数据命令)做兼容拦截,并不做通用的方言翻译层(见 doc/duckdb/protocol-compatibility.md)。

第五步:通过 PostgreSQL 协议读取同一个数据库

PostgreSQL 协议默认端口为 6034。示例使用的数据库名为main:

psql -h 127.0.0.1 -p 6034 -U duckuser main

然后执行:

SELECT * FROM sales ORDER BY region, amount;

两个协议端点连接的是同一个嵌入式 DuckDB 数据库。从 doc/duckdb/index.md 的架构描述可知:插件启动时打开一个duckdb_database,每个被接受的客户端连接拥有自己的duckdb_connection,该连接在整个连接专属线程的存续期内保持;因此在默认:memory:配置下,所有会话共享进程生命周期内的同一内存数据库,DuckDB 负责在连接间提供并发控制。

需要注意::memory:数据库只存活到 ProxySQL 停止。要让表跨重启保留,需要按下一节配置文件路径型database_path。

用户指南中的连接要点

  • 会话设置(如SET search_path='main')仅作用于客户端自己的连接,SET与SELECT是两个独立请求。
  • 事务命令(BEGIN;/COMMIT;)以普通文本查询逐条发送;PostgreSQL 协议的ReadyForQuery会基于 DuckDB 连接的真实状态报告I(空闲)、T(事务中)、E(事务失败),出错后需先ROLLBACK再继续。
  • 结果列当前全部以文本类型呈现(MySQL 端点全部为字符串,PostgreSQL 端点全部为TEXTOID),SQL NULL 保留为真实的协议空值。

详见 doc/duckdb/user-guide.md。

第六步:让数据库持久化

连接 ProxySQL Admin(端口 6032),填充可编辑的 DuckDB 配置表:

SAVE DUCKDB VARIABLES TO MEMORY; UPDATE global_variables SET variable_value='/var/lib/proxysql/duckdb/analytics.db' WHERE variable_name='duckdb-database_path'; LOAD DUCKDB VARIABLES TO RUNTIME; SAVE DUCKDB VARIABLES TO DISK;

duckdb-database_path属于引擎打开期设置:LOAD会拒绝实时切换,该改动会保留为 Main 中待生效状态(pending),而 Runtime 继续如实报告当前实际打开的数据库。变更database_path不会复制旧数据,也不会切换已打开的引擎;正确流程是:保存设置 → 停止流量 → 重启 ProxySQL → 显式验证新数据库。

为持久化数据库创建父目录,并赋予 ProxySQL 服务账号可写权限:

install -d -o proxysql -g proxysql -m 0750 /var/lib/proxysql/duckdb

随后重启 ProxySQL,插件将打开配置的文件。建议将数据库放在专为 ProxySQL 准备的目录中,避免全局可读/可写权限,也不要让duckdb-database_path指向敏感已有文件(见 doc/duckdb/security.md)。

关于 Admin 命令的补充说明

SAVE/LOAD DUCKDB VARIABLES只复制匹配duckdb-%的行,不会触碰其他模块命名空间。LOAD DUCKDB VARIABLES TO RUNTIME会把 Main 中合法的稀疏切片覆盖到生效状态,校验完整候选集,并拒绝未知变量、非法值以及不支持的实时切换;失败时不会静默修复 Main。常用命令及别名(SAVE DUCKDB VARIABLES TO MEMORY与SAVE ... FROM RUNTIME、SAVE ... TO DISK与SAVE ... FROM MEMORY等)的完整清单见 doc/duckdb/admin-reference.md。

第七步:验证配置

通过 ProxySQL Admin 检查生效值:

SELECT * FROM runtime_global_variables WHERE variable_name LIKE 'duckdb-%' ORDER BY variable_name;

Runtime 行会在每次查询时根据实际引擎与监听器状态重新生成,因此它反映的是真实生效状态而不是缓存意图。哪些变量立即生效、哪些要等待下一次插件打开,参见 doc/duckdb/configuration-reference.md。

全量配置参数速查

DuckDB 设置以duckdb-前缀命名存放在global_variables中,生效值同名存放在runtime_global_variables中。全部八个参数如下(默认值与实时行为摘自 doc/duckdb/configuration-reference.md):

变量默认值可接受值实时行为
duckdb-mysql_ifaces0.0.0.0:6031分号分隔的addr:port变更被拒绝;需重开监听器
duckdb-pgsql_ifaces0.0.0.0:6034分号分隔的addr:port变更被拒绝;需重开监听器
duckdb-database_path:memory:DuckDB 路径或:memory:变更被拒绝;需重开数据库
duckdb-memory_limit1GBDuckDB 内存限制字符串立即生效,校验并回读
duckdb-threads2整数1..INT_MAX立即生效,已有连接可见
duckdb-max_connections100整数1..INT_MAX对新准入立即生效
duckdb-read_onlyfalse布尔别名变更被拒绝;需重开数据库
duckdb-enable_external_accessfalse布尔别名true→false实时生效;反向被拒绝

布尔别名(true/false、1/0、on/off)会被规范化为标准形式存储;空的数据库路径会变成:memory:。Runtime 的引擎值来自 DuckDBcurrent_setting(),包括其规范的容量单位——例如输入512MB,DuckDB 1.4.5 回读为488.2 MiB。

各参数要点

  • 监听器变量:多地址用;分隔,IPv6 字面量需加方括号,如[::1]:6031;端口范围 1~65535。监听值未变化时,不阻塞其他无关的实时变更;监听值一旦变更则返回错误并保持在 Main 中待生效。
  • duckdb-database_path:空值或:memory:选择进程生命周期的内存数据库;其他值为 ProxySQL 账号可访问的路径。变更永远不复制数据;LOAD 拒绝替换已打开的数据库,Runtime 与状态继续使用实际打开的路径。
  • duckdb-memory_limit:示例值512MB、1GB、8GB。LOAD 通过内部控制连接校验并应用,然后回读;非法语法会让整个候选集失败。注意 DuckDB 与 ProxySQL 共享进程,须为核心、连接缓冲、其他插件、操作系统与负载尖峰预留内存。
  • duckdb-threads:控制查询并行度,全局应用、已有连接可感知。客户端无法修改:客户端执行SET threads=N(或其别名worker_threads)会收到指向该变量的错误。
  • duckdb-max_connections:跨两个监听器限制连接预留数。调低不会断开已有会话,只是拒绝新连接,直到数量回落到限值以下。
  • duckdb-read_only:映射为打开数据库时的访问模式。true配合有效:memory:会在候选校验阶段被拒绝(源码 plugins/duckdb/src/duckdb_config.cpp 中read_only=true requires a file-backed database_path的逻辑即为此)。它不能替代外部访问安全。
  • duckdb-enable_external_access:ProxySQL 覆盖 DuckDB 默认的宽松配置,默认关闭。收紧(true→false)可实时生效,且由于无法回滚,会被最后应用;放宽(false→true)需等待下一次数据库打开。客户端不能用SET修改;引擎级设置仅能通过 Admin 的duckdb-*变量配合LOAD DUCKDB VARIABLES TO RUNTIME修改。

实时生效 vs 生命周期生效

立即生效:duckdb-memory_limit、duckdb-threads、duckdb-max_connections、duckdb-enable_external_access(仅true→false)。

需要对应数据库/监听器生命周期重开:duckdb-database_path、duckdb-read_only、duckdb-mysql_ifaces、duckdb-pgsql_ifaces、duckdb-enable_external_access(false→true)。

当前接口没有独立的 DuckDB reload 命令,因此通常靠进程重启到达下一次打开;ProxySQL 不会为 LOAD 自行重启、终止会话、重开内存数据库或丢弃数据(见 doc/duckdb/admin-reference.md)。

协议行为与安全边界

必须使用简单文本查询

插件用 MySQL / PostgreSQL 前端协议作为 DuckDB SQL 的传输通道,并非完整的 MySQL 或 PostgreSQL 服务器实现。当前版本明确不支持:

  • 客户端可见的预处理语句(MySQL 的COM_STMT_PREPARE/COM_STMT_EXECUTE、PostgreSQL 的扩展查询协议)。PostgreSQL 端点对Parse/Bind/Describe/Execute扩展流程返回 SQLSTATE0A000(Feature not supported),随后按错误重同步规则丢弃消息直至Sync,再发送一个ReadyForQuery恢复正常处理。
  • 一个请求包含多条语句(含纯注释请求,因为无可准备的语句)。
  • 类型化结果元数据(当前所有列均为文本)。
  • 插件级查询超时(失控的 DuckDB 查询不会被中断)。
  • 通用 MySQL/PostgreSQL 方言翻译。

因此客户端应选用发起简单文本查询的 API:MySQL 用mysql_query/mysql_real_query;PostgreSQL 用PQexec或强制简单 Query 消息的驱动模式。切勿因为不支持预处理而改用对不可信输入的不安全字符串拼接。

兼容拦截列表

以下客户端发现类命令会被拦截或改写(匹配不区分大小写,容忍常规空白与结尾语句终止符):

  • SELECT @@version、SELECT VERSION()
  • SELECT DATABASE()、SELECT CURRENT_DATABASE()
  • SHOW TABLES、SHOW DATABASES、SHOW SCHEMAS(分别读取 DuckDB 目录与 schema 元数据,不是同一查询的别名)
  • SET autocommit=0/SET autocommit=1
  • 单条SET NAMES ...

仅靠前缀匹配不会接受更长的标识符或含第二条语句的报文包;含第二条语句的SET NAMES报文会走常规单语句准备路径并被拒绝。SELECT DATABASE()在:memory:时返回memory,否则返回配置的database_path。

结果转换细节

直接转换路径支持常见标量:布尔、有符号/无符号整数、浮点、double、日期、时间、时间戳、DECIMAL、间隔、VARCHAR、BLOB。对直接兼容列表之外的 DuckDB 类型(LIST、STRUCT、MAP、ARRAY、UNION、UUID、ENUM、BIT 及特殊时间戳变体等),插件在执行前检测类型,改用等价包装:

SELECT COLUMNS(*)::VARCHAR FROM (<original query>)

该决策发生在执行前,因此易变表达式与副作用恰好只执行一次。某些无法放入包装的 DMLRETURNING语句走原始执行回退路径,不支持的返回列可能以 NULL 呈现;SQL NULL 本身在其他情况下保留为真实协议空值。

错误映射

MySQL 客户端收到 MySQL 错误包;PostgreSQL 客户端收到 ErrorResponse,并在 DuckDB 暴露明确错误类别时映射对应 SQLSTATE(语法、数值范围、转换、除零、事务、约束、连接、I/O、取消、内存、权限、非法参数等),未分类错误使用XX000。

安全要点

  • 认证后端点用户共享嵌入式数据库,没有额外的按表 DuckDB 授权层;适合路由业务流量的凭据未必适合直接访问嵌入式分析库,建议使用专用凭据、限制端点可达性。
  • 两个监听器默认0.0.0.0会暴露在所有可用接口上。本地使用建议改为mysql_ifaces=127.0.0.1:6031、pgsql_ifaces=127.0.0.1:6034(监听变更需重启)。
  • duckdb-enable_external_access=false是安全基线:启用后可能允许read_csv读本地文件、COPY ... TO写文件、ATTACH 其他数据库文件等,这与duckdb-read_only相互独立,只读主库不代表任意文件系统读取安全。
  • vendored 构建禁用了扩展 autoload/autoinstall,未默认启用未签名扩展,插件不会从互联网拉取扩展。
  • 每个连接占一个线程,高连接上限即使查询空闲也会消耗线程栈与调度容量;没有每查询超时,网络隔离与凭据控制是资源保护的一部分。
  • 连接一被接受(认证前)即占用duckdb-max_connections槽位,未在mysql-connect_timeout_client/pgsql-connect_timeout_client内完成认证的连接会被断开并释放槽位,并记录 "Closing not established DuckDB client connection" 警告。

完整细节见 doc/duckdb/protocol-compatibility.md 与 doc/duckdb/security.md。

后续步骤

  • 学习常规连接、SQL 工作流、事务与会话行为:doc/duckdb/user-guide.md。
  • 回顾每个设置的默认值、校验规则与生效行为:doc/duckdb/configuration-reference.md。
  • 了解 Admin 表、Runtime 投影与 LOAD/SAVE 命令:doc/duckdb/admin-reference.md。
  • 在对外暴露任一监听器前阅读安全指南:doc/duckdb/security.md。
  • 选择驱动 API 前确认协议兼容性:doc/duckdb/protocol-compatibility.md。
  • 监控、备份、容量与重启恢复:doc/duckdb/operations.md。
  • 完整安装步骤、升级与替换注意事项:doc/duckdb/installation.md。
  • 插件构建说明:plugins/duckdb/README.md;依赖 vendoring 细节:deps/duckdb/README.md。
  • 后端
  • 数据库
  • 负载均衡

【免费下载链接】proxysql

High-performance proxy for MySQL and PostgreSQL

项目地址:https://gitcode.com/gh_mirrors/pr/proxysql
点击查看免费下载
上一篇:LeetCode 1371 题解:每个元音包含偶数次的最长子字符串(前缀和 + 状态压缩 / XOR 位运算)
下一篇:Node.js 25.1.0 (Current) 发布深度解析:HTTP 空请求优化、SQLite 防御模式与 watch 配置命名空间

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询