1. 项目背景与核心挑战在当今互联网产品运营中用户行为数据分析已成为驱动业务决策的关键引擎。作为国内领先的年轻人文化社区B站面临着海量用户行为数据处理的严峻挑战每天产生数千亿条行为事件数据增量超过10TB传统的大数据处理架构已无法满足实时分析和复杂查询的需求。1.1 传统架构的瓶颈早期B站采用Spark批处理方案进行用户行为分析这种架构存在三个致命缺陷响应延迟高简单事件分析需要3分钟以上复杂分析如漏斗计算耗时超过30分钟资源利用率低固定资源配置无法适应查询复杂度变化常出现资源浪费或不足并发能力弱YARN资源调度机制导致高并发查询时产生严重排队现象1.2 ClickHouse的破局优势2020年技术团队引入ClickHouse列式数据库后性能指标获得质的飞跃查询响应提升98%90%事件分析在5秒内返回漏斗分析30秒内完成实时分析能力支持当天行为数据的即时查询周活跃用户增长300%性能改善直接带来产品使用率的显著提升但第一代ClickHouse方案也暴露出新问题千亿级明细数据存储消耗过大集群存储利用率长期低于10%实时数据处理链路复杂且维护成本高昂。2. 架构演进与核心技术方案2.1 三代技术架构演进路径2.1.1 第一代Spark批处理架构2019-2020graph LR A[用户行为日志] -- B[Spark批处理] B -- C[预聚合模型] C -- D[前端展示]痛点模型固化、资源僵化、响应迟缓2.1.2 第二代ClickHouse明细方案2020-2021graph LR A[Kafka日志流] -- B[Flink实时处理] B -- C[ClickHouse明细存储] C -- D[直接查询分析]突破实时性提升但存储压力巨大2.1.3 第三代IcebergClickHouse混合架构2021-至今graph LR A[原始日志] -- B[Iceberg聚合模型] B -- C[ClickHouse加速层] C -- D[多维分析]创新存储压缩90%查询性能再提升60%2.2 核心技术创新点2.2.1 通用流量聚合模型采用公有参数私有参数的混合存储方案私有参数使用ArrayMap结构动态存储数据压缩率高达10:1千亿→百亿2.2.2 BulkLoad数据导入Spark生成ClickHouse格式的data part文件通过改造的FETCH语法从HDFS拉取数据最终演进为直连ClickHouse的DataReceive服务# 数据导入伪代码示例 def bulk_load(): spark_job generate_clickhouse_parts() upload_to_hdfs(spark_job.output) execute_sql(ALTER TABLE...FETCH PARTITION...)2.2.3 智能重平衡算法平衡度计算基于变异系数0-1范围两种平衡策略装箱算法追求极致均衡Best FitAVL树贪心算法最小迁移成本实现较优均衡3. 关键模块实现细节3.1 事件分析优化方案3.1.1 数据模型设计CREATE TABLE polaris_dwb_flow_ubt ( dt Date, buvid UInt64, event_id String, pub_params Map(String,String), priv_params Array(String), metrics Map(String,Float64) ) ENGINE ReplicatedReplacingMergeTree() PARTITION BY dt ORDER BY (buvid, event_id) SAMPLE BY murmurHash3_64(buvid)3.1.2 查询加速技巧利用SAMPLE BY实现高效抽样自定义UDF解析Map结构比原生函数快30%布隆过滤器加速Array/Map字段查询3.2 漏斗路径分析实现3.2.1 漏斗分析优化-- 优化后的下推查询示例 SELECT level, countMerge(uv) AS uv FROM cluster(default, SELECT windowFunnel(3600)(dt, event_idlogin, event_idpay ) AS level, countState() AS uv FROM local_table WHERE dt BETWEEN 2023-01-01 AND 2023-01-07 GROUP BY level ) GROUP BY level3.2.2 路径分析创新采用RoaringBitmap压缩用户集合桑基图生成算法优化干扰事件过滤路径补位拼接权重阈值裁剪3.3 人群圈选系统3.3.1 属性字典服务三级缓存架构内存缓存Guava CacheRedis集群自研RockDB存储雪花算法变种实现50万QPS编码能力3.3.2 标签计算示例-- 最近7天观看科技区且点赞的用户 WITH tech_viewers AS ( SELECT user_id FROM behavior_events WHERE eventview AND zonetech AND dt today() - 7 ), like_users AS ( SELECT user_id FROM behavior_events WHERE eventlike AND dt today() - 7 ) SELECT countDistinct(user_id) FROM tech_viewers WHERE hasAny(like_users, [user_id])4. 性能优化实战经验4.1 查询下推的三种境界基础下推使用distributed_group_by_no_mergeSELECT count() FROM distributed_table SETTINGS distributed_group_by_no_merge1高级下推clusterview组合SELECT sum(cnt) FROM cluster( default, view(SELECT count() AS cnt FROM local_table) )极致下推预计算最终聚合4.2 压缩算法选型对比算法类型压缩率写入性能查询性能适用场景LZ41x100%100%默认场景LZ4HC1.2x80%95%历史数据ZSTD(1)1.5x60%98%冷数据存储实践建议热数据用LZ4温数据用LZ4HC冷数据用ZSTD4.3 常见问题排查指南4.3.1 写入瓶颈问题症状Too many parts错误根因频繁小批量写入导致merge压力大解决方案增大批量写入规模使用BulkLoad替代JDBC调整merge策略4.3.2 查询超时问题症状Query timeout exceeded根因复杂查询未利用索引解决方案检查跳数索引使用情况添加SAMPLE BY子句考虑预聚合方案5. 实践心得与未来展望在实际落地过程中有三点关键经验值得分享存储计算权衡我们发现将千亿明细预聚合为百亿级模型后存储节省40%的同时查询性能反而提升60%这印证了在OLAP场景中适当的预计算是必要的这一原则。资源隔离策略通过为不同业务模块配置独立的资源队列我们成功将高峰期的查询失败率从15%降至0.5%特别是在大促期间效果显著。监控体系建设自研的ClickHouse监控系统包含200个指标实现了从硬件资源到查询性能的全方位监控平均故障定位时间从小时级缩短到分钟级。未来技术团队计划在三个方向继续突破ZOrder索引研发解决多维度查询的索引效率问题服务端日志分析扩展行为分析场景覆盖面实时数仓融合探索Hudi与ClickHouse的协同方案