B站千亿级用户行为数据分析架构演进与ClickHouse实践

发布时间:2026/7/18 4:47:58
B站千亿级用户行为数据分析架构演进与ClickHouse实践 1. 项目背景与核心挑战B站作为国内领先的年轻人文化社区日活跃用户数已突破9000万每天产生的用户行为数据量高达数千亿条。面对如此庞大的数据规模传统的SparkHive技术栈在实时分析和复杂查询场景下逐渐暴露出性能瓶颈。我们团队在2020年启动技术架构升级时面临三个核心挑战查询延迟问题基于Spark的离线分析任务单次事件分析需要3分钟以上漏斗分析甚至需要30分钟才能返回结果严重影响了产品运营决策效率。资源消耗困境千亿级明细数据存储导致HDFS集群存储压力巨大实时计算任务需要维持1200core的常驻资源运维成本居高不下。业务扩展瓶颈原有架构难以支持跨天留存分析、用户路径分析等复杂场景且无法与标签系统、AB测试平台实现数据打通。2. 技术选型与架构演进2.1 ClickHouse的核心优势经过对主流OLAP引擎的对比测试我们最终选择ClickHouse作为核心分析引擎主要基于以下考量列式存储优势数据压缩比可达10:1相比行式存储节省70%存储空间按列读取的特性特别适合行为分析中的聚合查询场景向量化执行引擎利用SIMD指令集实现并行计算单机每秒可处理数亿行数据特色数据结构RoaringBitmap实现高效用户分群计算原生支持漏斗分析函数windowFunnel数组函数满足路径分析需求2.2 架构的三阶段演进阶段一Lambda架构2020年Kafka → Flink → ClickHouse明细表 ↓ HDFS备份痛点实时/离线两套逻辑维护成本高千亿级明细数据存储压力大Redis维表关联成为性能瓶颈阶段二Kappa架构2021年Kafka → Flink → ↘ Iceberg聚合模型→ BulkLoad → ClickHouse ↳ 直接写入ClickHouse降级通道优化点统一实时/离线处理逻辑聚合模型使数据量减少90%引入BulkLoad降低写入压力阶段三混合架构2022年至今实时链路Kafka → Flink → ClickHouse 离线链路Hudi → Spark → Iceberg ↔ ClickHouse关键改进Hudi替代Hive实现增量更新智能路由实时查询走ClickHouse复杂分析走Iceberg资源隔离读写分离部署方案3. 核心模块实现细节3.1 高效数据导入方案BulkLoad技术实现# 数据准备阶段 spark.read.parquet(input_path) \ .repartition(200) \ .foreachPartition(write_to_ck_part) # 单个Executor处理流程 def write_to_ck_part(iter): # 调用clickhouse-local生成part文件 subprocess.run(fclickhouse-local --query fSELECT * FROM table FORMAT Native {part_file}) # 上传HDFS hdfs_client.upload(part_file, hdfs_path) # 触发FETCH PARTITION execute_sql(fALTER TABLE {table} FETCH PARTITION {part} FROM {hdfs_path})性能对比导入方式吞吐量(rows/s)CPU消耗写入放大系数JDBC直写50万高5-8xHDFS BulkLoad200万中1.2-1.5x直连BulkLoad500万低1.1x3.2 用户行为分析优化漏斗分析实现-- 原始实现全量扫描 SELECT windowFunnel(3600)(timestamp, event_type page_view, event_type add_cart, event_type payment) AS level FROM detail_table GROUP BY user_id -- 优化版本下推计算 SELECT sum(level) FROM cluster( default, view( SELECT countIf(level 3) AS level FROM local_table GROUP BY shard_key ) )性能提升查询耗时从25s降至1.8s网络传输量减少98%留存分析优化-- 使用Retention函数矩阵计算 WITH toDate(timestamp) AS day, retention( day today() - 1, day today(), day today() 1 ) AS ret FROM events GROUP BY user_id优化效果7日留存计算从分钟级降至秒级支持任意时间窗口组合分析3.3 数据重平衡策略平衡度算法实现def calculate_balance(table): node_sizes get_node_data_sizes(table) avg sum(node_sizes) / len(node_sizes) variance sum((x-avg)**2 for x in node_sizes) / len(node_sizes) std_dev math.sqrt(variance) return std_dev / avg # 变异系数作为平衡度指标重平衡效果表名平衡前平衡后迁移数据量uba_events0.620.1845TBuser_tags0.410.0912TB4. 关键问题与解决方案4.1 热点问题处理现象某些大V视频播放行为导致数据倾斜解决方案动态分片策略对热点content_id采用单独分片本地缓存在CH节点使用Redis缓存热点数据查询限流对高频访问接口实施令牌桶限流4.2 复杂属性查询挑战用户行为中的动态属性如视频标签难以高效过滤创新方案-- 创建Map类型的跳数索引 ALTER TABLE events ADD INDEX tag_map_index mapKeys(tags_map) TYPE bloom_filter GRANULARITY 3 -- 优化后的查询 SELECT count() FROM events WHERE has(tags_map, 科技) AND tags_map[科技] AI效果查询延迟降低5-8倍存储开销仅增加2%5. 实践心得与避坑指南5.1 配置调优经验关键参数merge_tree max_suspicious_broken_parts5/max_suspicious_broken_parts parts_to_delay_insert500/parts_to_delay_insert parts_to_throw_insert1000/parts_to_throw_insert /merge_tree storage_configuration disks hot path/data1/ch//path keep_free_space_bytes100GB/keep_free_space_bytes /hot /disks /storage_configuration5.2 常见问题排查问题现象Too many parts错误处理步骤检查后台merge是否正常SELECT * FROM system.merges临时调整并发度SET max_replicated_merges_in_queue 30紧急情况可强制合并OPTIMIZE TABLE events FINAL6. 未来优化方向ZOrder索引实践针对多维查询场景测试ZOrder索引对复合条件查询的加速效果智能预聚合基于查询模式分析自动生成物化视图冷热分离将历史数据自动迁移到对象存储降低存储成本在实际生产环境中我们通过这套架构实现了日均千亿级数据的实时分析能力查询性能平均提升20倍存储成本降低60%。特别在春节等流量高峰期间系统始终保持稳定运行支撑了多个重要运营活动的数据分析需求。