- 后端
- 数据库
- 负载均衡
【免费下载链接】proxysql
High-performance proxy for MySQL and PostgreSQL
本教程带你从当前仓库源码出发,构建 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 启动时加载。
默认端点如下:
| 协议 | 监听地址 | 端口 | 凭据来源 |
|---|---|---|---|
| MySQL | 0.0.0.0 | 6031 | mysql_users |
| PostgreSQL | 0.0.0.0 | 6034 | pgsql_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 makeverify-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_ifaces | 0.0.0.0:6031 | 分号分隔的addr:port | 变更被拒绝;需重开监听器 |
duckdb-pgsql_ifaces | 0.0.0.0:6034 | 分号分隔的addr:port | 变更被拒绝;需重开监听器 |
duckdb-database_path | :memory: | DuckDB 路径或:memory: | 变更被拒绝;需重开数据库 |
duckdb-memory_limit | 1GB | DuckDB 内存限制字符串 | 立即生效,校验并回读 |
duckdb-threads | 2 | 整数1..INT_MAX | 立即生效,已有连接可见 |
duckdb-max_connections | 100 | 整数1..INT_MAX | 对新准入立即生效 |
duckdb-read_only | false | 布尔别名 | 变更被拒绝;需重开数据库 |
duckdb-enable_external_access | false | 布尔别名 | 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
相关推荐
ProxySQL DuckDB 插件:在 MySQL/PostgreSQL 协议下嵌入运行 DuckDB 分析引擎的完整指南
ProxySQL DuckDB 插件:在 MySQL/PostgreSQL 协议下嵌入运行 DuckDB 分析引擎的完整指南 本指南围绕 doc/duckdb/
后端数据库负载均衡ProxySQL DuckDB 插件协议兼容性指南:MySQL / PostgreSQL 前端协议下的能力边界与实测要点
ProxySQL DuckDB 插件协议兼容性指南:MySQL / PostgreSQL 前端协议下的能力边界与实测要点 本指南以 doc/duckdb/pro
后端数据库负载均衡ProxySQL DuckDB 插件安装指南:从源码构建到生产部署的完整实践
ProxySQL DuckDB 插件安装指南:从源码构建到生产部署的完整实践 ProxySQL 的 DuckDB 插件将 DuckDB 分析引擎嵌入 Proxy
后端数据库负载均衡
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考