我花了一天时间，拆了一下 OpenTeleDB 的 XStore，到底解决了 PG 的哪根老筋？
这两年数据库圈有点像3年前的云原生圈："分布式"、"新一代内核"、"重构存储引擎"这些词突然又密集起来了。前几天刷群，看到有人转了 OpenTeleDB 的开源消息，说是"基于 PostgreSQL 的新一代内核"。说实话，我第一反应是：又一个魔改 PG？但看到里面提到一个点：原位更新 + Undo 引擎（XStore），我还是没忍住下了源码。 因为这恰好戳中我这些年被 PG 折磨得最狠的痛点：表膨胀、autovacuum 抽风、性能像心电图一样忽高忽低。所以这次我没看 PPT，也没看宣传稿，直接跑到机器上拆了半天，想看看它究竟动了 PG 的哪根"老筋"。一、先说结论：XStore 不是快，而是"稳"我装的是 OpenTeleDB 的 17.6 内核版。 创建方式很直观：SELECT relname, amname FROM pg_class c JOIN pg_am a ON c.relam = a.oid WHERE relname = 'test_xstore';这一步其实就已经很有意思了------它不是 fork 了一套新引擎，而是作为插件挂进去的。 这个思路我很认可：不绑死 PG 版本能跟着大版本升级出问题可以随时回退像 Citus、openHalo 这些"成功插件化路线"的项目，本质都是这个思路。二、打开数据目录，我第一次意识到：它真不是换皮在 $PGDATA 下面，多了一个非常显眼的目录：drwx------ 2 postgres postgres 4096 Nov 3 20:15 undo这就是 XStore 的核心： 它不是靠多版本链来维护 MVCC，而是靠 Undo 日志回滚。这点和 Oracle、MySQL InnoDB 的逻辑更像。也正是它敢说"原位更新"的底气来源。三、插入测试：它不快，但很"诚实"我用同样的参数，在同一台机器上跑了两组：INSERT INTO test_xstore (name, value) SELECT md5(random()::text), (random()*1000)::int FROM generate_series(1,10000000);INSERT INTO test_heap (name, value) SELECT md5(random()::text), (random()*1000)::int FROM generate_series(1,10000000);结果是：写慢了将近一倍。这点我反而觉得真实：因为 XStore 在写数据页的同时，还要写一份 Undo。物理写入翻倍，吞吐下降是必然的。如果一个系统告诉你"原位更新 + Undo 还更快"，那我反而会不太信。四、创新实验：模拟1千万数据的存储膨胀对比我设计了一项创新实验：在 1000 万条级别的大数据量下，评估 XStore 与 Heap 表在高频更新下的空间膨胀、索引稳定性以及查询性能表现。该实验主要有两个创新点：大规模数据模拟使用 generate_series(1,10000000) 生成 1000 万条数据，保证数据量级对存储膨胀影响明显。初始数据包括 id、name、value 和 updated_at 四列，与前期实验一致，但数据量增加十倍，以模拟真实大规模 OLTP 系统负载。多维度空间分析不仅监控表总大小，还分别统计索引占用和 TOAST 表空间。每轮更新后，通过 pg_relation_size、pg_total_relation_size 和 pg_indexes_size 获取精细化指标。引入 可视化趋势分析，绘制表空间增长曲线，以直观展示 XStore 与 Heap 的差异。4.1 实验设计表结构CREATE TABLE xstore_large ( id SERIAL PRIMARY KEY, name TEXT, value INT, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) USING XSTORE; CREATE TABLE heap_large ( id SERIAL PRIMARY KEY, name TEXT, value INT, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );初始化 1000 万条数据INSERT INTO xstore_large (name, value) SELECT 'name_' || g, g FROM generate_series(1, 10000000) AS g; INSERT INTO heap_large (name, value) SELECT 'name_' || g, g FROM generate_series(1, 10000000) AS g;先对现在存入1000w数据的空间监控与记录一下如下。SELECT pg_size_pretty(pg_total_relation_size('xstore_large')) AS xstore_total, pg_size_pretty(pg_indexes_size('xstore_large')) AS xstore_index, pg_size_pretty(pg_total_relation_size('heap_large')) AS heap_total, pg_size_pretty(pg_indexes_size('heap_large')) AS heap_index; xstore_total | xstore_index | heap_total | heap_index --------------+--------------+------------+------------ 985 MB | 388 MB | 789 MB | 214 MB多轮全表更新连续 5 轮更新，每轮更新 value 和 updated_at，模拟写入密集场景：UPDATE xstore_large SET value = value + 1, updated_at = CURRENT_TIMESTAMP; UPDATE heap_large SET value = value + 1, updated_at = CURRENT_TIMESTAMP;空间监控与记录SELECT pg_size_pretty(pg_total_relation_size('xstore_large')) AS xstore_total, pg_size_pretty(pg_indexes_size('xstore_large')) AS xstore_index, pg_size_pretty(pg_total_relation_size('heap_large')) AS heap_total, pg_size_pretty(pg_indexes_size('heap_large')) AS heap_index;第一轮： xstore_total | xstore_index | heap_total | heap_index --------------+--------------+------------+------------ 985 MB | 388 MB | 1578 MB | 428 MB第五轮： xstore_total | xstore_index | heap_total | heap_index --------------+--------------+------------+------------ 985 MB | 388 MB | 1628 MB | 428 MB4.2 千万数据更新膨胀可视化五、实验结论这组 1000 万级数据 + 多轮全表更新的实验，其实把 PG 传统 Heap 表的"老问题"放大得非常清楚。最核心的对比结果只有一句话：XStore 的空间是线性的、可预测的；Heap 表的空间是失控的、不可预测的。具体来看：表空间膨胀a. Heap 表在第一次更新后，表体空间直接翻倍，从 789MB 飙到 1578MB。b. 之后每一轮更新，虽然增长幅度趋缓，但空间再也回不到初始状态。c. XStore 从头到尾不变： 985MB → 985MB → 985MB索引体积稳定性a. Heap 表索引从 214MB 膨胀到 428MB，且在后续更新中保持"高位横盘"。b. XStore 的索引尺寸始终维持在 388MB 左右，没有明显漂移。更新行为本质差异a. Heap：每一次 UPDATE，本质都是 DELETE + INSERT → 老版本残留 → 表膨胀 → 索引碎片 → autovacuum 压力。b. XStore：真正的原位更新 → 历史版本进 Undo → 主表物理页不变 → 无膨胀。长期可运维性a. 在 Heap 表上，如果你不 VACUUM，它一定会慢； 如果你 VACUUM，系统一定会抖。b. 在 XStore 上，这两件事都不再是必选项。这意味着什么？它不是让你飞起来，而是让你不再塌方。六、我的心得说实话，这几年我已经对"新一代数据库内核"这类说法有点免疫了。大多数项目，要么是在 PG 上糊一层分布式壳； 要么就是换个名字，重新卖一遍 MVCC。而 XStore 给我的感觉不一样。它没有试图掩盖代价。写入更慢， IO 更多，架构更复杂。但它正面承认了一个事实：PostgreSQL 的 MVCC，在高频更新场景下已经接近物理极限。这不是参数调优能解决的事，也不是加机器能扛住的事，而是存储模型本身的问题。这些年我见过太多系统：白天 QPS 很稳，半夜 autovacuum 开始清垃圾，延迟突然拉长，业务报警，DBA 开始手工 VACUUM / REINDEX / CLUSTER，第二天继续循环。这不是运维水平的问题，而是模型在和现实硬扛。XStore 让我第一次意识到：原来 PG 也可以选择不走这条老路。它没有追求"更快"，而是选择了一个更难、但更稳的方向：用 Undo 换空间可控用写放大换性能平滑用工程复杂度换系统长期可预期性如果你是写多、更新密集型 OLTP 系统，如果你被表膨胀、索引碎片、autovacuum 抽风折磨过，那你会和我一样---不一定立刻用它，但你会开始认真看它。这大概就是我这次拆源码、跑实验，最大的收获。
使用托管数据库部署 Coreflux MQTT 代理MQTT 代理 通过发布-订阅消息模式连接物联网设备和应用程序，使其成为现代 物联网 基础设施的重要组成部分。Coreflux 是一个 低代码 MQTT 代理，增加了实时数据处理和转换功能，让你可以直接与 DigitalOcean 托管数据库（包括 MongoDB、PostgreSQL、MySQL 和 OpenSearch）集成，而无需编写自定义集成代码。你将学到什么： 本教程将引导你部署一个完整的物联网数据管道——从在 DigitalOcean 上设置托管数据库集群和 Coreflux MQTT 代理，到配置安全的 VPC 网络、使用 Coreflux 的物联网语言 (LoT) 构建数据转换模型，以及自动将处理后的物联网数据存储到你选择的数据库中。最终你将获得一个可用于生产环境的设置，能够处理物联网应用的实时消息传递和持久存储。关键要点在深入了解分步部署过程之前，以下是你将学到的关键点：在 DigitalOcean 上部署托管数据库集群（PostgreSQL、MongoDB、MySQL 或 OpenSearch），用于可扩展的物联网数据存储。使用 Marketplace 镜像或 Docker 在 DigitalOcean Droplet （DigitalOcean的VPC）上设置 Coreflux MQTT 代理。创建安全的 VPC 网络以连接你的 MQTT 代理和数据库，无需公开暴露。使用 Coreflux 的物联网语言 (LoT) 构建实时数据管道，实现低代码物联网自动化。自动转换和存储物联网数据，从 MQTT 主题到数据库表、集合或索引。验证端到端数据流，从模拟传感器通过转换模型到数据库存储。本教程为需要实时消息传递结合持久数据存储以及搜索、分析或关系查询等高级功能的物联网应用提供了一个可用于生产环境的基础。你将构建什么在本教程结束时，你将得到：一个用于可扩展存储的托管数据库集群（PostgreSQL、MongoDB、MySQL 或 OpenSearch）一台运行 Coreflux MQTT 代理的 DigitalOcean Droplet一个用于安全 物联网通信的虚拟私有云 (VPC) 网络使用 LoT Notebook 扩展进行的实时数据模拟低代码数据转换模型和数据库集成路由用于 物联网自动化 的完整 数据集成与转换 管道Coreflux 与 DigitalOcean 合作Coreflux 通过物联网语言编程语言在 DigitalOcean 云平台上提供轻量级 MQTT 代理和数据管道工具，以实现高效的物联网通信。什么是 MQTT？MQTT（消息队列遥测传输）是一种轻量级的、发布-订阅网络协议，在物联网生态系统中被广泛采用。专为受限设备和低带宽、高延迟或不稳定的网络设计，MQTT 能够在带宽受限的环境中实现高效、实时的消息传递。关于 CorefluxCoreflux 提供了一个轻量级 MQTT 代理，以促进物联网设备与应用程序之间的高效、实时通信，包括每个用例所必需的实时数据转换功能。为可扩展性和可靠性而构建，Coreflux 专为低延迟和高吞吐量至关重要的环境量身定制。无论你是构建一个小型物联网项目还是部署工业监控系统，Coreflux 都能处理设备之间的消息路由和数据流。在 DigitalOcean 云平台上使用 Coreflux，你将获得：数据处理： 在你的数据所在之处集中处理你的数据处理需求，确保实时数据处理。数据集成： 轻松与其他 DigitalOcean 服务（如托管数据库 PostgreSQL、MongoDB、MySQL 或 OpenSearch）集成，确保为你的所有数据需求提供一个单一且简单的生态系统。可扩展性： 轻松处理不断增长的数据和设备数量，而不会影响性能。可靠性： 确保在所有连接的设备之间进行一致且可靠的消息传递。准备工作在开始本 MQTT 代理 部署教程之前，你需要：一个 DigitalOcean 帐户，可在DigitalOcean.com注册，支持绑定信用卡、支付宝或数字货币了解 MQTT 协议概念和 物联网 架构Visual Studio Code（用于 LoT Notebook 扩展）预计时间： 本教程大约需要 30-45 分钟完成，具体取决于数据库配置时间（通常每个数据库集群需要 1-5 分钟）。步骤 1 — 为物联网自动化创建网络基础设施为安全的 MQTT 通信创建 VPC 网络首先，你将创建一个虚拟私有云 (VPC)，以确保你的 物联网 服务和 MQTT 代理 之间的安全通信，无需公开访问。登录你的 DigitalOcean 控制面板从左侧导航栏进入 网络 → VPC点击 创建 VPC 网络为物联网自动化配置你的 VPC：名称：coreflux-integrations-vpc（或你的 VPC 名称）数据中心区域：选择法兰克福（或你首选的区域）IP 范围：使用默认值或根据需要配置描述：为你的 MQTT 代理和数据库 网络添加有意义的描述点击 创建 VPC 网络VPC 将为你所有的物联网资源提供隔离的网络，确保 Coreflux MQTT 代理 和 托管数据库 之间的安全通信。有关 VPC 配置的更多详细信息，请参阅我们关于创建 VPC 网络的教程。步骤 2 — 为可扩展存储设置托管数据库根据你的物联网应用需求，选择以下数据库选项之一：PostgreSQL：适用于需要关系查询、ACID 合规性和复杂关系的结构化数据MySQL：适用于结构化工作负载和具有强一致性及广泛工具支持的事务性查询MongoDB：适用于具有可变模式的灵活文档存储和快速开发OpenSearch：适用于高级搜索、分析、日志分析和时间序列数据可视化设置 PostgreSQL 托管数据库当你的物联网工作负载需要关系模式、强一致性 和 高级 SQL 分析，并由自动备份、监控和维护支持时，DigitalOcean 上的托管 PostgreSQL 是一个很好的选择。从 DigitalOcean 控制面板，导航到 数据库点击 创建数据库集群为物联网自动化配置你的 PostgreSQL 集群：数据库引擎：选择 PostgreSQL版本：选择最新的稳定版本数据中心区域：选择法兰克福（与你的 VPC 相同）VPC 网络：选择你创建的 coreflux-integrations-vpc数据库集群名称：postgresql-coreflux-test项目：选择你的目标项目根据你的 物联网 需求选择你的计划：对于开发：基础 计划，1 GB RAM对于生产：通用型 或更高，用于可扩展存储点击 创建数据库集群托管数据库 创建过程通常需要 1-5 分钟。完成后，你将被重定向到数据库概览页面，在那里你可以查看连接详细信息并执行管理操作。为 MQTT 代理集成配置 PostgreSQL 数据库访问系统将提示你进行入门步骤，显示你的连接详细信息，你可以配置入站访问规则（建议限制为你的 IP 和仅 VPC）。点击 开始使用 来配置你的 PostgreSQL 数据库（可选操作）限制入站连接：添加你本地计算机的 IP 以进行管理访问droplet 将通过 VPC 网络自动获得允许对于连接详细信息，你将看到两个选项 - 公共网络和 VPC 网络。第一个用于像 DBeaver 这样的工具进行外部访问，而第二个将由 Coreflux 服务用于访问数据库。记下提供的连接详细信息，包括公共访问和 VPC 访问（每种都有不同的详细信息）：主机：你的数据库主机名用户：默认管理员用户密码：自动生成的安全密码数据库：身份验证数据库名称测试 PostgreSQL 数据库连接你可以使用提供的连接参数，使用公共访问凭证通过 DBeaver 测试 PostgreSQL 连接：创建 PostgreSQL 应用程序数据库和用户（可选）为了更好的安全性和组织性，为你的 物联网自动化 应用程序创建一个专用用户和数据库。这也可以通过 DBeaver 或 CLI 完成，但 DigitalOcean 提供了一种用户友好的方法：转到你的 托管数据库 集群中的 用户与数据库 选项卡创建用户：用户名：coreflux-broker-client密码：自动生成创建数据库：数据库名称：coreflux-broker-data注意： 你可能需要更改数据库内的用户权限，以便能够创建表、插入和选择数据。对于 PostgreSQL，使用 GRANT CREATE, INSERT, SELECT ON DATABASE coreflux-broker-data TO coreflux-broker-client; 授予必要的权限。对于 MySQL，使用 GRANT CREATE, INSERT, SELECT ON coreflux-broker-data.* TO 'coreflux-broker-client'@'%';。设置 MySQL 托管数据库当你想要熟悉的 SQL、广泛的生态系统支持以及处理备份、更新和监控的完全托管服务时，DigitalOcean 上的托管 MySQL 是结构化、事务性物联网数据的理想选择。从 DigitalOcean 控制面板，导航到 数据库点击 创建数据库集群为物联网自动化配置你的 MySQL 集群：数据库引擎：选择 MySQL版本：选择最新的稳定版本数据中心区域：选择法兰克福（与你的 VPC 相同）VPC 网络：选择你创建的 coreflux-integrations-vpc数据库集群名称：mysql-coreflux-test项目：选择你的目标项目根据你的 物联网 需求选择你的计划：对于开发：基础 计划，1 GB RAM对于生产：通用型 或更高，用于可扩展存储点击 创建数据库集群托管数据库 创建过程通常需要 1-5 分钟。完成后，你将被重定向到数据库概览页面，在那里你可以查看连接详细信息并执行管理操作。为 MQTT 代理集成配置 MySQL 数据库访问系统将提示你进行入门步骤，显示你的连接详细信息，你可以配置入站访问规则（建议限制为你的 IP 和仅 VPC）。点击 开始使用 来配置你的 MySQL 数据库（可选操作）限制入站连接：添加你本地计算机的 IP 以进行管理访问droplet 将通过 VPC 网络自动获得允许对于连接详细信息，你将看到两个选项 - 公共网络和 VPC 网络。第一个用于像 DBeaver 这样的工具进行外部访问，而第二个将由 Coreflux 服务用于访问数据库。记下提供的连接详细信息，包括公共访问和 VPC 访问（每种都有不同的详细信息）：主机：你的数据库主机名用户：默认管理员用户密码：自动生成的安全密码数据库：身份验证数据库名称测试 MySQL 数据库连接你可以使用提供的连接参数，使用公共访问凭证通过 DBeaver 测试 MySQL 连接。注意： 你可能需要更改 DBeaver 的驱动程序设置——设置 allowPublicKeyRetrieval = true。创建 MySQL 应用程序数据库和用户（可选）为了更好的安全性和组织性，为你的 物联网自动化 应用程序创建一个专用用户和数据库。这也可以通过 DBeaver 或 CLI 完成，但 DigitalOcean 提供了一种用户友好的方法：转到你的 托管数据库 集群中的 用户与数据库 选项卡创建用户：用户名：coreflux-broker-client密码：自动生成创建数据库：数据库名称：coreflux-broker-data设置 MongoDB 托管数据库托管 MongoDB 非常适合灵活或不断演变的物联网负载，让你能够存储异构的传感器文档，而无需严格模式，同时平台处理复制、备份和监控。从 DigitalOcean 控制面板，导航到 数据库点击 创建数据库集群为物联网自动化配置你的 MongoDB 集群：数据库引擎：选择 MongoDB版本：选择最新的稳定版本数据中心区域：选择法兰克福（与你的 VPC 相同）VPC 网络：选择你创建的 coreflux-integrations-vpc数据库集群名称：mongodb-coreflux-test项目：选择你的目标项目根据你的 物联网 需求选择你的计划：对于开发：基础 计划，1 GB RAM对于生产：通用型 或更高，用于可扩展存储点击 创建数据库集群托管数据库 创建过程通常需要 1-5 分钟。完成后，你将被重定向到数据库概览页面，在那里你可以查看连接详细信息并执行管理操作。为 MQTT 代理集成配置 MongoDB 数据库访问系统将提示你进行入门步骤，显示你的连接详细信息，你可以配置入站访问规则（建议限制为你的 IP 和仅 VPC）。点击 开始使用 来配置你的 MongoDB 数据库（可选）限制入站连接：添加你本地计算机的 IP 以进行管理访问droplet 将通过 VPC 网络自动获得允许对于连接详细信息，你将看到两个选项：公共网络和 VPC 网络。第一个用于像 MongoDB Compass 这样的工具进行外部访问，而第二个将由 Coreflux 服务用于访问数据库。记下提供的连接详细信息，包括公共访问和 VPC 访问（每种都有不同的详细信息）：主机：你的数据库主机名用户：默认管理员用户密码：自动生成的安全密码数据库：身份验证数据库名称测试 MongoDB 数据库连接你可以使用 MongoDB Compass 或提供的连接字符串，使用公共访问凭证测试 MongoDB 连接：mongodb://username:password@mongodb-host:27017/defaultauthdb?ssl=true创建 MongoDB 应用程序数据库和用户（可选）为了更好的安全性和组织性，为你的 物联网自动化 应用程序创建一个专用用户和数据库。这也可以通过 MongoDB Compass 或 CLI 完成，但 DigitalOcean 提供了一种用户友好的方法：转到你的 托管数据库 集群中的 用户与数据库 选项卡创建用户：用户名：coreflux-broker-client密码：自动生成创建数据库：数据库名称：coreflux-broker-data设置 OpenSearch 托管数据库托管 OpenSearch 专为高容量物联网数据的搜索、日志分析和时间序列仪表板而设计，该服务为你管理集群健康、扩展和索引存储。从 DigitalOcean 控制面板，导航到 数据库点击 创建数据库集群为物联网自动化配置你的 OpenSearch 集群：数据库引擎：选择 OpenSearch版本：选择最新的稳定版本数据中心区域：选择法兰克福（与你的 VPC 相同）VPC 网络：选择你创建的 coreflux-integrations-vpc数据库集群名称：opensearch-coreflux-test项目：选择你的目标项目根据你的 物联网 需求选择你的计划：对于开发：基础 计划，1 GB RAM对于生产：通用型 或更高，用于可扩展存储点击 创建数据库集群托管数据库 创建过程通常需要 1-5 分钟。完成后，你将被重定向到数据库概览页面，在那里你可以查看连接详细信息并执行管理操作。为 MQTT 代理集成配置 OpenSearch 数据库访问系统将提示你进行入门步骤，显示你的连接详细信息，你可以配置入站访问规则（建议限制为你的 IP 和仅 VPC）。点击 开始使用 来配置你的 OpenSearch 数据库（可选）限制入站连接：添加你本地计算机的 IP 以进行管理访问droplet 将通过 VPC 网络自动获得允许对于连接详细信息，你将看到两个选项：公共网络和 VPC 网络。第一个用于工具的外部访问，而第二个将由 Coreflux 服务用于访问数据库。你还将看到访问 OpenSearch 仪表板的 URL 和参数。记下提供的连接详细信息，包括公共访问和 VPC 访问（每种都有不同的详细信息）：主机：你的数据库主机名用户：默认管理员用户密码：自动生成的安全密码数据库：身份验证数据库名称测试 OpenSearch 数据库连接你可以使用提供的凭证通过 OpenSearch 仪表板测试 OpenSearch 连接：步骤 3 — 在 DigitalOcean Droplet 上部署 Coreflux MQTT 代理创建 DigitalOcean Droplet在你的 DigitalOcean 控制面板中导航到 Droplets点击 创建 Droplet为 MQTT 代理 部署配置你的 droplet：选择区域：法兰克福（与你的托管数据库相同）VPC 网络：选择 coreflux-integrations-vpc选择镜像：转到 Marketplace 选项卡搜索 “Coreflux” 并从 Marketplace 中选择 Coreflux为你的 物联网 工作负载选择大小：对于开发：基础 计划，2 GB 内存对于生产：基础 或 通用型 计划，4+ GB 内存以获得可扩展性能选择身份验证方法：SSH 密钥：推荐用于提高安全性可以使用 ssh-keygen 在本地创建密钥密码：备选方案最终确定详细信息：主机名：coreflux-test-broker项目：选择你的项目标签：为 DevOps 组织添加相关标签点击 创建 Droplet查看 Droplet 主页并等待其完成部署替代方案 - 在Docker镜像Droplet上使用Docker安装Coreflux MQTT代理采用与Coreflux Droplet相同的方法，选择Docker作为市场应用镜像。一旦你的droplet运行起来，通过已定义的认证方法或Droplet主页上提供的Web控制台，使用SSH连接到它：ssh root@your-droplet-ip使用Docker运行Coreflux MQTT代理：docker run -d \ --name coreflux \ -p 1883:1883 \ -p 1884:1884 \ -p 5000:5000 \ -p 443:443 \ coreflux/coreflux-mqtt-broker-t:1.6.3这个Docker命令：以分离模式运行容器 (-d)将容器命名为 coreflux暴露MQTT和Web界面所需的端口使用最新的Coreflux镜像验证MQTT代理是否在运行：docker ps你应该看到一个正在运行的容器：通过使用默认值连接到MQTT代理来验证部署你可以通过MQTT客户端（如MQTT Explorer）访问MQTT代理，以验证对代理的访问，无论采用何种部署方法。步骤4 — 为安全的物联网通信配置防火墙规则（可选）对于生产环境的物联网自动化部署，配置防火墙规则以限制访问：导航到网络 → 防火墙点击创建防火墙配置MQTT代理安全的入站规则：SSH：来自你IP的端口22MQTT：来自你的物联网应用程序源的端口1883带TLS的MQTT：用于安全的带TLS的MQTT的端口1884WebSocket：用于通过WebSocket的MQTT的端口5000带TLS的WebSocket：用于通过带TLS的WebSocket的MQTT的端口443将防火墙应用到你的droplet关于详细的防火墙配置，请参考DigitalOcean的防火墙快速入门教程。生产提示： 将MQTT端口1883限制在特定的源IP或VPC范围，并且对于外部设备连接，优先使用端口1884（带TLS的MQTT）。如果你需要额外的安全层，请考虑使用带有私有网络的DigitalOcean应用平台。步骤5 — 使用Coreflux的Language of Things设置物联网数据集成安装LoT Notebook扩展用于Visual Studio Code的LoT（Language of Things）Notebook扩展提供了一个集成的低代码开发环境，用于MQTT代理编程和物联网自动化。了解更多关于Coreflux的Language of Things (LoT)用于低代码物联网自动化的信息。打开Visual Studio Code转到扩展（Ctrl+Shift+X）搜索"LoT Notebooks"安装由Coreflux提供的LoT VSCode Notebooks扩展连接到你的MQTT代理配置与你的Coreflux MQTT代理的连接，当在顶部栏提示时或通过点击底部左侧栏的MQTT按钮时，使用默认凭据：用户：root密码：coreflux假设没有错误，你将在底部左侧栏看到与代理的MQTT连接状态。步骤6 — 通过Actions在MQTT代理中创建数据对于这个用例，我们将通过一个转换管道将原始数据集成到数据库中。然而，由于在演示中没有连接到任何MQTT设备，我们将利用LoT的能力，并使用一个Action来模拟设备数据。在LoT中，Action是一种可执行的逻辑，由特定事件触发，例如定时间隔、主题更新或其他操作或系统组件的显式调用。Actions允许与MQTT主题、内部变量和负载进行动态交互，促进复杂的物联网自动化工作流。因此，我们可以使用一个以定义的时间间隔在特定主题中生成数据的Action，然后由我们将在下面定义的管道的其余部分使用。你可以下载包含示例项目的github仓库。生成模拟物联网数据使用低代码的LoT（Language of Things）界面创建一个Action来生成模拟传感器数据：DEFINE ACTION RANDOMIZEMachineData ON EVERY 10 SECONDS DO PUBLISH TOPIC "raw_data/machine1" WITH RANDOM BETWEEN 0 AND 10 PUBLISH TOPIC "raw_data/station2" WITH RANDOM BETWEEN 0 AND 60在提供的Notebook中，你还有一个Action可以执行递增计数器来模拟数据，作为提供Action的替代方案。当你运行这个Action时，它将：自动部署到MQTT代理每10秒生成一次模拟的物联网传感器数据将实时数据发布到特定的MQTT主题在LoT Notebook界面中显示同步状态此状态显示LoT Notebook上的代码是否与代理中运行的代码不同，或者是否完全缺失步骤7 — 为实时处理创建数据转换模型使用Language of Things定义数据模型Coreflux中的模型用于转换、聚合和计算来自输入MQTT主题的值，并将结果发布到新主题。它们是创建适用于你多个数据源的UNS - 统一命名空间 - 的基础。因此，通过该模型，你可以定义原始物联网数据的结构与转换方式，适用于单个设备，也支持同时处理多个设备（借助通配符+实现）。模型还作为用于可扩展存储到托管数据库的关键数据模式。DEFINE MODEL MachineData WITH TOPIC "Simulator/Machine/+/Data" ADD "energy" WITH TOPIC "raw_data/+" AS TRIGGER ADD "energy_wh" WITH (energy * 1000) ADD "production_status" WITH (IF energy > 5 THEN "active" ELSE "inactive") ADD "production_count" WITH (IF production_status EQUALS "active" THEN (production_count + 1) ELSE 0) ADD "stoppage" WITH (IF production_status EQUALS "inactive" THEN 1 ELSE 0) ADD "maintenance_alert" WITH (IF energy > 50 THEN TRUE ELSE FALSE) ADD "timestamp" WITH TIMESTAMP "UTC"这个低代码模型：使用通配符+自动应用到所有机器通过乘以1000将能量转换为瓦时（energy_wh）根据能量阈值确定生产状态跟踪生产计数和停机事件向所有实时数据点添加时间戳从主题结构中提取机器ID将结构化数据发布到Simulator/Machine/Data主题（将+替换为每个匹配触发器/源数据格式的主题）由于我们使用Action生成了两个模拟传感器/机器，我们可以看到模型结构自动应用于两者，同时生成了一个json对象和各个单独的主题。步骤8 — 为可扩展存储设置数据库集成选择与你在步骤2中选择的数据库相匹配的数据库集成部分。PostgreSQL集成在本节中，你将学习如何将处理后的物联网数据存储到DigitalOcean上的PostgreSQL托管数据库中。要将处理后的物联网数据存储到PostgreSQL托管数据库中，你需要在Coreflux中定义一个Route。Route使用简单、低代码的配置指定数据如何从你的MQTT代理发送到你的PostgreSQL集群：DEFINE ROUTE PostgreSQL_Log WITH TYPE POSTGRESQL ADD SQL_CONFIG WITH SERVER "db-postgresql.db.onmyserver.com" WITH PORT 25060 WITH DATABASE "defaultdb" WITH USERNAME "doadmin" WITH PASSWORD "AVNS_pass" WITH USE_SSL TRUE WITH TRUST_SERVER_CERTIFICATE FALSE使用来自DigitalOcean的你自己的PostgreSQL连接详细信息替换，并在你的LoT Notebook中运行该Route。重要提示： 为了更好的安全性和更低的延迟，请使用VPC连接详细信息（而非公共连接）。VPC主机名和端口与公共连接字符串不同 - 请检查你的数据库集群的连接详细信息页面以获取这两个选项。为PostgreSQL数据库存储更新模型修改你的LoT模型以使用数据库路由进行可扩展存储，通过将此添加到模型的末尾：STORE IN "PostgreSQL_Log" WITH TABLE "MachineProductionData"此外，添加一个带有主题的参数，以便在你的托管数据库中为每个条目提供唯一标识符。DEFINE MODEL MachineData WITH TOPIC "Simulator/Machine/+/Data" ADD "energy" WITH TOPIC "raw_data/+" AS TRIGGER ADD "device_name" WITH REPLACE "+" WITH TOPIC POSITION 2 IN "+" ADD "energy_wh" WITH (energy * 1000) ADD "production_status" WITH (IF energy > 5 THEN "active" ELSE "inactive") ADD "production_count" WITH (IF production_status EQUALS "active" THEN (production_count + 1) ELSE 0) ADD "stoppage" WITH (IF production_status EQUALS "inactive" THEN 1 ELSE 0) ADD "maintenance_alert" WITH (IF energy > 50 THEN TRUE ELSE FALSE) ADD "timestamp" WITH TIMESTAMP "UTC" STORE IN "PostgreSQL_Log" WITH TABLE "MachineProductionData"部署此更新后的操作后，所有数据在更新时应自动存储在数据库中。MySQL集成MySQL是一种广泛使用的关系数据库管理系统，非常适合大规模存储和分析物联网数据。在本节中，你将学习如何将你的Coreflux MQTT代理连接到DigitalOcean上的托管MySQL数据库，以便你的实时设备数据能够安全可靠地持久化，用于分析、报告或与其他应用程序集成。要启用此集成，你必须在Coreflux的LoT（Language of Things）中定义一个Route，指示处理后的数据应该发送到哪里以及如何发送。下面是路由数据到MySQL数据库所需的低代码格式。请务必根据需要替换你自己的连接详细信息：DEFINE ROUTE MySQL_Log WITH TYPE MYSQL ADD SQL_CONFIG WITH SERVER "db-mysql.db.onmyserver.com" WITH PORT 25060 WITH DATABASE "defaultdb" WITH USERNAME "doadmin" WITH PASSWORD "AVNS_pass" WITH USE_SSL TRUE WITH TRUST_SERVER_CERTIFICATE FALSE使用来自DigitalOcean的你自己的MySQL连接详细信息替换，并在你的LoT Notebook中运行该Route。重要提示： 为了更好的安全性和更低的延迟，请使用VPC连接详细信息（而非公共连接）。如果你遇到连接问题，请验证TRUST_SERVER_CERTIFICATE是否已为你的MySQL版本正确设置 - 某些版本需要TRUE，而其他版本则使用FALSE。为MySQL数据库存储更新模型修改你的LoT模型以使用数据库路由进行可扩展存储，通过将此添加到模型的末尾：STORE IN "MySQL_Log" WITH TABLE "MachineProductionData"此外，添加一个带有主题的参数，以便在你的托管数据库中为每个条目提供唯一标识符。DEFINE MODEL MachineData WITH TOPIC "Simulator/Machine/+/Data" ADD "energy" WITH TOPIC "raw_data/+" AS TRIGGER ADD "device_name" WITH REPLACE "+" WITH TOPIC POSITION 2 IN "+" ADD "energy_wh" WITH (energy * 1000) ADD "production_status" WITH (IF energy > 5 THEN "active" ELSE "inactive") ADD "production_count" WITH (IF production_status EQUALS "active" THEN (production_count + 1) ELSE 0) ADD "stoppage" WITH (IF production_status EQUALS "inactive" THEN 1 ELSE 0) ADD "maintenance_alert" WITH (IF energy > 50 THEN TRUE ELSE FALSE) ADD "timestamp" WITH TIMESTAMP "UTC" STORE IN "MySQL_Log" WITH TABLE "MachineProductionData"部署此更新后的操作后，所有数据在更新时应自动存储在数据库中。MongoDB集成MongoDB是一种NoSQL数据库，非常适合存储和查询具有灵活模式的物联网数据。在本节中，你将学习如何将你的Coreflux MQTT代理连接到DigitalOcean上的托管MongoDB数据库，以便你的实时设备数据能够安全可靠地持久化，用于分析、报告或与其他应用程序集成。要启用此集成，你必须在Coreflux的LoT（Language of Things）中定义一个Route，指示处理后的数据应该发送到哪里以及如何发送。下面是路由数据到MongoDB数据库所需的低代码格式。请务必根据需要替换你自己的连接详细信息：DEFINE ROUTE mongo_route WITH TYPE MONGODB ADD MONGODB_CONFIG WITH CONNECTION_STRING "mongodb+srv://<username>:<password>@<cluster-uri>/<database>?tls=true&authSource=admin&replicaSet=<replica-set>" WITH DATABASE "admin"使用来自DigitalOcean的你自己的MongoDB连接详细信息替换，并在你的LoT Notebook中运行该Route。重要提示： 当可用时，请使用VPC连接字符串格式。连接字符串应包括tls=true和authSource=admin参数。有关MongoDB连接故障排除，请参阅我们关于连接MongoDB的教程。为MongoDB数据库存储更新模型修改你的LoT模型以使用数据库路由进行可扩展存储，通过将此添加到模型的末尾：STORE IN "mongo_route" WITH TABLE "MachineProductionData"此外，添加一个带有主题的参数，以便在你的托管数据库中为每个条目提供唯一标识符。DEFINE MODEL MachineData WITH TOPIC "Simulator/Machine/+/Data" ADD "energy" WITH TOPIC "raw_data/+" AS TRIGGER ADD "device_name" WITH REPLACE "+" WITH TOPIC POSITION 2 IN "+" ADD "energy_wh" WITH (energy * 1000) ADD "production_status" WITH (IF energy > 5 THEN "active" ELSE "inactive") ADD "production_count" WITH (IF production_status EQUALS "active" THEN (production_count + 1) ELSE 0) ADD "stoppage" WITH (IF production_status EQUALS "inactive" THEN 1 ELSE 0) ADD "maintenance_alert" WITH (IF energy > 50 THEN TRUE ELSE FALSE) ADD "timestamp" WITH TIMESTAMP "UTC" STORE IN "mongo_route" WITH TABLE "MachineProductionData"部署此更新后的操作后，所有数据在更新时应自动存储在数据库中。OpenSearch集成OpenSearch是一种分布式搜索和分析引擎，专为大规模数据处理和实时分析而设计。在本节中，你将学习如何将你的Coreflux MQTT代理连接到DigitalOcean上的托管OpenSearch数据库，以便你的实时设备数据能够安全可靠地持久化，用于分析、报告或与其他应用程序集成。要启用此集成，你必须在Coreflux的LoT（Language of Things）中定义一个Route，指示处理后的数据应该发送到哪里以及如何发送。下面是路由数据到OpenSearch数据库所需的低代码格式。请务必根据需要替换你自己的连接详细信息：DEFINE ROUTE OpenSearch_log WITH TYPE OPENSEARCH ADD OPENSEARCH_CONFIG WITH BASE_URL "https://my-opensearch-cluster:9200" WITH USERNAME "myuser" WITH PASSWORD "mypassword" WITH USE_SSL TRUE WITH IGNORE_CERT_ERRORS FALSE使用来自DigitalOcean的你自己的OpenSearch连接详细信息替换，并在你的LoT Notebook中运行该Route。重要提示： 当可用时，请使用VPC基础URL（而非公共URL）。基础URL格式通常为https://your-cluster-hostname:9200。对于OpenSearch仪表板访问，请使用数据库集群详细信息中提供的单独的仪表板URL。有关更多详细信息，请参阅我们的OpenSearch快速入门。为OpenSearch数据库存储更新模型修改你的LoT模型以使用数据库路由进行可扩展存储，通过将此添加到模型的末尾：STORE IN "OpenSearch_Log" WITH TABLE "MachineProductionData"此外，添加一个带有主题的参数，以便在你的托管数据库中为每个条目提供唯一标识符。DEFINE MODEL MachineData WITH TOPIC "Simulator/Machine/+/Data" ADD "energy" WITH TOPIC "raw_data/+" AS TRIGGER ADD "device_name" WITH REPLACE "+" WITH TOPIC POSITION 2 IN "+" ADD "energy_wh" WITH (energy * 1000) ADD "production_status" WITH (IF energy > 5 THEN "active" ELSE "inactive") ADD "production_count" WITH (IF production_status EQUALS "active" THEN (production_count + 1) ELSE 0) ADD "stoppage" WITH (IF production_status EQUALS "inactive" THEN 1 ELSE 0) ADD "maintenance_alert" WITH (IF energy > 50 THEN TRUE ELSE FALSE) ADD "timestamp" WITH TIMESTAMP "UTC" STORE IN "OpenSearch_Log" WITH TABLE "MachineProductionData"部署此更新后的操作后，所有数据在更新时应自动存储在数据库中。步骤9 — 验证完整的物联网自动化管道监控实时数据流MQTT Explorer：使用MQTT客户端验证实时数据发布数据库客户端：连接以验证数据的存储（PostgreSQL使用DBeaver，MongoDB使用MongoDB Compass，OpenSearch使用OpenSearch Dashboards）验证PostgreSQL存储使用DBeaver连接到你的PostgreSQL托管数据库以验证可扩展存储：使用来自你的DigitalOcean数据库的连接字符串导航到 coreflux-broker-data 数据库（或你为数据库指定的名称）检查 MachineProductionData 表中存储的记录正如我们之前看到的，所有数据都可在MQTT代理中用于其他用途和集成。验证MongoDB存储使用MongoDB Compass连接到你的MongoDB托管数据库以验证可扩展存储：使用来自你的DigitalOcean数据库的连接字符串导航到 coreflux-broker-data 数据库（或你为数据库指定的名称）检查 MachineProductionData 集合中存储的文档你应该看到具有类似结构的实时数据文档：{ "_id": { "$oid": "68626dc3e8385cbe9a1666c3" }, "energy": 36, "energy_wh": 36000, "production_status": "active", "production_count": 31, "stoppage": 0, "maintenance_alert": false, "timestamp": "2025-06-30 10:58:11", "device_name": "station2" }正如我们之前看到的，所有数据都可在MQTT代理中用于其他用途和集成。验证MySQL存储使用DBeaver连接到你的MySQL托管数据库以验证可扩展存储：使用来自你的DigitalOcean数据库的连接字符串导航到coreflux-broker-data数据库（或你为数据库指定的名称）检查MachineProductionData表中存储的记录与其他集成一样，所有数据也可在MQTT代理中用于其他用途和下游集成。验证OpenSearch存储使用提供的URL和凭据打开OpenSearchDashboards：打开菜单并选择索引管理选项在菜单中选择索引选项，查看你的表名是否出现在列表中返回主页并在菜单中选择发现选项按照提供的步骤创建索引模式返回到发现页面，你应该会看到你的数据正如我们之前看到的，所有数据都可在MQTT代理中用于其他用途和集成。步骤10 - 扩展你的用例和集成测试LoT能力发布示例数据：使用MQTT Explorer将示例数据集发布到你的Coreflux代理。尝试不同的负载结构和不同的模型/操作，查看它们如何处理并存储到你选择的数据库中。数据验证：验证你数据库中的数据与你发布的有效负载是否匹配。使用你的数据库客户端（PostgreSQL使用DBeaver，MongoDB使用MongoDB Compass，OpenSearch使用OpenSearch Dashboards）检查一致性和准确性，确保你的物联网自动化集成按预期工作。比较时间戳、字段转换和数据类型，以验证你的实时数据管道。实时监控：使用另一个MQTT数据源（例如具有MQTT连接功能的简单传感器）设置连续的实时数据馈送。观察Coreflux和你的数据库如何处理传入的物联网数据流，并探索数据检索和查询的响应时间。构建分析和可视化创建仪表板：与Grafana等可视化工具集成，创建显示你的物联网数据的仪表板，从实时MQTT主题和历史数据库查询中提取数据。跟踪指标，如设备正常运行时间、传感器读数、生产计数或来自你自动化系统的维护警报。了解如何使用我们的教程设置DigitalOcean托管数据库与Prometheus和Grafana的监控。对于实时仪表板，直接订阅MQTT主题；对于历史趋势和聚合，查询你的数据库。趋势分析：利用你数据库的能力来分析随时间变化的趋势：PostgreSQL：使用SQL查询进行复杂的关系分析MongoDB：使用聚合框架进行基于文档的分析OpenSearch：使用高级分析和搜索能力进行全文搜索和时间序列分析多数据库集成：探索集成其他托管数据库，如用于非结构化数据的MongoDB，用于关系数据的PostgreSQL，用于结构化查询的MySQL，或用于高级分析和搜索的OpenSearch。使用Coreflux路由将数据同时发送到多个目的地。优化和扩展你的物联网基础设施负载测试：使用LoT Notebook或自动化脚本通过同时发布多条消息来模拟高流量。监控你的Coreflux MQTT代理和数据库集群如何处理负载，并识别你的数据管道中的任何瓶颈。扩展：DigitalOcean提供垂直和水平扩展选项。随着你的物联网数据需求增长，增加droplet资源（CPU、RAM或存储）。扩展你的托管数据库集群以处理更大的数据集，并配置自动扩展警报，以便在接近资源限制时通知你。常见问题解答1. 如何将Coreflux MQTT代理与托管数据库集成？你通过定义指向目标服务（PostgreSQL、MySQL、MongoDB或OpenSearch）的LoTRoute来将Coreflux MQTT代理与托管数据库集成。每个路由使用适当的连接参数（服务器或连接字符串、端口、数据库名称、用户名、密码和SSL/TLS选项），并自动将MQTT消息有效负载持久化到表、集合或索引中。一旦定义好路由，你就使用STORE IN指令将其附加到Model，这样每个处理后的消息都会被写入你选择的数据库。2. 我能否在不编写自定义集成代码的情况下将MQTT数据直接保存到数据库？可以。Coreflux设计为一个低代码集成层，因此你无需编写应用程序代码或外部ETL作业来持久化数据。对于每种数据库类型，你配置一个LoT路由（例如，PostgreSQL_Log、MySQL_Log、mongo_route或OpenSearch_Log），然后使用STORE IN "<route_name>" WITH TABLE "MachineProductionData"扩展你的模型。Coreflux处理连接池、重试和错误处理，因此你可以专注于建模主题和转换，而不是样板数据库代码。3. 我应该为MQTT物联网数据存储选择哪种托管数据库？你的MQTT物联网数据的最佳托管数据库取决于你的数据结构、查询需求和分析目标。使用下面的比较表来帮助你决定：数据库最适合示例用例PostgreSQL强一致性、关系模式、复杂的SQL查询工业传感器网络、事务性事件、需要跨连接数据集的分析MySQL关系数据、结构化查询、广泛的兼容性库存系统、生产指标、传统业务记录MongoDB灵活、不断演进的模式；文档存储具有可变负载的互联设备、具有变化格式的物联网遥测OpenSearch全文搜索、分析、仪表板、日志索引时间序列分析、监控、事件日志、物联网搜索和可视化提示： 你可以通过配置多个Coreflux路由同时使用多个托管数据库。这使得可以从同一个MQTT流中，将结构化的物联网数据存储在PostgreSQL或MySQL中，在OpenSearch中聚合日志和指标，并在MongoDB中收集非结构化或无模式数据。4. 这种架构如何处理实时和历史分析？Coreflux将所有处理后的值保留在MQTT主题上，供实时消费、仪表板或额外管道使用，而Routes则将相同的建模数据持久化到你的数据库中，用于历史查询。在实践中，你可以订阅主题以进行即时反应（警报、控制回路），并查询PostgreSQL/MySQL/MongoDB/OpenSearch以进行聚合、趋势和长期分析。这种双路径设计反映了MQTT和物联网数据集成教程中的常见模式，其中代理提供实时消息传递，而数据库提供持久存储和分析。5. Coreflux和托管数据库之间的连接有多安全？当部署在DigitalOcean上时，你可以使用VPC网络来保持Coreflux MQTT代理和数据库之间的所有通信私密。VPC将你的资源与公共互联网访问隔离开来，并且DigitalOcean托管数据库支持连接的TLS加密。此外，你可以为你的Coreflux应用程序创建具有有限权限的专用数据库用户，遵循最小权限原则。6. 这个设置是否适用于生产环境物联网部署？是的。这种架构反映了生产环境中MQTT和数据库集成所使用的模式，其中代理前端处理设备流量，而托管数据库层提供持久性和分析。DigitalOcean托管数据库提供自动备份、高可用性和监控，而Coreflux MQTT代理可以水平扩展以处理高消息吞吐量。对于生产环境，你还应该配置防火墙规则、使用强凭据、为MQTT和数据库连接启用TLS，并根据预期的消息量来调整你的droplet和集群大小。7. 我能否在没有公共互联网访问的情况下，或在混合环境中运行MQTT代理？可以。MQTT代理通常部署在私有网络或边缘环境中，公共资源一致指出，只要客户端可以访问代理，MQTT就可以在没有公共互联网的情况下工作。使用DigitalOcean，你可以将Coreflux和你的数据库保持在VPC内部，并且只暴露绝对必要的内容（例如，VPN、堡垒主机或有限的防火墙规则）。如果你需要混合或多站点架构，你还可以将选定的主题与其他代理或云区域同步。8. 在物联网数据中使用MQTT和数据库是否存在任何限制或权衡？MQTT针对轻量级、事件驱动的消息传递进行了优化；数据库则针对存储和查询进行了优化。存储每一条原始消息可能会变得昂贵或嘈杂，因此最佳实践建议仔细建模数据（例如，聚合指标、过滤主题或降采样）。极低功耗设备或超受限网络可能难以维持持久连接或处理TLS开销，在这种情况下，你可能需要调整QoS级别、批处理和保留策略。只要你在设计中考虑到这些权衡，MQTT加上托管数据库对于大多数物联网场景都能很好地工作。9. 我如何为我的物联网项目在PostgreSQL、MySQL、MongoDB和OpenSearch之间做出选择？你应该根据物联网数据结构、可扩展性以及你希望如何查询设备数据来选择托管数据库。下表总结了每个选项的优势：数据库当...时最佳典型用例关键优势PostgreSQL你需要复杂的关系查询、强一致性和事务完整性（ACID支持）。工业传感器网络、将设备数据与生产相关联、需要对连接的数据集进行分析关系模式、高级SQL、一致性MySQL你的工作负载是结构化的，具有广泛的工具和兼容性需求。库存跟踪、传统业务系统、生产指标更简单的关系需求、广泛支持MongoDB你的设备负载和模式不断演变，或者你希望使用灵活的、基于文档的存储进行快速原型设计。具有可变格式的物联网遥测、快速开发、半结构化数据灵活的模式、易于扩展、快速原型设计OpenSearch你需要分析、搜索或对大容量的物联网数据（日志、时间序列、事件）进行仪表板展示。搜索传感器数据、日志分析、可视化、基于关键字/时间的查询搜索、全文、分析、快速聚合结论将Coreflux MQTT代理与DigitalOcean的托管数据库服务（PostgreSQL、MongoDB、MySQL或OpenSearch）集成，为你提供了实时物联网数据处理和存储的完整设置。按照本教程，你已经使用低代码开发实践构建了一个收集、处理和存储物联网数据的自动化管道。借助Coreflux的架构和你选择的数据库的存储特性，你可以处理大量的实时数据并查询它以获取洞察。无论你是监控工业系统、跟踪环境传感器还是管理智慧城市基础设施，这种设置都让你能够基于实时MQTT主题和历史数据库查询做出数据驱动的决策。了解更多关于DigitalOcean托管数据库的信息，以及DigitalOcean 针对 IoT行业的产品服务支持，可咨询 DigitalOcean 中国区独家战略合作伙伴卓普云AI Droplet（aidroplet.com）。你可以尝试提供的用例或使用Coreflux和DigitalOcean实现你自己的用例。你还可以在DigitalOcean Droplet市场或通过Coreflux网站获取免费的Coreflux MQTT代理。
基于分层协作多智能体的数据库参数调优——OceanBase 校企研究
摘要：OceanBase联合成都信息工程大学的数据库缺陷实证研究，被软件工程顶刊IEEE TKDE录用。研究聚焦复杂工作负载下数据库参数自动调优的效率与泛化能力问题，提出一种分层协作的多智能体框架，通过创新的训练机制与协同策略，有效破解传统调优方法的瓶颈，为数据库性能优化和预测提供了兼具理论创新性与工程实用性的技术方案。近日，成都信息工程大学与 OceanBase 研发团队合作完成的研究《CMA+DB: How to Automatically Tune Database Parameters through Collaborative Multi-Agents》，被《IEEE Transactions on Knowledge and Data Engineering》（TKDE，CCF A 类、SCI 一区）录用。研究聚焦复杂工作负载下数据库参数自动调优的效率与泛化能力问题，提出一种分层协作的多智能体框架，通过创新的训练机制与协同策略，有效破解传统调优方法的瓶颈，为数据库性能优化和预测提供了兼具理论创新性与工程实用性的技术方案。以下为论文介绍：研究背景与挑战随着分布式与云计算技术的发展，数据库工作负载日趋多样化、复杂化。从高并发的在线交易场景（TPC-C），到随机读写的云服务场景（YCSB），再到高实时性的社交互动场景（Twitter），不同场景对参数配置的需求差异显著。传统调优方式逐渐难以适配这些实际需求：人工调优高度依赖 DBA 的专业经验，不仅需要耗费大量时间梳理参数关系，而且无法应对动态变化的工作负载，往往出现 “调优即过时” 的问题；搜索式调优方法依赖启发式规则，在简单场景下表现尚可，但面对多参数交互的复杂场景时，搜索空间急剧扩大，调优效率大幅下降；贝叶斯优化方法需要手动筛选关键参数，若参数定义不全面，难以找到最优配置；现有强化学习调优方法多采用单智能体设计，仅能对参数进行粗粒度调优，无法充分挖掘不同类型参数间的深层交互影响，调优精度和泛化能力受限。如何实现参数调优的自动化、精准化与高效化，成为数据库领域亟待解决的关键问题。图1 数据库参数调优主要步骤核心理论创新：CMA+DB 多智能体协作框架CMA+DB 框架以 “分类协作、分层训练” 为核心设计理念，构建了三级递进式训练机制，整合单智能体预训练模型 SAPM、多智能体联合训练模型 MATM 与基于概率选择的联合训练模型 PJTM，既保障了单个参数类别内的调优深度，又实现了跨类别参数的协同优化。三个子模型并非孤立存在，而是以级联方式递进工作，前一阶段的训练成果直接作为后一阶段的输入，形成 “基础专精—交互探索—精准强化” 的完整调优链路，确保框架在参数交互捕捉、调优效率与泛化能力之间实现最优平衡。图2 CMA+DB 模型工作原理在技术实现上，CMA+DB 基于深度确定性策略梯度（DDPG）与多智能体深度确定性策略梯度（MADDPG）构建核心算法架构，采用 Actor-Critic 网络结构实现智能体的决策与优化。每个智能体都具备独立的观测空间与动作空间，通过与数据库环境的持续交互获取反馈，不断优化参数调优策略。图3 多智能体 Actor 和 Critic 网络结构在第一阶段，提出单智能体预训练模型 SAPM。训练初期，每个 Agent 负责调优一类功能或参数级别相似的参数，目的是探究单个 Agent 对数据库性能的影响，进而优化其网络，使得其神经网络偏向于调节重要参数。该过程 Agent 之间相互不影响。与传统的单智能体模型相比，SAPM 模型的优点在于更深入地探究相似参数之间的关系，也更容易识别出一些重要参数。这一阶段对于识别关键参数和实现快速收敛至关重要。通过使智能体能够初步掌握参数调整策略，SAPM 为后续更复杂的多智能体训练奠定了坚实的基础，并减少后续阶段的耦合干扰，从而提高了整体效率和效果。在第二阶段，提出多智能体联合训练模型 MATM，在 MATM 模型训练阶段，使用组合算法将多个 Agent 的预测动作组合并映射为一组数据库的推荐配置，要求 Agent 之间不能存在相同的数据库参数。这种协作方法不仅增加了可调参数的数量，还显著增强了模型的表现力和调整能力。此阶段虽然存在耦合，但通过联合训练，能够让智能体逐步适应彼此的行为模式，实现协同优化。在第三阶段，提出了联合动作概选模型 PJTM，在 SAPM 和 MATM 模型训练之后进行训练，算法为每个 Agent 设置了一个概选因子 Pi， Agent 根据 Pi，随机地参与联合动作推荐。当一个 Agent 控制的数据库参数对数据库性能的提升微乎其微时，就可以根据 Pi 减小该 Agent 的动作参与，进而降低其对其它 Agent 所做动作的负面影响。这一机制有效减少了低影响智能体对整体调优过程的干扰，缓解了耦合带来的负面影响。基于上述三种方式，提出协作型多智能体模型 CMA+DB，其整合 SAPM、MATM 和 PJTM 模型进行分阶段训练，实现分功能、分级别地对数据库参数进行调优。探究了相同类型参数之间的相互影响以及不同类型参数之间的协作关系。有效地解决了离散环境和异步反馈的挑战，确保多个智能体的动作是协调的，并针对数据库性能进行了优化，提高了数据库参数的调优数量，提升了数据库参数调优的效率。关键验证成果相关研究成果已在 PostgreSQL 数据库环境下，在 TPC-C、YCSB、Twitter 三种典型工作负载上，与主流调优方法进行全面对比验证，核心性能指标表现突出且稳定。在调优效率方面，CMA+DB 的收敛速度优势显著。在 TPC-C 高并发交易场景中，这一优势尤为明显，CMA+DB 的平均收敛速度（达到最大吞吐量时）优于其他三种算法。能帮助数据库更快脱离性能波动期，进入最优稳定状态，大幅缩短调优耗时，降低系统上线或扩容后的性能适配成本。在性能提升方面，CMA+DB 展现出持续优化的能力。经过 SAPM 预训练后，框架的吞吐量已优于现有部分主流方法；后续经 MATM 的跨类别参数协同优化，以及 PJTM 的精准强化，在 TPC-C 场景下，其延迟显著低于 OtterTune、CDBTune+ 等方法，有效保障了系统在峰值压力下的响应稳定性，避免了因参数配置不当导致的延迟突增问题。在泛化能力方面，CMA+DB 表现出极强的适应性。实验结果表明，不同参数规模与智能体数量的组合测试显示，CMA+DB 能够根据实际场景灵活调整，无需人工干预即可适配不同规模的数据库参数调优需求，解决了传统方法在参数规模变化时泛化能力下降的问题。总结与展望作为一种兼具理论深度与工程价值的数据库参数自动调优方案，CMA+DB 框架通过多智能体分类协作与分层训练的创新设计，有效解决了传统方法在参数交互探索、调优效率与泛化能力上的短板，为 AI 赋能数据库优化领域提供了新的技术思路。该框架的核心优势在于，不但实现了参数调优的自动化与精准化，而且无需依赖大量人工干预与领域知识，降低了数据库性能优化的门槛，具备较强的应用价值。未来研究将进一步优化框架结构，通过算法改进降低计算复杂度，提升框架在超大规模参数场景下的运行效率；同时，将尝试适配 MySQL、OceanBase 等更多主流 DBMS，针对不同数据库的内核特性调整智能体的参数分类与协作策略，推动相关技术在金融、电商、社交等实际生产环境中的广泛应用，为数据库系统的性能优化提供更高效、更通用的解决方案。欢迎访问 OceanBase 官网获取更多信息：https://www.oceanbase.com/
【文档悬赏令】第2号：数据库巡检手册征集，上传文档赢好礼！
墨天轮社区举办的 【文档悬赏令】系列活动，每次聚焦一个主题，征集真实、可操作的第一手文档，希望能扩充社区文档资源、为更多人提供有用的参考资料，让技术学习少走弯路！第2号悬赏令活动主题：数据库巡检方案实践数据库巡检是保障业务稳定运行的核心运维环节，更是DBA日常工作的重中之重。当前数据库类型、场景十分丰富，多数从业者需耗费大量时间整理巡检清单、调试巡检流程。墨天轮社区第二期【文档悬赏令】活动特围绕这一主题发起有奖征集活动，诚邀您上传实用、可落地的数据库巡检文档，和社区众位DBA们互帮互助，让巡检工作更高效、更标准！一、活动时间2026 年 1 月 26 日 - 3 月 28 日二、文档要求1、主题范围本次征集聚焦 “数据库巡检” 核心主题，覆盖国内外主流数据库，基础巡检、专项巡检、自动化巡检等多类实用方案等均可，具体范围如下：巡检主题细分（包含但不限于）：基础巡检：日常运维巡检表/巡检清单/巡检手册专项巡检：性能监控与优化巡检/灾备状态巡检/单机or集群巡检方式：手动巡检标准化文档/自动化巡检/脚本命令/巡检工具数据库不限：商业数据库：Oracle、SQL Server等国产数据库：达梦DM8、人大金仓KingbaseES、OceanBase等国产库开源数据库：MySQL、PostgreSQL、Redis等开源库2、合格要求与格式文档内容需明确巡检目的、适用场景、巡检流程等，包含巡检相关代码（部分敏感信息可隐去）。页数要求：≥5 页必加标签：上传时需在 “标签” 栏填写 “数据库巡检” + 数据库种类（如 Oracle、OceanBase） 两个标签支持格式：优先推荐 .doc、.pdf、.ppt、.md、.txt 格式（可支持前 5 页预览，下载率更高）；也可上传 .zip （需附内容说明）；以下文档将被判为不合格：1）主题无关：非“数据库巡检”相关主题2）内容搬运：直接上传电子书或产品官方文档、他人演讲PPT，或直接复制抄袭、全文搬运网站其他文章/文档内容（已发布的文章内容不可以同时上传成文档参与活动，但如果是您曾发在其他网站的内容则可以上传参与）3）流水账或凑字数：文档页数需≥5页，但不可通过凑字数、使用大量无关图片占篇幅等4）作者刷量：不可刷数据-我们鼓励作者自发宣传自己的文档，但不可使用人工刷量、注册小号刷量等方式提高下载量；不可将文档拆分多份上传，导致单份内容无实际意义、缺乏完整性5）重复文档：重新上传以前发布的文档系统会自动识别判定为重复仅自己可见，也不可删除旧文档后重新上传三、上传步骤登录上传：登录墨天轮账号后，点击链接直达上传页：https://www.modb.pro/docUpload，或在首页下拉框点击 “传文档”；填写信息：标题：建议明确标注 “数据库种类 + 巡检场景”（如《MySQL数据库巡检手册》《Oracle数据库常规巡检项目和命令》），帮助他人快速判断主题标签：上传时需在 “标签” 栏填写 “数据库巡检” + 数据库种类（如 Oracle、OceanBase） 两个标签墨值设置：支持免墨值 / 5 墨值 / 10 墨值 / 25 墨值 / 50 墨值 / 100 墨值，设置墨值后，他人下载时支付的墨值将实时计入您的账户（ps：一般来说墨值越低下载门槛越低，被下载可能更高）提交：确认信息无误后点击 “提交文档”即可。于 “控制台-内容管理-我的文档” 处可查看您所有文档明细，若您遇到“仅自己可见”“转换失败”等状态可询问墨天轮小助手（VX：modb666）询问具体原因。四、奖励设置本次活动奖励分为 “合格奖”“有效助人奖”“巡检先锋奖” 三类1、合格奖每位用户每日首次上传≥5 页的合格文档，可自动触发 “每日任务” 获 5 墨值。此外，本次活动奖励额外可叠加，根据用户合格文档数量发放不同等级的墨值奖励，具体如下：合格数量墨值0-3个10墨值/份3个以上15墨值/份2、有效助人奖根据单个文档下载数发放不同等级的墨值奖励，每个用户最多可有5个文档获得本项奖励：被下载数墨值30＜被下载数 ≤ 5050墨值50＜被下载数 ≤ 100100墨值100＜下载数 ≤ 150200墨值150＜下载数 ≤ 200300墨值下载数＞200500墨值3、巡检先锋奖将综合评估用户上传的合格文档的内容质量及总下载量，评选出 “既多产、又优质” 的核心贡献者，发予相应奖励：奖项等级奖励内容第 1 名1000 墨值 + 100元内数据库实体书一本第 2 名500墨值 + 爱国者U盘（128GB 双接口）第 3-5 名笔记本电脑支架（可旋转）说明：三类奖项单独评奖、每位用户可重复获得。其中新版本先锋奖数量将根据实际参与情况灵活调整，若参与情况佳则可能增设、反之亦然。五、奖励公布与发放进度公示：为了让大家更加了解自己的参与进度，将在活动期间不定期在活动原文评论区公布最新合格情况。若发现违规行为也欢迎向工作人员反馈，一经核实将取消其参与资格。结果公布：活动结束后 3 个工作日内公布所有获奖名单；奖励发放：墨值将在结果公布后 1-2 个工作日内发放至账户；实物奖励将通过私信收集地址，10 个工作日内寄出。常见问题（Q&A）Q1：如何让我的安装文档下载率更高？：A：建议在标题、简介中写明 “适用版本 + 核心亮点”，若上传的是.zip 等无法预览的格式，可在评论区附关键步骤截图或内容大纲，帮助他人判断价值。Q2：墨值可以干什么？A：墨值是墨天轮社区的“通用货币”，可以用来下载付费文档、赞赏他人文章或进行提问赞赏、直播打赏、兑换商品、参与墨值拍卖等。具体可查看使用说明：https://www.modb.pro/db/446902。Q3：我的文档会被展示在哪里？A：文档上传成功后可在您的控制台、个人主页找到相应链接。管理员也会择优推荐到网站首页及文档页面，为您的文档增加更多曝光。若您觉得您的文档优秀，欢迎您转发分享或自荐给工作人员，我们将为您争取首页推荐、转发等更多曝光。无论是你是初学者还是资深开发者，欢迎你加入本次文档悬赏活动，分享你的优质文档，与更多朋友一起学习进步！未来我们也将针对更多技术主题推出悬赏活动，如果你有推荐的主题也不妨告诉我们！乐知乐享、共同成长！点击跳转上传文档：https://www.modb.pro/docUpload往期活动导航【文档悬赏令】第1号：数据库新版本的安装实操欲了解更多可浏览墨天轮社区，围绕数据人的学习成长提供一站式的全面服务，打造集新闻资讯、在线问答、活动直播、在线课程、文档阅览、资源下载、知识分享及在线运维为一体的统一平台，持续促进数据领域的知识传播和技术创新。关注官方公众号： 墨天轮、 墨天轮平台、墨天轮成长营、数据库国产化 、数据库资讯
内存一年疯涨 170%，云账单里的“隐性成本”该算清了
2025 年下半年，存储价格又一次成为行业聚焦点。多家市场机构统计显示，2025 年三季度跟四季度，DRAM 和 NAND 价格一路攀升。根据 Tom's Hardware 披露的数据，2025 年 DRAM 合同价同比上涨幅度高达 171.8%，创下历史新高。此轮上涨跟 AI 数据中心建设拓展、服务器需求集中释放紧密相联，还直接引发企业 IT 基础设施采购成本上升。对于依赖自建数据中心或中小 IDC 的企业来说，这种变化带来的冲击尤为剧烈。硬件采购从一次性预算问题，演变为难以预测的长期成本风险。服务器、SSD 和内存条的价格不再稳定，交付周期也更不确定。企业在扩容时不得不承担高价买入、供货延迟的双重压力。因此，将硬件采购压力转化为按需付费的运营支出，把价格波动风险转移给云服务商，正在成为越来越多企业的选择。但问题并未因此结束。随着业务迁移到云端，企业发现云账单中存储与内存的占比仍在持续上升，即便算力配置并未明显升级，总体成本依旧水涨船高。部分团队开始反思：问题是否仅和数据量增多有关，还是资源使用方式本身就存在不合理的地方？目前，多数云实例依旧按固定的 CPU 与内存配比来交付，诸如 2 核 4GB、4 核 8GB 的规格。早期，这种设计可简化资源管理，推动了云计算普及，但如今业务形态有所改变，企业系统一般得同时支撑多样业务，各业务对于算力、内存的消耗不一样，固定规格愈发难以契合实际需求。这导致企业要么部分资源长期闲置，要么不得不面对业务在高峰阶段出现性能瓶颈的风险。当内存价格进入上行周期，这种规格错配带来的浪费被进一步放大：闲置的不再只是资源本身，而是越来越昂贵的成本。正是基于这样的背景，云基础设施走到新的路径分岔口：是继续就资源本身实施配置，还是转变方向围绕应用需求设计算力供给方式？在近期面向中国区合作伙伴召开的发布会上，华为云对 Flexus 云服务器系列规格及性能进行更新，并且展示了其在各种业务负载下的运行表现。该实例基于华为云首创的柔性算力技术，打破 CPU 与内存的固定绑定关系，使企业能够按真实业务需求配置资源，从源头减少内存浪费，并结合智能调度与应用级加速改善长期运行稳定性与算力资源投入产出比。本文将从行业环境变化与技术实现等层面，剖析这种模式背后的思路，以及它所代表的云服务器演进方向。云服务器，开始不太“合身”了云服务器长期采用固定 CPU 与内存的配比，是工程上的一种取舍考量。早期云平台首先得解决的是规模化交付和稳定调度的问题，采用固定规格利于资源池管理，同样便于容量规划及计费设计。当业务形态呈现相对单一阶段，这样的方式尚可接纳。但究其本质它是从平台管理成本角度设计的，并非从业务负载的角度出发。如今业务已不再是单一模式，电商、内容分发、数据库、缓存、AI 推理在一套系统中同步协同运行，对 CPU 以及内存的需求差别明显，固定规格无法精准对应实际负载，企业只能采用超出实际所需的实例型号。云服务器规格跟应用需求普遍不匹配，用户往往被迫去为用不到的算力和内存付费，引发大量资源的闲置浪费。资源浪费只不过是表象罢了，更深层的问题体现为性能优化的复杂度。现实的业务部署不仅涉及操作系统选定，还包含网络参数、系统参数以及应用配置参数。数量往往达到数千级别，缺少专家经验积累，难以达成稳定的最优配置。单是内核跟应用层的参数组合，就已超出普通团队可控范围，调优所用的周期漫长，效果也难以把控。从较长的时间阶段看，云服务器本身一直在不断演变，最初的资源虚拟化阶段，是把物理服务器标准化成可租借的实例；紧接着进入弹性规模阶段，采取自动伸缩的方式去应对流量变化，这两个阶段处理的是存不存在以及是否充足的问题，当下已经迈入第三阶段，关注焦点转向使用是否高效。过去，固定实例曾是工程优势，如今却愈发像是一件穿着不合身的衣服。柔性算力：从“卖规格”到“卖能力”怎样让资源本身更贴近应用？在 Flexus 云服务器 X 实例产品的设计里，华为云引入了柔性算力这一概念。在 Flexus X 实例里，柔性算力首先体现在规格形态的调整变化上。传统实例一般仅仅可在少量固定比例中选择 CPU 跟内存配置，而该实例支持按业务需求实施更精细的组合配置。发布会现场提到，所有 X 实例均支持多种非常规的 CPU/ 内存配比，包括 3:1、2:5、3:7 等组合。这可减少由规格不一致引起的资源闲置，让用户更接近按实际负载付费。然而规格数量增加，并非表示问题自动就解决了，其关键是系统如何判断哪种配置更合适。传统调度大多依据节点上剩余的 CPU 与内存。新方式需要领会业务负载本身，涵盖资源使用结构，以及随时间的变化趋势。Flexus X 实例本质上不再是调度 CPU，而是实际的业务场景。就工程实现而言，这种转变依赖底层架构的支撑，Flexus X 实例借助华为云自研的擎天 QingTian 架构和瑶光云脑调度系统得以实现，经由计算、存储和网络资源的解耦操作，提高了资源组合的自由度，也增强了非标准规格运行状态下的稳定性。此外，柔性算力还意味着配置不再是一次性决定，实例运行时会一直对资源使用状况进行评估，系统会判断当前配置跟负载是否相符，进而给出调整建议，而且还支持算力规格热升降的独家能力。从这个层面看，Flexus X 实例的转变不只是规格数量增多，它更像是把算力从提前打包好的商品，变成可持续优化的能力，实现“应用驱动算力”的最优体验。关键应用加速：算力之外的第二条性能曲线Flexus X 实例不单单改变了资源形态，还进一步深入应用执行层，解决了算力配置合理系统却依旧不稳定的问题。此次规格升级，华为云为数据库以及中间件类的负载引入专属应用级加速机制。Flexus X 实例针对 PostgreSQL、Memcached、MySQL、Redis、Nginx 提供了独立的一键加速能力，由 X-Turbo 应用加速引擎统一驱动。此类优化不会对用户的使用途径做出改变，实例创建结束之后即可启用，平台会把调优工作完成，用户无需插手复杂参数的配置。发布会现场，华为云对该能力实测演示，在 PostgreSQL 的使用场景下，Flexus X 实例的吞吐量达到 2.1 万 + TPS，大概为同规格业界旗舰型实例的 3.4 倍。就数据库这类系统而言，峰值性能仅仅属于一方面，更为关键的是高负载持续状态下的稳定输出能力。业务系统更易受诸如延迟抖动、连接堆积等问题的干扰，而不是单次压测形成的成绩。X-Turbo 的设计目标之一正是实现性能优化长期运行状态下的吞吐与响应稳定性。跟应用级优化同步进行的是，实例规模的进一步扩展。新一代 Flexus X2e 实例的 x86 规格从原本的 32U128G 提升至 64U256G，多核算力提升了约 30%；新增 Flexus KX1 鲲鹏实例，最高可达 80U320G，以覆盖大数据处理、内存数据库这类资源密集型场景。这意味着应用加速机制不再受中小规格环境约束，能在规模更大的资源池里发挥作用。这一系列的变化显示出云服务器性能边界正在转移。过去，性能更多由 CPU 规格和内存容量决定。而如今，应用执行路径、参数组合的方法及调度策略成为同等要紧的变量，在固定规格的时代里，这些优化由用户自己承担，而于 Flexus X 实例中，它们被纳入到算力交付范畴，正是从这一意义出发，云服务器竞争不再只是资源规模大小的比拼，而是发展为聚焦运行效率的系统工程。从工程能力到真实落地：柔性算力如何进入生产系统一项新的算力供给方式，能否切实进入生产系统，首要取决于它是否具备充足的稳定性与可用性。Flexus X 实例可靠性设计向华为云旗舰级云服务器标准看齐，实现单 AZ 99.975% 的可用水平，还有跨 AZ 99.995% 的可用性。这暗示柔性算力没有以牺牲稳定性为交换代价，而是可直接承受核心业务负载的基础设施形态。除了稳定性这一点，规模化使用还取决于运维体系自身是否具有确定性，Flexus X 实例在华为云既有的 SRE 运维体系框架内运行，强调借助标准化变更、容量预测与故障演练减少系统行为的不确定性，实现大规模实例并发运行的可控性。从行业落地的实际来看，柔性算力最先进入的并非那种单一业务场景，而是负载结构繁杂、资源使用波动大的系统类型。其已经在医疗电商平台迁移、连锁零售系统、医药行业信息化平台、游戏服务器迁移等场景大规模部署，用以承载数据库、中间件及核心交易服务。中软国际智能集团云业务部副总经理王春玉在发布会上分享，团队为某大型生物医药集团搭建系统的时候，引入 Flexus X 实例作为数据库及业务服务的主要承载环境，在原有系统架构未改变的情形下完成迁移，而且在性能满足要求的前提下，达成约 30% 的综合成本下降。王春玉还谈到，其团队服务的一家专业酒水直营连锁品牌，把部分核心业务迁移到 Flexus X 实例而后，通过规格按需匹配与资源利用率优化，实现整体云资源成本约 15% 的下降。这些亮眼的结果主要源于两方面：一是实例规格跟业务负载的匹配度有所提升，降低了长期闲置资源的数量；二是借助应用级加速与调度优化，降低了单位业务量所需的算力规模。从这些真实的实际部署案例能看出，Flexus X 实例的用户一般有几个共同特性：业务负载呈现明显波动，系统结构相对复杂，然而运维及架构团队的规模较为有限，同时对长期云资源的成本敏感度较高。Flexus X 实例在未对业务形态本身作出改变的情况下，却降低了基础设施对业务扩展所施加的约束强度，让按照业务形态去配置算力成为可践行的工程实践。可以预见，未来企业买的不再是服务器，而是业务效率。Flexus X 实例凸显了云服务器设计思路的一次转向：由“卖规格”过渡到“交付能力”，从“静态资源”过渡到“智能算力”，在 AI 成为主流计算负载的未来，此种转变大概率不会再是差异化优势，而是云基础设施的必要门槛。
本次版本 新增函数对象转换能力，扩展了达梦等多数据库迁移适配范围，并提升了批量转换的处理效率，进一步降低企业级数据库迁移的复杂度与成本。一、核心特性支持函数对象迁移​函数对象可随存储过程的迁移任务一键同步转换​。该能力的加入，让 SQLShift[1] 从一款“​存储过程迁移工具​”升级为“​核心业务逻辑对象全量迁移工具​”。随之也带来三重提升：降低迁移风险与人工成本避免 函数对象 需人工逐个改写与反复校验，大幅减少因语法差异、返回值不一致引发的运行期错误。提升非表对象整体迁移效率函数对象与存储过程 可在同一时间中完成迁移与校验，缩短整体迁移周期。保障业务逻辑完整性与可用性避免 函数对象 缺失导致上层存储过程等对象无法编译或运行的问题，有效降低迁移后集中调试与返工压力，提升割接与上线的稳定性。 新增数据库迁移组合本次升级，SQLShift 扩展了多项数据库迁移组合。新增 Oracle / OceanBase → 达梦降低了迁移至达梦数据库的复杂度和人工成本，帮助企业快速完成数据库替换或国产化改造。新增 PostgreSQL → OceanBase（Oracle 模式）减少了跨数据库迁移中的人工调整工作量，加快了从 PostgreSQL 向 OceanBase 的迁移进程。二、其他更新批量处理能力提升支持同时上传多个 SQL 文件进行转换，提升大规模迁移场景下的处理效率。免费试用限时开放！👉 点击领取 你的转换额度，立即体验 SQLShift 智能化迁移带来的飞跃效率！🧩 SQL 方言再多，转换也能一步到位，SQLShift 为你搞定！
PHP 网站重构， Rust/ Python + PostgreSQL + astro+solid，大家觉得怎么样子
如题，传统 php 网站，mysql 数据库，一些 crud 等，pdf 、excel 等处理准备重构：后端 Rust+python 微服务处理 pdf 、excel 等前端 astro+solid数据库 PostgreSQL部署 Podman大家觉得如何，有没有更优化的组合。前几天我还在用 Go ，但是，因为感觉很多人倾向于 Rust 替代 Go ，所有把 Go 替换成 Rust 在试一试
奥特曼小号泄密：OpenAI 代码工作 100% 交给 Codex！工程师才揭底 Codex“大脑”运行逻辑，碾压 Claude 架构？
整理 | 华卫 用一个 PostgreSQL 主库和 50 个只读副本，就顶住了 ChatGPT 上的 8 亿用户！ 近日，OpenAI 的工程师们不仅爆出了这一惊人消息，还直接把 Codex 的“大脑”给扒了个精光。在 OpenAI 官方工程博客主页，OpenAI 工程师、Technical Staff 成员 Michael Bolin 发布了一篇文章，以“揭秘 Codex 智能体循环”为题，深入揭秘了 Codex CLI 的核心框架：智能体循环（Agent Loop），并详细讲解了 Codex 在查询模型时如何构建和管理其上下文，以及适用于所有基于 Responses API 构建智能体循环的实用注意事项和最佳实践。 这些消息传出后，在 Hacker News 等技术论坛及社交平台上获得了高度关注。“看似平淡的技术最终会胜出。OpenAI 正在证明，优秀的架构远胜于花哨的工具。” 值得一提的是，有网友透露，前不久 Anthropic 的一位工程师称“他们用于 Claude Code UI 的架构糟糕且效率低下”。而就在刚刚，X 上出现一条爆料：Codex 已接管 OpenAI 100%的代码编写工作。 对于“你们有多少百分比的编码工作是基于 OpenAI 模型进行”的问题，roon 表示，“100%，我不再写代码了。”而此前，Sam Altman 曾公开发帖称，“roon 是我的小号。” Codex 的“大脑”揭秘“每个人工智能智能体的核心都是 Agent Loop，负责协调用户、模型以及模型调用以执行有意义的软件工作的工具之间的交互。” 据介绍，在 OpenAI 内部，“Codex”涵盖了一系列软件智能体产品，包括 Codex CLI、Codex Cloud 和 Codex VS Code 插件，而支撑它们的框架和执行逻辑是同一个。 Agent Loop 的简化示意图 首先，智能体会从用户那里接收输入，并将其纳入为模型准备的文本指令集，该指令集被称为提示词。下一步是通过向模型发送指令并要求其生成响应来查询模型，这个过程称为推理。推理过程中，文本提示词首先被转换为一系列输入 token，随后被用于对模型进行采样，生成新的输出 token 序列。输出 token 会被还原为文本，成为模型的回复。由于 token 是逐步生成的，该还原过程可与模型的运行同步进行，这也是众多基于大语言模型的应用支持流式输出的原因。实际应用中，推理功能通常封装在文本 API 后方，从而抽象化词元化的细节。 推理步骤完成后，模型会产生两种结果：（1）针对用户的原始输入生成最终回复；（2）要求智能体执行某项工具调用操作。若为第二种情况，智能体将执行该工具调用并将工具输出结果附加至原始提示词中。该输出结果会被用于生成新的输入内容，再次对模型进行查询；智能体随后会结合这些新信息，重新尝试完成任务。这一过程会不断重复，直至模型停止发出工具调用指令，转而生成面向用户的消息（在 OpenAI 的模型中，该消息被称为助手消息）。多数情况下，这条消息会直接解答用户的原始请求，也可能是向用户提出的跟进问题。 由于智能体可执行能对本地环境进行修改的工具调用，其 “输出” 并不仅限于助手消息。在很多场景下，软件智能体的核心输出是在用户设备上编写或编辑的代码。但无论何种情况，每一轮交互最终都会以一条助手消息收尾，该消息是智能体循环进入终止状态的信号。从智能体的角度来看，其任务已完成，操作控制权将交还给用户。 多轮智能体循环 这意味着，对话内容越丰富，用于模型采样的提示词长度也会随之增加。而所有模型都存在上下文窗口限制，即其单次推理调用可处理的 token 最大数量，智能体可能在单次对话轮次中发起数百次工具调用，这有可能耗尽上下文窗口的容量。因此，上下文窗口管理是智能体的多项职责之一。这套智能体循环如何运行？据介绍，Codex 正是借助响应 API 来驱动这套智能体循环的，博文曝出许多背后的实际运行细节，包括：Codex 不会把用户的话直接给大模型用，而是会主动“拼接”出一整套精心设计的提示词结构，且涵盖多个角色的指令、用户输入的一句话在结尾才出现。模型推理与工具调用之间可能会进行多轮迭代，提示词的内容会持续增加。构建初始提示词作为终端用户，在调用响应 API 时无需逐字指定用于模型采样的提示词，只需在查询中指定各类输入类型，由响应 API 服务器决定如何将这些信息组织为模型可处理的提示词格式。在初始提示词中，列表中的每个条目均关联一个角色。该角色决定了对应内容的权重占比，优先级从高到低分为以下几类：系统、开发者、用户、助手。 响应 API 接收包含多个参数的 JSON 负载，其中三个核心参数有：指令：插入模型上下文的系统（或开发者）消息工具：模型生成回复过程中可调用的工具列表输入：向模型传入的文本、图片或文件输入列表 在 Codex 中，若已配置，指令字段的内容会从～/.codex/config.toml 配置文件中的模型指令文件读取；若未配置，则使用与该模型关联的基础指令。模型专属指令存储在 Codex 代码仓库中，并被打包至命令行工具中。工具字段为符合响应 API 定义的模式的工具定义列表。对于 Codex 而言，该列表包含三部分工具：Codex 命令行工具自带的工具、响应 API 提供且开放给 Codex 使用的工具，以及通常由用户通过 MCP 服务器提供的自定义工具。JSON 负载的输入字段为一个条目列表。在添加用户消息前，Codex 会先向该输入中插入以下条目： 1. 一条角色为开发者（role=developer）的消息，用于描述仅适用于工具部分中定义的 Codex 内置 Shell 工具的沙箱环境。也就是说，其他工具（如由 MCP 服务器提供的工具）并不受 Codex 的沙箱限制，需自行负责实施自身的防护规则。该消息基于模板构建，核心内容均来自打包在 Codex 命令行工具中的 Markdown 代码片段。2.一条角色为开发者的消息，其内容为从用户的 config.toml 配置文件中读取的 developer_instructions 配置值。3.一条角色为用户的消息，其内容为用户指令；该内容并非来源于单个文件，而是从多个数据源聚合而来。一般而言，表述越具体的指令，排序越靠后：加载 $CODEX_HOME 目录下 AGENTS.override.md 和 AGENTS.md 文件的内容在默认 32 千字节的大小限制内，从当前工作目录对应的 Git / 项目根目录（若存在）向上遍历至当前工作目录本身，加载任意 AGENTS.override.md、AGENTS.md 文件的内容，或加载 config.toml 配置文件中 project_doc_fallback_filenames 参数指定的任意文件内容若已配置相关技能，则补充以下内容：关于技能的简短引言、各技能对应的技能元数据、技能使用方法说明章节。4. 一条角色为用户的消息，用于描述智能体当前的运行本地环境，其中会明确当前工作目录及用户所使用的终端 Shell 信息。 当 Codex 完成上述所有计算并完成输入初始化后，会追加用户消息以启动对话。需注意的是，输入中的每一个元素都是一个 JSON 对象，包含类型、角色和内容三个字段。当 Codex 构建好要发送至响应 API 的完整 JSON 负载后，会根据～/.codex/config.toml 中响应 API 端点的配置方式，携带授权请求头发起 HTTP POST 请求（若有指定，还会添加额外的 HTTP 请求头和查询参数）。当 OpenAI 响应 API 服务器接收到该请求后，会使用 JSON 数据来推导出模型的提示信息，（需要说明的是，Responses API 的自定义实现可能会采用不同的方法）。 可见，提示词中前三项的顺序由服务器决定，而非客户端。也就是说，这三项里仅系统消息的内容同样由服务器控制，工具与指令则均由客户端决定。紧随其后的是 JSON 负载中的输入内容，至此提示词拼接完成。模型采样提示词准备就绪后，模型才开始进行进行采样。 第一轮交互：此次向响应 API 发起的 HTTP 请求，将启动 Codex 中对话的第一轮交互。服务器会以服务器发送事件（SSE）流的形式进行响应，每个事件的数据均为一个 JSON 负载，其 type 字段以 response 开头。Codex 接收该事件流并将其重新发布为可供客户端调用的内部事件对象。`response.output_text.delta`这类事件用于为用户界面实现流式输出功能，而`response.output_item.added`等其他事件则会被转换为对象，附加至输入内容中，为后续的响应 API 调用所用。 若首次向响应 API 发起的请求返回两个`response.output_item.done`事件，一个类型为推理（reasoning），一个类型为函数调用（function_call），那么当结合工具调用的返回结果再次向模型发起查询时，这些事件必须在 JSON 的输入字段中进行体现。后续查询中用于模型采样的最终提示词结构如下： 需要特别注意的是，旧提示词是新提示词的完整前缀。这一设计是有意为之的，因为它能让用户借助提示词缓存提升后续请求的效率。 在 Codex 命令行工具中，会将助手消息展示给用户，并聚焦输入编辑区，以此提示用户轮到其继续对话。若用户做出回应，上一轮的助手消息以及用户的新消息均需附加至响应 API 请求的输入字段中，从而开启新一轮对话。同样，由于对话处于持续进行的状态，发送至响应 API 的输入内容长度也会不断增加。 弃用简单参数费力做优化，就为了用户隐私？“在对话过程中，发送至响应 API 的 JSON 数据量，是否会让智能体循环的时间复杂度达到二次方级别？”答案是肯定的。 据悉，尽管响应 API 支持通过可选的 previous_response_id 参数缓解这一问题，但目前 Codex 并未启用该参数，主要是为了保证请求完全无状态，并兼容零数据保留（ZDR） 配置，即不存储用户对话数据。 取而代之的，是两套需投入大量研发精力、涉及复杂实施流程的技术策略。文中，OpenAI 详细介绍了这两项硬核优化的具体方案。 通常，模型采样的开销远高于网络传输的开销，采样环节会成为优化效率的核心目标，这也是提示词缓存至关重要的原因，它能复用前一次推理调用的计算结果。当缓存命中时，模型采样的时间复杂度将从二次方降至线性。OpenAI 相关的提示词缓存文档对这一机制有更详细的说明：仅当提示词存在完全匹配的前缀时，才有可能实现缓存命中。为充分发挥缓存的优势，需将指令、示例等静态内容置于提示词开头，而将用户专属信息等可变内容放在末尾。这一原则同样适用于图片和工具，且其内容在各次请求中必须保持完全一致。 基于这一原则，Codex 中可能有以下导致缓存未命中的操作：在对话过程中修改模型可调用的工具列表；更换响应 API 请求的目标模型（实际场景中，这会改变原始提示词中的第三项内容，因该部分包含模型专属指令）；修改沙箱配置、审批模式或当前工作目录。 因此，Codex 团队在为命令行工具开发新功能时，必须审慎考量，避免新功能破坏提示词缓存机制。例如，他们最初对 MCP 工具的支持曾出现一个漏洞：工具的枚举顺序无法保持一致，进而导致缓存未命中。需要注意的是，MCP 工具的处理难度尤为突出，因为 MCP 服务器可通过 notifications/tools/list_changed 通知，动态修改其提供的工具列表。若在长对话过程中响应该通知，极易引发高成本的缓存未命中问题。 在可能的情况下，针对对话过程中发生的配置变更，他们会通过在输入中追加新消息的方式体现变更，而非修改已有的早期消息：若沙箱配置或审批模式发生变更，我们会插入一条新的role=developer消息，格式与原始的条目保持一致；若当前工作目录发生变更，我们会插入一条新的role=user消息，格式与原始的条目保持一致。 据介绍，为保障性能，OpenAI 在实现缓存命中方面投入了大量精力。除此之外，他们还重点管理了一项核心资源：上下文窗口。 其规避上下文窗口耗尽的通用策略是：一旦词元数量超过某个阈值，就对对话进行压缩。具体来说，会用一个更精简、且能代表对话核心内容的新条目列表替代原有输入，让智能体在继续执行任务时仍能理解此前的对话过程。早期的压缩功能实现方案，需要用户手动调用/compact 命令，该命令会结合现有对话内容和自定义的摘要生成指令，向响应 API 发起查询；Codex 则会将返回的、包含对话摘要的助手消息，作为后续对话轮次的新输入。 此后，响应 API 不断迭代，新增了专用的/responses/compact 端点，能以更高效率完成压缩操作。该端点会返回一个条目列表，可替代原有输入继续对话，同时释放出更多的上下文窗口空间。该列表中包含一个特殊的 type=compaction 条目，其附带的 encrypted_content 加密字段为透明化设计，可保留模型对原始对话的潜在理解。 现在，当词元数量超过 auto_compact_limit 自动压缩阈值时，Codex 会自动调用该端点对对话内容进行压缩。极限扩容：用 1 个数据库扛住了 8 亿用户在另一篇技术博文中，OpenAI 工程师 Bohan Zhang 介绍， OpenAI 通过严苛的技术优化与扎实的工程实践，对单个数据库 PostgreSQL 进行深度扩容，实现以单套体系支撑 8 亿用户、每秒数百万次查询的访问需求。 据称，多年来，PostgreSQL 一直是支撑 ChatGPT、OpenAI API 等核心产品的核心底层数据系统之一。过去一年，公司 PostgreSQL 的负载增长超 10 倍，且这一增长趋势仍在持续加速。OpenAI 称，PostgreSQL 的横向扩展能力远超此前行业普遍认知，能够稳定支撑规模大得多的读密集型工作负载。“这套最初由加州大学伯克利分校的科学家团队研发的系统，助力我们通过单主节点 Azure PostgreSQL 弹性服务器实例，搭配分布在全球多个区域的近 50 个只读副本，承接了海量的全球访问流量。” 而且，OpenAI 表示，其扩容在实现规模提升的同时，始终将延迟控制与可靠性优化放在核心位置：生产环境中，客户端 99 分位延迟稳定保持在十几毫秒的低水平，服务可用性达到五个九标准；过去 12 个月内，PostgreSQL 仅出现过一次零级严重故障，该故障发生在 ChatGPT 图像生成功能爆红上线期间，一周内超 1 亿新用户注册导致写流量突发暴涨超 10 倍。 尽管 PostgreSQL 的扩容成果已达预期，OpenAI 仍在持续探索其性能极限。目前，他们已将可分片的写密集型业务负载迁移至 CosmosDB 等分片式数据库系统；对于分片难度更高的剩余写密集型负载，相关迁移工作也在积极推进，以此进一步减轻 PostgreSQL 主节点的写压力。同时，OpenAI 正与微软 Azure 团队展开合作，推动级联复制功能落地，实现只读副本的安全、大规模扩容。随着基础设施需求的持续增长，其将继续探索更多扩容方案，包括基于 PostgreSQL 的分片架构改造、引入其他分布式数据库系统等。 有网友评价道，“这招的高明之处，就在于极简。他们没用什么花里胡哨的冷门技术，不过是把最佳实践做到了极致。过去十年，行业里全是 ‘一切皆分片、拥抱 NoSQL、全面分布式，为 CAP 定理折腰’ 的论调，而 OpenAI 倒好， 服务十亿级用户的解法，居然只是一句‘试过加只读副本吗？’” 参考链接：https://openai.com/index/unrolling-the-codex-agent-loop/https://openai.com/index/scaling-postgresql/
Spring Boot 3 集成 Apache Calcite：多数据源查询的终极解决方案
熟悉 Spring Boot 3 的开发者，都知道它在简化开发流程、提高开发效率方面的出色表现吧！但是，在实际业务场景中，大家肯定都碰到过这样的棘手问题：订单数据存放在 MySQL 里，库存数据在 PostgreSQL 中，用户数据又保存在 MongoDB 中，当多种数据源同时存在时，想要实现统一查询简直比登天还难。所以呢，今天我就亮出我的“终极大招”——Apache Calcite，着重给大家讲讲它怎样与 Spring Boot 3 实现无缝集成，还会分享一些可以直接拿来使用的经典应用场景。掌握了这一招，多数据源查询的难题就能轻松解决啦！一、核心认知：Apache Calcite 为何是多数据源查询的利器？在动手集成前，咱们先把核心逻辑搞明白：为啥 Calcite 能成为多数据源查询的“万能钥匙”？它的核心优势到底在哪？1.1 不止是查询引擎：Calcite 的核心定位Apache Calcite 本质是一个动态数据管理框架，而非传统的数据库。它最核心的价值在于“解耦”——将数据存储与数据查询分离，无论数据存在哪里、是什么格式，都能通过统一的 SQL 接口进行查询。说通俗点，Calcite 就像个“超级数据翻译官”——不管数据藏在哪个数据源里、是什么格式，你只要写一套标准 SQL，它就能翻译成对应数据源能懂的指令，最后把结果整理成统一格式返回。这也是它能搞定多数据源查询的核心秘诀！1.2 Calcite 的核心能力拆解统一 SQL 接口：支持标准 SQL，无论底层是关系型数据库（MySQL、PostgreSQL）、非关系型数据库（MongoDB、Redis），还是文件（CSV、Parquet）、大数据引擎（Hive、Spark），都能通过同一套 SQL 查询。强大的查询优化：内置基于规则和成本的查询优化器，能自动优化 SQL 执行计划，提升查询效率，尤其是在复杂多表关联、跨数据源查询场景下，优化效果明显。灵活的数据源适配：通过“适配器（Adapter）”机制适配不同数据源，社区已提供大量现成适配器，也支持自定义开发，适配特殊数据源。轻量级集成：核心依赖体积小，无复杂依赖，可轻松集成到 Spring Boot、Spring Cloud 等主流 Java 开发框架中，无需单独部署独立服务（也支持独立部署）。二、重点实战：Spring Boot 3 集成 Calcite 核心步骤既然大家都熟悉 Spring Boot 3 的基础操作，我就不啰嗦项目搭建这些常规步骤了，直接聚焦 Calcite 集成的核心环节，每一步都附完整代码和避坑提醒，跟着做就能成！2.1 核心依赖引入第一步先引依赖，在 pom.xml 里加好 Calcite 核心包、对应数据源的适配器，再配上 MyBatis Plus 的核心依赖（替换掉原来的 Jdbc 依赖就行），具体如下： <dependency> <groupId>org.apache.calcite</groupId> <artifactId>calcite-core</artifactId> <version>1.36.0</version> </dependency> <dependency> <groupId>org.apache.calcite</groupId> <artifactId>calcite-mysql</artifactId> <version>1.36.0</version> </dependency> <dependency> <groupId>org.apache.calcite</groupId> <artifactId>calcite-mongodb</artifactId> <version>1.36.0</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.20</version> </dependency>这里有 3 个避坑点必须强调下：Calcite 所有组件版本要统一，不然容易出现类加载异常；MyBatis Plus 得选适配 Spring Boot 3 的版本（3.5.3+）；一定要加连接池依赖，不然 Calcite 数据源没法被 MyBatis Plus 正常管理。2.2 核心配置：Calcite 模型文件编写模型文件是 Calcite 识别数据源的关键，一般用 JSON 格式，放在 resources 目录下命名为 calcite-model.json 就行。下面给大家一个适配 MySQL 和 MongoDB 双数据源的示例，直接改改连接信息就能用：{ "version": "1.0", "defaultSchema": "ecommerce", "schemas": [ { "name": "ecommerce", "type": "custom", "factory": "org.apache.calcite.adapter.jdbc.JdbcSchema$Factory", "operand": { "jdbcUrl": "jdbc:mysql://localhost:3306/ecommerce_order?useSSL=false&serverTimezone=UTC", "username": "root", "password": "123456", "driver": "com.mysql.cj.jdbc.Driver" } }, { "name": "user_mongo", "type": "custom", "factory": "org.apache.calcite.adapter.mongodb.MongoSchema$Factory", "operand": { "host": "localhost", "port": 27017, "database": "user_db", "collection": "user_info" } } ] }几个关键配置给大家解释清楚，避免踩坑：defaultSchema：默认查询的 Schema，可省略，查询时需指定 Schema 名称（如 ecommerce.order、user_mongo.user_info）。factory：对应数据源的适配器工厂类，Calcite 已为主流数据源提供现成工厂，自定义数据源需实现自己的 Factory。operand：数据源连接参数，根据数据源类型不同配置不同参数（如 MySQL 的 jdbcUrl、MongoDB 的 host/port）。2.3 Spring Boot 集成 Calcite + MyBatis Plus 核心配置这一步是核心，主要分两步走：配置好 Calcite 数据源；让 MyBatis Plus 用上这个数据源，顺便把 mapper 扫描、分页插件这些基础参数配好。直接上配置类代码：import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.apache.calcite.jdbc.CalciteConnection; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; import java.sql.Connection; import java.sql.DriverManager; import java.util.Properties; @Configuration // MyBatis Plus mapper 接口扫描（指定 mapper 包路径） @MapperScan(basePackages = "com.example.calcite.mapper") public class CalciteMybatisPlusConfig { // 1. 配置 Calcite 数据源（核心，与原逻辑一致） @Bean public DataSource calciteDataSource() throws Exception { Properties props = new Properties(); props.setProperty("model", "classpath:calcite-model.json"); Connection connection = DriverManager.getConnection("jdbc:calcite:", props); CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class); return calciteConnection.getDataSource(); } // 2. 配置 MyBatis Plus 的 SqlSessionFactory，指定使用 Calcite 数据源 @Bean public SqlSessionFactory sqlSessionFactory(DataSource calciteDataSource) throws Exception { MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean(); // 注入 Calcite 数据源 sessionFactory.setDataSource(calciteDataSource); // 配置 mapper.xml 文件路径（如果使用 XML 方式编写 SQL） sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/*.xml")); // 配置 MyBatis Plus 全局参数（可选） org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(true); // 下划线转驼峰 sessionFactory.setConfiguration(configuration); // 注入 MyBatis Plus 插件（如分页插件） sessionFactory.setPlugins(mybatisPlusInterceptor()); return sessionFactory.getObject(); } // 3. MyBatis Plus 分页插件（可选，复杂查询分页用） @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 适配 Calcite 兼容的 MySQL 语法 return interceptor; } // 4. 配置事务管理器（可选，需要事务支持时添加） @Bean public PlatformTransactionManager transactionManager(DataSource calciteDataSource) { return new DataSourceTransactionManager(calciteDataSource); } }核心逻辑给大家捋一捋：先通过 Calcite 创建统一的数据源，再把它注入到 MyBatis Plus 的 SqlSessionFactory 里。这样一来，咱们后续写代码就完全是 MyBatis Plus 的熟悉风格了，不管是 Mapper 接口还是 XML 映射文件，都能直接用，跨数据源查询的复杂逻辑全交给 Calcite 处理。2.4 核心查询实现（MyBatis Plus 风格）接下来就是大家最熟悉的查询实现环节了，我用 MyBatis Plus 最常用的“Mapper 接口+注解”和“XML”两种方式来演示，还是以 MySQL 订单表和 MongoDB 用户表的关联查询为例，大家可以根据自己的习惯选：(1)定义实体类（对应跨数据源查询结果，可使用 lombok 简化代码）import lombok.Data; @Data public class UserOrderVO { private String orderId; // 订单 ID（来自 MySQL） private String orderTime; // 下单时间（来自 MySQL） private BigDecimal amount; // 订单金额（来自 MySQL） private String userName; // 用户名（来自 MongoDB） private String phone; // 手机号（来自 MongoDB） private String userId; // 用户 ID（关联字段） }(2)定义 Mapper 接口（MyBatis Plus 风格，无需编写实现类）import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; // 继承 BaseMapper，获得 MyBatis Plus 基础 CRUD 能力 public interface UserOrderMapper extends BaseMapper<UserOrderVO> { // 注解方式编写跨数据源关联 SQL @Select("SELECT " + "o.order_id AS orderId, o.order_time AS orderTime, o.amount, " + "u.user_name AS userName, u.phone, o.user_id AS userId " + "FROM ecommerce.order o " + // ecommerce：MySQL 的 Schema；order：订单表 "JOIN user_mongo.user_info u " + // user_mongo：MongoDB 的 Schema；user_info：用户表 "ON o.user_id = u.user_id " + "WHERE o.user_id = #{userId}") List<UserOrderVO> queryUserOrderByUserId(@Param("userId") String userId); }(3)编写 Service 层import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserOrderServiceImpl extends ServiceImpl<UserOrderMapper, UserOrderVO> implements UserOrderService { @Override public List<UserOrderVO> getUserOrderByUserId(String userId) { // 调用 Mapper 接口方法，实现跨数据源查询 return baseMapper.queryUserOrderByUserId(userId); // 若使用 XML 方式：return baseMapper.queryUserOrderByUserIdWithXml(userId); } }(4)编写 Controller 层import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class CrossDataSourceQueryController { @Autowired private UserOrderService userOrderService; @GetMapping("/user/order/{userId}") public List<UserOrderVO> queryUserOrder(@PathVariable String userId) { // 调用 Service 方法，返回跨数据源查询结果 return userOrderService.getUserOrderByUserId(userId); } }最后再划 3 个重点，确保大家少走弯路：实体类字段要和查询结果列名对应，用别名适配下划线转驼峰更省心；Mapper 接口继承 BaseMapper 后，MyBatis Plus 的分页、条件构造器这些功能都能直接用，复杂查询也能轻松搞定；咱们写的都是标准 SQL，Calcite 会自动解析适配不同数据源，完全不影响大家原来的开发习惯。三、深度解析：Calcite 的经典使用场景讲完了集成步骤，再跟大家深度拆解下 Calcite 的经典落地场景。毕竟技术最终要服务于业务，这些场景都是我在实际项目中常用到的，拿来就能用！第一个经典场景是多系统数据融合查询，这也是企业级中台的核心需求。做企业级中台的小伙伴肯定深有体会，大型企业里数据都是分散的——订单系统用 MySQL，用户系统用 MongoDB 存行为数据，库存系统用 PostgreSQL。要是想做“用户-订单-库存”全链路分析，传统做法得分别调三个系统的接口，再在业务层手动整合数据，不仅效率低，还容易出错。用 Calcite 分别适配这三个数据源后，只要写一套标准 SQL 就能实现跨数据源关联查询，咱们用 Spring Boot 3 搭好接口服务，业务层完全不用管数据存在哪，专注核心业务逻辑就行，亲测开发效率能提升 50%以上，再也不用写重复的接口调用和数据整合代码，而且 Calcite 的查询优化器会自动优化关联逻辑，查询效率也能跟上。第二个场景是实时数据与离线数据联动查询，做电商的小伙伴应该经常遇到这类需求。比如实时订单数据存在 Kafka 里，历史订单数据存在 Hive 里，运营需要实时查看“今日订单+近 30 天历史订单”的汇总数据来做实时监控和决策。这种情况不用麻烦地把 Kafka 数据同步到 Hive，也不用把 Hive 数据同步到实时库，直接用 Calcite 的 Kafka 适配器（calcite-kafka）和 Hive 适配器（calcite-hive），就能把实时流数据和离线数据放到同一个查询体系里，写一条 SQL 就能实现“实时+离线”数据的联合查询，既省了大量数据同步成本，又能兼顾实时性和准确性，还支持增量查询。第三个场景是自定义数据源适配，主要解决特殊格式数据查询的难题。企业里总有很多 CSV、Excel、Parquet 格式的文件数据，传统做法是先把这些文件导入数据库才能查询，步骤又多又耗时，尤其是临时做数据分析的时候，导入数据库的成本太高了。而 Calcite 内置了文件适配器（calcite-file），支持直接查询这些文件数据，根本不用导入数据库。咱们再结合 Spring Boot 3 的文件上传功能，还能实现“文件上传后直接用 SQL 查询”的需求，临时分析数据超方便。如果有企业内部的特殊格式文件，比如自定义的二进制文件，也可以自己实现 Calcite 的 SchemaFactory 和 TableFactory 接口，写个自定义适配器，就能适配这些特殊数据源了。四、避坑指南：集成注意事项与优化建议4.1 这些坑一定要避开！适配器版本要统一：Calcite 核心依赖和各数据源适配器的版本必须一致，不然很容易出现类加载异常，这个坑我踩过，大家一定要注意。模型文件配置要规范：Schema 名称、表名要清晰，别重复；数据源的地址、端口、账号密码这些连接参数一定要准确，错一个就会连接失败。要考虑数据源性能：跨数据源查询的性能取决于最慢的那个数据源，所以要确保每个数据源自身性能没问题，不然会拖慢整个查询。4.2 优化小技巧，查询更快更稳启用 Calcite 缓存：配置一下 Calcite 的元数据缓存和查询计划缓存，能减少重复解析和元数据查询的时间，提升查询效率。优化 SQL 写法：尽量避免复杂的多表关联，能把过滤条件下推到数据源的就尽量下推。虽然 Calcite 会自动优化，但手动优化后的效果会更好。自定义优化规则：如果是特别复杂的业务场景，可以自己实现 Calcite 的 OptimizerRule 接口，写自定义的查询优化规则，进一步提升查询效率。五、本文总结最后总结一下，对于熟悉 Spring Boot 3 的咱们来说，集成 Calcite 的关键就是理解它“统一查询”的核心思想，把模型文件写对、核心 Bean 配置好，就能快速实现多数据源查询能力了。https://mybj123.com/28732.html
前言前阵子写的日志分析工具NginxPulse，自开源以来，已过去 2 周时间，目前 GitHub 已收获 1.5k 的 star 。收到了不少用户的反馈建议，花了点时间将这些问题都处理了下。本文就跟大家分享下新版本都解决了哪些问题，优化了哪些内容，欢迎各位感兴趣的开发者阅读本文。抛弃 SQLite有不少用户反馈说日志文件很大的时候（ 10G+），解析速度非常慢，需要解析好几个小时，解析完成之后数据看板的查询也比较慢（接口响应在 5 秒左右）。于是，我重写了日志解析策略（解析阶段不做 IP 归属地查询，仅入库其他数据，将日志中 IP 记录起来），日志解析完毕后，将记录的 IP 做去重处理，随后去做归属地的查询处理（优先本地的 ip2region 库，远程的 API 调用查询做兜底），最后将解析到的归属地回填至对应的数据库表中，这样一套下来就可以大大提升日志的解析速度。数据库的数据量大了之后，SQLite 的表现就有点差强人意了，请教了一些后端朋友，他们给了我一些方案，结合我自身的实际场景后，最后选定了 PostgreSQL 作为新的数据库选型。这套方案落地后，用户群的好兄弟说：他原先需要解析 1 个小时的日志，新版只需要 10 多分钟。UI 配置可视化使用有一部分用户反馈说他非专业人士，这些晦涩的配置对他来说使用门槛太高了，希望能有一个 UI 配置页面，他只需要点一点、敲敲键盘，就能完成这些配置。我将整个配置流程做成了 4 步，同时也准备一个[演示视频](NginxPulse 支持 UI 配置化了) - https://www.bilibili.com/video/BV1hqzyBVEU9： 配置站点 配置数据库 配置运行参数 确认最终配置 新增 wiki 文档因为配置过于庞大，仓库主页浏览 README.md 比较费劲，希望能整理一份 wiki 文档发上去。花了点时间，简化了下 README ，整理了一份： https://github.com/likaia/nginxpulse/wiki访问明细模块优化有部分用户反馈说希望增加更多的筛选条件以及导出 Excel 功能，现在它来了：概况模块优化概况页面的日期筛选之前放在趋势分析卡片的上方，但是他的切换影响的维度还包含了指标，于是我就调整了下它的位置，新版如下图所示：项目地址 GitHub 地址： https://github.com/likaia/nginxpulse dockerhub 地址： https://hub.docker.com/r/magiccoders/nginxpulse/ 写在最后至此，文章就分享完毕了。我是神奇的程序员，一位前端开发工程师。如果你对我感兴趣，请移步我的个人网站，进一步了解。