B站用户行为分析架构演进与ClickHouse优化实践
1. B站用户行为分析的技术挑战与架构演进B站作为国内领先的视频社区平台每天产生的用户行为数据量达到数千亿行级别。这些数据包括视频观看、弹幕发送、点赞收藏、分享评论等丰富的行为类型构成了一个极具价值的用户行为分析宝库。面对如此庞大的数据规模传统的数据分析架构面临着三大核心挑战首先是存储压力。半年以上的历史行为数据需要存储PB级别的压缩数据这对存储系统的扩展性和成本控制提出了极高要求。其次是查询性能。用户行为分析需要支持多维度实时查询包括事件分析、漏斗分析、路径分析等复杂场景传统方案往往需要分钟级响应。最后是资源效率。如何在保证分析能力的同时降低计算资源消耗成为技术团队必须解决的难题。B站的北极星用户行为分析平台经历了三个主要的技术架构演进阶段2019-2020年采用的是部分模型化聚合Spark Jar任务架构。这个阶段通过预定义的Spark作业处理特定分析场景虽然功能上能够实现基本分析需求但存在明显的性能瓶颈。单事件分析需要超过3分钟返回结果漏斗和路径分析甚至需要30分钟以上严重影响了产品可用性。2020-2021年升级为无模型化明细FlinkClickHouse架构。这一代架构引入了ClickHouse列式数据库直接对用户行为明细数据进行实时分析。性能得到显著提升90%的事件分析查询可以在5秒内返回漏斗分析也缩短到30秒内。然而这种架构对资源消耗极大Flink任务峰值需要1200个计算核心存储几经扩容后仍面临不足10%剩余空间的窘境。2021年至今发展为Iceberg全模型化聚合ClickHouse的混合架构。这一架构创新性地结合了数据湖技术与OLAP引擎的优势通过全模型化聚合将每天千亿级数据压缩到百亿级别同时实现了秒级查询响应。实时资源节约了1400个计算核心存储资源节省40%查询效率提升60%以上。2. ClickHouse在用户行为分析中的核心优势ClickHouse之所以成为B站用户行为分析的核心引擎主要基于其在海量数据分析场景下的四大独特优势列式存储结构天然适合分析场景。用户行为分析通常只需要查询少数几个字段而不需要整行数据。ClickHouse的列式存储避免了读取无关字段带来的IO浪费配合高效的压缩算法如ZSTD可以将存储空间减少30%以上。在实际测试中B站采用ZSTD(1)压缩算法后存储空间节省显著而查询性能基本不受影响。向量化执行引擎大幅提升计算效率。ClickHouse的查询执行不是传统的逐行处理而是采用SIMD指令对数据块进行批量操作。这种设计特别适合用户行为分析中的聚合计算如UV统计、留存率计算等场景。在B站的实践中向量化引擎使得单节点每秒可以处理数亿行数据的聚合运算。原生支持RoaringBitmap数据结构。用户行为分析中常见的交并差集计算如计算同时完成多个行为的用户群通过RoaringBitmap可以得到极致优化。B站利用这一特性实现了高效的标签人群圈选功能将原本需要分钟级计算的复杂人群筛选优化到秒级响应。分布式能力与线性扩展。ClickHouse的分布式表引擎可以透明地将数据和查询分布到集群各节点。B站通过合理的数据分片策略如按user_id哈希分片实现了计算资源的线性扩展。当数据量增长时只需增加节点即可保持查询性能稳定。3. 海量数据导入与重平衡实践3.1 数据导入方案的三次迭代B站在ClickHouse数据导入方案上经历了三个阶段的演进最初的JDBC写入方案直接通过Flink任务将数据写入ClickHouse。这种方式实现简单延迟可以控制在秒级但存在明显的资源竞争问题。数据排序、索引生成和压缩都在ClickHouse服务端完成高峰期会严重影响查询性能。同时高频的小批量写入导致大量merge操作产生写放大效应消耗额外30%以上的磁盘IO和CPU资源。第二阶段采用基于HDFS的BulkLoad方案。这一方案的核心创新是将data part文件的生成过程转移到Spark端完成利用YARN集群资源进行数据预处理。生成的文件上传到HDFS后ClickHouse通过改造过的FETCH语句拉取并attach。实测显示这种方案将写入对查询的影响降低了90%merge压力减少70%以上。但HDFS作为中间存储带来了额外的网络开销和存储成本。当前阶段实现了直达ClickHouse的BulkLoad方案。通过开发DataReceive服务Spark Executor可以直接将data part文件传输到ClickHouse节点完全绕开HDFS。这一优化使导入性能再提升100%同时系统稳定性得到进一步增强。DataReceive服务实现了完善的流量控制机制单节点可支持每秒GB级别的数据传输。3.2 数据重平衡的自动化实践随着数据量持续增长ClickHouse集群需要定期扩容。B站开发了一套自动化重平衡工具主要解决以下问题平衡度量化通过变异系数实现。该指标消除了数据绝对大小的影响能够客观反映表在各节点的分布均匀程度。计算公式为变异系数标准差/平均值。当该值超过0.3时系统会自动触发平衡操作。针对不同场景提供两种平衡算法装箱算法追求极致均衡采用Best Fit策略配合AVL树优化适合数据量相对较小的表贪心算法以最小迁移成本达到较优均衡通过轮询实现局部最优适合PB级大表平衡平衡执行流程设计了完善的原子性保证机制。采用预判断fetchdetachattachdrop detached的管道式操作配合异常重试和回滚确保即使在网络抖动等异常情况下也不会出现数据丢失或重复。同时通过max_replicated_fetches_network_bandwidth参数实现精细化的流量控制平衡过程对查询性能的影响控制在5%以内。4. 核心分析功能的实现与优化4.1 事件分析与留存计算事件分析是用户行为分析的基础功能B站通过多级聚合模型实现了高效查询第一层是DWD明细数据保留原始行为日志的所有细节。第二层DWB进行轻度聚合将相同user_id和event_id的行为按时间窗口聚合私有参数存入Array结构指标值通过Map类型聚合。第三层DWS实现高度聚合采用RoaringBitmap存储用户集合查询时通过位运算快速计算UV等指标。留存分析利用ClickHouse的Retention函数族实现。通过将用户行为序列转换为留存矩阵可以高效计算任意时间窗口的留存率。例如计算第N日留存的SQL模式为SELECT sum(r[1]) AS active_users, sum(r[2]) AS retained_users, retained_users / active_users AS retention_rate FROM ( SELECT retention(day1_active, dayN_active) AS r FROM ( SELECT user_id, toDate(time) today() - 1 AS day1_active, toDate(time) today() - 1 - N AS dayN_active FROM user_events WHERE event video_view ) GROUP BY user_id )这种实现方式相比传统JOIN方法性能提升10倍以上且不受时间窗口大小的限制。4.2 漏斗与路径分析优化漏斗分析通过windowFunnel函数实现该函数可以找出用户在规定时间窗口内完成的一系列行为序列。B站通过查询下推技术进一步优化性能-- 原始查询 SELECT level, count() FROM ( SELECT user_id, windowFunnel(3600)(time, eventstart, eventstep1, eventstep2) AS level FROM distributed_table GROUP BY user_id ) GROUP BY level -- 优化版本V1 SELECT level, sum(cnt) FROM cluster(default, view(SELECT level, count() AS cnt FROM local_table GROUP BY level) ) GROUP BY level -- 优化版本V2 SELECT level, sum(cnt) FROM cluster(default, view(SELECT windowFunnel(3600)(time, eventstart, eventstep1, eventstep2) AS level, count() AS cnt FROM local_table GROUP BY level) ) GROUP BY level通过将计算尽可能下推到各分片执行三个版本的性能提升分别为5倍和30倍。路径分析采用桑基图可视化用户行为流转。技术实现上分为三步将用户行为序列聚合为路径模式使用sequenceCount函数统计各路径出现次数通过RBM计算路径间的用户重叠度针对路径分析中的噪声问题如页面刷新导致的重复事件B站开发了基于马尔可夫链的清洗算法可以有效识别并过滤非关键路径节点。5. 标签人群圈选与系统集成5.1 RoaringBitmap在人群圈选中的应用B站构建了统一的标签画像平台底层基于ClickHouse的RoaringBitmap实现高效人群圈选。技术架构包含三个关键组件字典服务将业务属性编码为数字ID。采用改进的Snowflake算法生成64位ID配合多级缓存RedisRockDB实现50万QPS的高并发查询。服务设计考虑了故障恢复能力通过BulkLoad机制可在40分钟内恢复20亿的属性字典。位图索引构建器定期将用户标签转化为RoaringBitmap。根据标签热度采用不同的存储策略高频标签使用全局位图低频标签使用分段位图。这种混合存储方式节省了60%以上的内存空间。查询引擎支持复杂的布尔运算。通过ClickHouse的bitmapAnd、bitmapOr等函数可以实现多标签的组合查询。例如查找最近7天观看科技类视频且未充值会员的用户WITH tech_viewers AS ( SELECT bitmapFromArray(groupArray(user_id)) AS bm FROM user_events WHERE event video_view AND category tech AND time now() - interval 7 day ), non_vip AS ( SELECT ~bm AS bm FROM vip_users ) SELECT bitmapCardinality(bitmapAnd(tech_viewers.bm, non_vip.bm)) FROM tech_viewers, non_vip5.2 多系统集成实践北极星分析平台与B站的其他数据系统深度集成形成了完整的数据分析生态与AB测试平台集成可以直接将行为分析结果作为实验分组依据。通过共享RoaringBitmap格式的人群包实现了分钟级的实验人群创建。与推荐系统对接将用户行为特征实时反馈到推荐算法。利用ClickHouse的物化视图机制关键行为指标可以在5秒内更新到推荐特征库。与风控系统联动通过异常行为模式识别潜在风险账号。基于窗口函数的时序分析可以实时检测刷量、爬虫等异常行为。6. 关键性能优化经验6.1 查询下推的最佳实践查询下推是ClickHouse性能优化的核心手段B站总结了以下实践经验适合下推的场景数据已按查询维度合理分片如按user_id分片后计算UV中间结果集较大如countDistinct、windowFunnel等聚合需要减少网络传输量的宽表查询不适合下推的场景简单聚合如sum、count全局排序如top N查询跨分片精确去重下推实现方式使用distributed_group_by_no_merge设置禁止中间结果合并通过cluster() view()组合将聚合完全下推对分布式表使用GLOBAL关键字控制执行计划6.2 跳数索引优化技巧针对Array/Map类型的字段查询B站开发了专门的跳数索引优化方案BloomFilter索引适合低基数字段。对Map类型的key构建BloomFilter可以将包含特定key的part快速定位减少90%以上的无效数据读取。MinMax索引适合有序数据。对Array中的时间戳字段构建MinMax索引可以高效支持时间范围查询。Granularity自适应调整。根据字段分布特征动态设置索引粒度热点数据采用更细粒度如8192行稀疏数据采用更大粒度如65536行。6.3 资源隔离与限流机制为保证查询稳定性B站实施了多层次的资源管控查询队列分离。将实时查询与离线分析分配到不同的处理队列避免长查询阻塞关键业务。内存限额控制。通过max_memory_usage参数限制单查询内存使用配合max_memory_usage_for_all_queries控制集群总内存。并发请求限制。根据用户等级设置max_concurrent_queries保障高优先级用户的查询资源。7. 未来演进方向7.1 多模数据分析支持当前架构正在向支持多业务通用模型的方向演进行为数据模型泛化。将用户-内容-行为的三元组模型扩展为N元组支持更丰富的业务场景。例如社区互动场景引入回复对象作为第四维度。异构数据统一查询。通过定义标准映射规则将不同业务线的数据自动转换为统一模型保持查询接口的一致性。7.2 实时分析能力增强基于Hudi的增量处理。将底层存储迁移到Hudi支持分钟级的数据新鲜度同时保持批处理的吞吐能力。流式OLAP集成。探索将ClickHouse与流处理引擎如Flink深度集成实现亚秒级的实时分析。7.3 查询优化持续深入ZOrder索引开发。通过多维空间填充曲线优化多条件查询使得单个索引可以同时高效支持user_id、event_type、time等多维度过滤。JIT编译优化。针对高频查询模式开发定制化的代码生成器将解释执行的查询计划编译为本地代码预计可提升30%以上的计算性能。

相关新闻