Novu ClickHouse 迁移体系详解:基于 clickhouse-migrations 的 SQL 迁移工作流与实战
发布时间:2026/9/10 4:42:07 锦皓数字建站

Novu ClickHouse 迁移体系详解基于 clickhouse-migrations 的 SQL 迁移工作流与实战【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu本文面向 Novu开源通信基础设施仓库中apps/api/migrations/clickhouse-migrations/目录的 SQL 迁移机制完整讲解其迁移文件的命名规范、幂等 SQL 写作要求、本地与生产/暂存环境下的运行命令、CI/CD 集成方式以及排障手段并逐一剖析仓库中 6 个真实迁移文件的演进过程帮助你在接触或贡献 Novu 分析型analytic-logs存储层时安全、规范地管理 ClickHouse 表结构。ClickHouse 迁移目录在 Novu 中的定位Novu 使用 ClickHouse 存储工作流执行的分析型日志数据包括 step 执行记录、trace 事件、HTTP 请求日志、工作流运行实例等这些数据由analytic-logs服务持续写入和查询。为了像管理普通关系库一样管理 ClickHouse 的 SchemaNovu 在 apps/api/migrations/clickhouse-migrations/ 目录下集中存放 SQL 迁移文件并通过clickhouse-migrationsnpm 包统一执行。这套机制的核心能力来自该目录 README.md自动迁移跟踪在 ClickHouse 中维护一张migrations表记录每个迁移文件的执行状态幂等执行每个迁移在每个数据库中只运行一次已应用的迁移不会重复执行简洁 CLI通过 npm script 暴露命令支持命令行参数与环境变量两种配置方式。创建新迁移命名规范与写作守则文件命名约定迁移文件必须遵循以下模式number_description.sql其中number是纯数字前缀决定执行顺序迁移按数字升序依次应用description用简短下划线分隔的英文描述该迁移的目的。仓库中真实文件名示例1_initial_schema.sql2_add_workflow_id_to_schema.sql3_analytics_tables.sql4_refactor_traces_schema.sql5_finalize_table_exchange.sql6_add_source_to_requests.sql迁移文件写作规则原文档给出了 5 条必须遵守的规则这些规则在仓库中每个迁移文件里都有对应实践1. 使用幂等 SQL。始终使用条件语句确保迁移可安全重跑CREATE TABLE IF NOT EXISTS my_table (...); ALTER TABLE my_table ADD COLUMN IF NOT EXISTS new_column String; CREATE INDEX IF NOT EXISTS idx_name ON my_table (column);仓库实例2_add_workflow_id_to_schema.sql 中全部使用ADD COLUMN IF NOT EXISTS6_add_source_to_requests.sql 同样以ALTER TABLE requests ADD COLUMN IF NOT EXISTS source ...结尾。2. 每个文件只做一种逻辑变更便于回滚与排查。仓库的拆分正是如此2 号文件只补workflow_id列6 号文件只加source列而涉及整体 Schema 重构的复杂流程则拆成 4、5 号两个文件分阶段完成。3. 写入注释说明目的与上下文。常见形式是变更含义 关联工单-- Add user timezone preference -- Ticket: NV-1234 ALTER TABLE users ADD COLUMN IF NOT EXISTS timezone String DEFAULT UTC;4. 一个文件可含多条语句以分号;分隔CREATE TABLE IF NOT EXISTS table1 (...); CREATE TABLE IF NOT EXISTS table2 (...);1_initial_schema.sql 正是如此单个文件内依次建出step_runs、traces、requests、workflow_runs四张表。5. 按需包含 ClickHouse 查询级设置例如启用实验性类型设置语句与 DDL 在同一文件内按顺序书写SET allow_experimental_json_type 1; CREATE TABLE IF NOT EXISTS events (data JSON) ENGINE MergeTree ...;仓库 6 个迁移文件全解析结合源码逐文件阅读可以完整还原 Novu ClickHouse Schema 的演进史这也是编写高质量迁移文件的绝佳范本。1_initial_schema.sql —— 建四张核心表这是初始 Schema见 1_initial_schema.sql为analytic-logs服务创建全部表step_runs工作流内单步执行记录。关键设计点引擎ReplacingMergeTree(updated_at)通过updated_at做版本去重允许对同一step_run_id以新数据替换旧数据PARTITION BY toYYYYMM(created_at)按月分区方便按时间裁剪旧数据ORDER BY (organization_id, step_run_id)TTL toDateTime(expires_at)基于expires_at到期自动删除落实数据留存策略step_type、status等维度列使用LowCardinality(String)优化压缩与查询。traces调试与监控用事件 trace引擎MergeTreeORDER BY (entity_type, organization_id, entity_id, created_at)并设置async_insert 1支持异步批量插入。requestsHTTP 请求日志ORDER BY (organization_id, environment_id, transaction_id, created_at)。workflow_runs完整工作流执行实例同样采用ReplacingMergeTree(updated_at)TTL toDateTime(expires_at)。2_add_workflow_id_to_schema.sql —— 补工作流模板 ID在step_runs与traces上分别追加workflow_id String DEFAULT 存储每条 step 执行/trace 所属的工作流模板 ID为后续按工作流维度聚合做铺垫。3_analytics_tables.sql —— 引入物化视图聚合该迁移展示了明细表 物化视图 汇总表的典型 ClickHouse 分析架构源码新建delivery_trend_counts引擎SummingMergeTree(count)物化视图delivery_trend_counts_mv实时消费step_runs中状态为completed且step_type属于in_app/email/sms/chat/push的行按天、租户、渠道累加投递量先给traces加provider_id列注释明确说明必须在创建引用它的物化视图之前添加这体现了迁移文件内语句的书写顺序约束新建trace_rollup与trace_rollup_mv消费traces中message_sent以及message_seen/read/snoozed/archived等交互事件。4_refactor_traces_schema.sql —— 以新表 物化视图完成 Schema 重构ClickHouse 修改ORDER BY无法原地完成因此这里采用建临时表 物化视图回流 分批回填策略源码值得仔细学习Step 0先把 14 个工作流运行列workflow_name、transaction_id、channels、payload、is_digest、severity、critical、context_keys等补到旧traces表确保后续 MV 数据能正确流入Step 1创建新表traces_temp新的ORDER BY (organization_id, environment_id, entity_type, toDate(created_at), entity_id)更贴近实际查询模式并对高频过滤列定义二级跳数索引idx_event_type、idx_workflow_id、idx_transaction_id同时把大量Nullable列收敛为带默认值的普通列以提升性能Step 2物化视图traces_to_traces_temp_mv只承接created_at 2026-02-03的新增数据历史数据注释明确另行通过INSERT SELECT回填Step 3–6再建delivery_trend_counts_temp、workflow_run_count及其临时物化视图为投递趋势与工作流运行计数铺路。5_finalize_table_exchange.sql —— EXCHANGE TABLES 原子换表收尾在回填全部完成后执行收尾迁移源码其中原子换表是真正的点睛之笔EXCHANGE TABLES traces AND traces_temp; EXCHANGE TABLES delivery_trend_counts AND delivery_trend_counts_temp;EXCHANGE TABLES让新旧表在一条语句内原子地互换数据与结构主表立即切换为优化后的 Schema期间写入不中断。紧接着按正确次序删除临时物化视图traces_to_traces_temp_mv、delivery_trend_counts_temp_mv、workflow_run_count_temp_mv→ 删除需要重建来源的delivery_trend_counts_mv→ 基于新traces表重建永久的delivery_trend_counts_mv与workflow_run_count_mv来源从step_runs迁移到traces→ 清理delivery_trend_counts_temptraces_temp因保留历史数据而刻意不删相关 DROP 语句被注释保留。文件头部的注释强调执行前提是traces_temp与delivery_trend_counts_temp的历史回填必须全部完成——这类前提约束正是复杂迁移的安全护栏。6_add_source_to_requests.sql —— 演进式小步变更最后一个小而完整的例子源码给requests加source LowCardinality(String) DEFAULT http。注释说明其语义存量行都是 HTTP API 请求故默认httpworker 写入的 inbound-email 请求日志则显式设为inbound_email。在本地运行迁移前置条件确保本地 ClickHouse 已通过 Docker Compose 启动。在仓库根目录执行docker-compose -f docker/local/docker-compose.yml up -d clickhouse执行迁移进入apps/api后使用仓库 apps/api/package.json 中定义的真实脚本。本地脚本对应原文档描述的硬编码连接值cd apps/api pnpm run clickhouse:migrate:local原文档中写为pnpm run clickhouse:migrate它实际对应的就是本仓库 package.json 中的clickhouse:migrate:local脚本。该本地脚本实际展开的命令为clickhouse-migrations migrate \ --hosthttp://localhost:8123 \ --userdefault \ --password \ --dbnovu-local \ --migrations-home./migrations/clickhouse-migrations其中连接信息与ClickHouseService在本地环境下createClient的默认值一致见 clickhouse.service.ts 中NODE_ENVlocal/test分支对http://localhost:8123、用户default、空密码的使用。脚本执行过程连接本地 ClickHouse 实例若不存在则创建migrations跟踪表按数字顺序执行所有尚未应用的迁移将已完成迁移标记为已应用。在生产/暂存环境运行迁移生产与暂存环境使用同样以仓库 package.json 中的实际脚本为准pnpm run clickhouse:migrate:prod该脚本不携带任何硬编码连接参数而是依赖clickhouse-migrations原生支持的环境变量环境变量含义示例/默认值CH_MIGRATIONS_HOSTClickHouse 服务器 URLhttp://clickhouse.example.com:8123CH_MIGRATIONS_USER数据库用户名defaultCH_MIGRATIONS_PASSWORD数据库密码按部署环境配置CH_MIGRATIONS_DB目标数据库名novu-localCH_MIGRATIONS_HOME迁移目录可选默认./migrations/clickhouse-migrations这些变量应在部署环境中设置如 CI 平台的 secrets、Kubernetes Secrets 等。从部署侧看运行时若配置了CLICK_HOUSE_URL与CLICK_HOUSE_DATABASEClickHouseService才会初始化客户端见 clickhouse.service.ts 的isClickHouseConfigured()判断迁移所管理的表正是该服务写入与查询的对象。CI/CD 集成迁移在部署前由 CI/CD 自动执行在发布流程中使用pnpm run clickhouse:migrate:prod即可在任何环境本地、staging、production、CI用同一命令、不同环境变量完成 Schema 升级。若某个迁移在 CI 中失败查看 CI 日志定位具体报错在本地修复迁移 SQL本地验证pnpm run clickhouse:migrate:local提交修复并重新触发部署。常用排障命令重置本地数据库并全量重跑# 删除本地数据库注意使用反引号转义库名 docker exec -it clickhouse_main clickhouse-client --query DROP DATABASE IF EXISTS \novu-local\ # 重新创建并执行全部迁移 pnpm run clickhouse:migrate:local说明本地容器名称以文档/仓库约定的clickhouse_main为准实际名称以你本地docker compose ps输出为准。查看迁移应用状态docker exec -it clickhouse_main clickhouse-client \ --query SELECT * FROM \novu-local\.migrations ORDER BY versionmigrations表由clickhouse-migrations自动维护version对应迁移文件的数字前缀升序展示即为应用历史。Schema 与 TypeScript 层的对应关系迁移文件管理的当前表集合与读写语义README 的 Schema Reference 所列step_runs—— 工作流内的单步执行traces—— 用于调试与监控的事件 tracerequests—— HTTP 请求日志workflow_runs—— 完整的工作流执行实例这些表的详细列定义可以从 libs/application-generic/src/services/analytic-logs/ 目录下的 TypeScript Schema 文件中对照阅读该目录按表拆分仓库层step-run/step-run.schema.ts定义step_runs表名与列类型并通过clickhouse-schema库生成ClickhouseSchema其中ORDER_BY [organization_id, step_run_id]、TTL expires_at、引擎ReplacingMergeTree(updated_at)、附加PARTITION BY toYYYYMM(created_at)与TTL toDateTime(expires_at)与 1 号迁移文件逐项对应。注释中还标出了各字段与 Dal 实体的映射关系如step_run_id映射JobEntity._id、workflow_run_id映射NotificationEntity._iddelivery-trend-counts/、trace-rollup/、workflow-run-count/对应物化视图聚合结果的查询仓库request-log/、workflow-run/对应requests、workflow_runs表log.repository.ts与clickhouse.service.ts提供统一的底层读写入口与连接管理。也就是说SQL 迁移是 Schema 的事实来源TypeScript Schema 是它的类型化镜像两者必须保持一致一旦通过新增迁移文件改表需要同步更新对应.schema.ts否则运行期可能出现类型与真实结构不匹配的问题。迁移实践要点小结综合原文档与仓库 6 个迁移文件可以提炼出 Novu ClickHouse 迁移工作的四个关键习惯命名即排序坚持number_description.sql让应用顺序一目了然全程幂等IF NOT EXISTS是标配宁可冗余不可重放出错复杂重构分阶段借助补列 → 建新表/临时 MV → 分批回填 →EXCHANGE TABLES原子切换 → 重建永久 MV → 清理临时对象的流程把大重构拆成 4、5 号这种可独立验证的迁移配合注释写明前提条件与先后顺序约束本地/生产同一套文件本地靠脚本内硬编码连接生产靠CH_MIGRATIONS_*环境变量但迁移文件与执行器完全一致最大程度降低环境差异带来的 Schema 漂移风险。【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。