ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PostHog 中的 ClickHouse Materialized Columns 实战指南:从自动物化到手工运维

PostHog 中的 ClickHouse Materialized Columns 实战指南:从自动物化到手工运维 PostHog 中的 ClickHouse Materialized Columns 实战指南从自动物化到手工运维【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog导读本文以 PostHog 仓库中的 materialized-columns.md 手册为核心系统讲解 ClickHouse 物化列Materialized Columns的核心原理、自动物化机制、基于 Dagster 的手动物化流程与配置参数并结合仓库源码剖析其底层实现。读完本文你将掌握物化列为什么能让 JSON 属性查询提速手册给出的典型数据为最高 25x、PostHog 如何自动分析慢查询并物化属性列、如何在生产环境通过 Dagster 手工创建物化列并安全回填历史数据以及如何用环境变量控制整个物化流程。背景为什么需要物化列PostHog 的核心事件数据以 JSON 形式存储在 ClickHouse 的字符串列中。事件属性、用户属性、群组属性等都被塞进properties、person_properties、group_properties这类胖JSON 列中查询时依赖JSONExtract*系列函数在读取阶段实时解析 JSON。由于这些列体积巨大解析成本高导致查询缓慢。物化列Materialized Columns的思路是把 JSON 中高频使用的特定属性在写入/变更时提前抽取出来落盘为独立的物理列。这样查询时直接读取扁平列无需再对整块 JSON 做解析读取速度可提升一个数量级——手册明确给出reading these columns up to 25x faster than normal properties的实测结论。从源码可以印证这一设计columns.py 中的MaterializedColumn.get_expression_and_parameters()展示了物化列默认表达式的两种形态非 nullable 场景JSONExtractRaw(properties, %(property)s)抽取 JSON 中属性的原始值nullable / 显式指定类型场景JSONExtract(properties, %(property_name)s, %(property_type)s)按目标类型如Nullable(String)强类型抽取。这两个表达式最终被拼进ADD COLUMN ... DEFAULT expression即列默认值即 JSON 抽取表达式——这正是物化的本质列数据由表达式生成并持久化到磁盘。手册中附带的 ClickHouse JSON 使用手册 与相关博客是进一步阅读的入口本文聚焦物化列的机制与运维。物化列在实践中的两大路径物化列在 PostHog 中承担着为大数据量客户优化查询性能的重任。它存在两条使用路径自动物化一个定时任务自动分析上周的慢查询从中识别出高频属性并自动物化手动物化通过 Dagster 作业按需创建物化列生产环境即以此为主。无论哪条路径都有一个前提——物化列必须回填backfill历史数据才能生效。回填意味着对集群上大量历史分区执行数据重写会显著增加集群负载因此手册强调这类操作最好安排在周末执行。自动物化慢查询驱动的 cron 任务自动物化的代码位于 ee/clickhouse/materialized_columns/analyze.py。核心入口是materialize_properties_task()它大致分三步分析慢查询调用_analyze(since_hours_ago, min_query_time, team_id)从 ClickHousesystem.query_log中检索最近一周默认的查询用正则抽取 SQL 中的JSONExtract*调用定位哪个表、哪一列、哪个属性被频繁读取去重过滤通过get_materialized_columns(table)拿到已物化的列跳过已经存在的属性避免重复物化物化与回填对筛选出的候选属性默认最多 100 个调用materialize()建列随后调用backfill_materialized_columns()回填指定天数的历史数据。_analyze的过滤条件非常讲究体现了生产环境的工程取舍见 analyze.py只统计失败/超时的查询异常码159TIMEOUT EXCEEDED与160TOO SLOW或query_duration_ms超过阈值只统计重活read_bytes 20GB且read_rows 5,000,000保证物化只针对真正昂贵的大扫描排除person_distinct_id2旧式关联查询、排除personal_api_key与 celery 内部查询只关注properties、person_properties、group0~4_properties这几类 JSON 属性列每个候选需满足超时失败至少 1 次或慢查询至少 10 次才进入物化候选并用LIMIT 100限制单轮物化列数防止一次性加几百列把集群压垮。自动物化的调度与环境变量自动物化由 celery 定时任务驱动posthog/tasks/tasks.py 中在条件满足时调用materialize_properties_task()。相关调度与阈值全部可通过环境变量调整定义见 ee/settings.py环境变量默认值说明MATERIALIZE_COLUMNS_SCHEDULE_CRON0 5 * * SAT调度 cron 表达式默认每周六凌晨 5 点运行MATERIALIZE_COLUMNS_MINIMUM_QUERY_TIME40000毫秒慢查询判定阈值超过 40 秒即视为慢MATERIALIZE_COLUMNS_ANALYSIS_PERIOD_HOURS1687 天分析窗口统计多久之前的查询MATERIALIZE_COLUMNS_BACKFILL_PERIOD_DAYS0自动物化的默认回填天数0 表示不回填MATERIALIZE_COLUMNS_MAX_AT_ONCE100单轮最多物化列数另有两个与物化系统运行相关的开关位于 posthog/settings/dynamic_settings.pyMATERIALIZED_COLUMNS_ENABLED默认True物化列整体功能开关COMPUTE_MATERIALIZED_COLUMNS_ENABLED默认True是否计算使用物化列。手册特别提醒由于集群问题或正在进行数据迁移这个 cron 经常会被临时禁用——运维时应注意检查上述开关与调度状态避免在迁移期间触发大规模物化。手动物化Dagster 作业实战在生产环境中PostHog 使用Dagster手工执行物化。作业名为create_materialized_column位于team-clickhouselocation 中EU 与 US 两个 region 各有实例。作业定义见 posthog/dags/create_materialized_column.py其配置类MaterializeColumnConfig直接对应手册中的 YAML 配置。进入 Dagster playground对应 region后配置create_materialized_columns_op即可手册给出的完整示例ops: create_materialized_columns_op: config: backfill_period_days: 90 dry_run: false properties: - $browser_language_prefix - $app_namespace table: events table_column: properties配置项详解对照 create_materialized_column.py 中的配置类各字段含义与约束如下table要物化的 ClickHouse 表可选值为events或person默认eventstable_column包含属性的 JSON 列可选值为properties、group_properties、person_properties默认properties对应源码中DEFAULT_TABLE_COLUMN propertiesproperties需要物化为列的属性名列表必填如$browser_language_prefix、$app_namespacebackfill_period_days回填多少天的历史数据默认90dry_run置为true时只预览将物化哪些列、不做任何变更默认falseis_nullable新建物化列是否为 nullable默认true源码中is_nullable: bool True自动物化任务默认False。其中dry_run对应 analyze.py 中的if not dry_run:分支dry-run 模式下只记录日志、跳过materialize()与回填。Dagster op 也会显式输出Dry run: No changes to the tables will be made!警告日志适合在正式操作前先预览。执行流程从 op 到底层 DDL当 YAML 配置提交后create_materialized_columns_op会把(table, table_column, property)三元组打包传给materialize_properties_task()随后走通如下链路materialize()columns.py校验属性是否已物化重复会抛ValueError校验table_column是否合法生成唯一列名person表前缀pmat_events表前缀mat_若table_column非默认还会插入短码p/pp/gp/gp0~gp4见SHORT_TABLE_COLUMN_NAME属性名中的非法字符替换为_冲突时追加随机短后缀在数据节点上执行ALTER TABLE ... ADD COLUMN IF NOT EXISTS col type DEFAULT JSONExtract 表达式并附带 COMMENT格式为column_materializer::table_column::property[::disabled]这是系统识别物化列的依据若为分片表events还会在所有查询节点上为分布式表补建同名空列默认同时创建minmax跳数索引create_minmax_indexnot TEST并可选创建bloom_filter、ngram_bf_v1(lower(col))、bloom_filter(lower(col))等索引后两者因 ClickHouse 索引大小写敏感、不支持 nullable需用lower(coalesce(col,))包装详见NgramLowerIndex/BloomFilterLowerIndex。backfill_materialized_columns()columns.py对数据表执行ALTER TABLE ... UPDATE col col WHERE timestamp cutoff的轻量变更mutation由 ClickHouse 在后台异步重写分区数据回填窗口由backfill_period_days换算为截止日期传入对events表按天数截断person表则全表回填源码中if table events的注释标记了这一点该方法注释明确写道 This will require reading and writing a lot of data on clickhouse disk再次印证回填对磁盘 IO 的巨大压力。缓存失效变更完成后调用_clear_materialized_columns_cache()清除物化列元数据缓存确保后续查询立即感知新列。物化列的查询侧机制查询时PostHog 的查询引擎会先通过get_materialized_columns(table)/get_enabled_materialized_columns()columns.py15 分钟缓存 后台刷新读取物化列清单将JSONExtract表达式改写为直接读列。物化列的元数据来自system.columns靠 COMMENT 中的column_materializer::标记识别见MaterializedColumn._get_all的 SQL。is_disabled机制允许在不删列的情况下临时停用某列通过update_column_is_disabled()改写 COMMENT 追加disabled标记而drop_column()则负责彻底删除列及其关联索引先删索引再删列分布式表与数据表分别处理。运维建议与注意事项综合手册与源码生产环境操作物化列时需注意回填是重操作务必避开高峰backfill_period_days: 90意味着对 90 天的历史数据执行 mutation 重写集群 IO 压力巨大手册建议安排在周末先 dry_run 再执行任何手动物化前先将dry_run: true跑一遍确认要创建的列与回填窗口符合预期用MATERIALIZE_COLUMNS_*环境变量控制自动物化大数据量集群若担心自动物化失控可调低MATERIALIZE_COLUMNS_MAX_AT_ONCE、关闭MATERIALIZED_COLUMNS_ENABLED或在数据迁移期间直接禁用该 cron列名与索引自动管理列命名、minmax 索引创建、缓存清理均由materialize()一站式完成运维无需手工拼 DDL如需停用列而非删除优先使用update_column_is_disabled()保留数据以降低重建成本测试覆盖完整仓库在 ee/clickhouse/materialized_columns/test/ 下提供了test_columns.py、test_analyze.py、test_query.py等测试覆盖列创建、分析逻辑与查询改写可作为理解各函数行为的参考。结语物化列是 PostHog 在JSON 属性查询慢这一典型 ClickHouse 痛点上的工程解法以磁盘空间和回填 IO 为代价换取查询时免解析的极速读取。理解自动物化的慢查询分析逻辑、Dagster 手动物化的配置语义以及底层ADD COLUMN ... DEFAULT JSONExtract(...) mutation 回填的实现链路就能在大数据量场景下安全、高效地运用这套工具让慢查询分析物化流程真正服务于性能优化。【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表