1. 为什么要在腾讯云上做实时数仓
1.1 项目背景与核心需求
前阵子接到一个项目,要在腾讯云上搭一套大数据实时数仓,起初以为把离线数仓的经验平移过来就行,结果落地过程中踩了不少坑。业务侧原来的数仓是 Hive + Spark 跑 T+1,报表和看板都是前一天的数据。后来产品经理提了一堆实时需求:大屏指标要秒级刷新、运营活动要实时监控投放效果、风控要实时识别异常行为。离线模式根本顶不住,所以必须引入一条“数据从产生到可分析只有几十秒”的链路,这就是实时数仓要解决的核心问题。
项目目标拆下来其实就两条。第一,核心业务指标从分钟级延迟降到 10 秒以内,至少要做到“准实时”。第二,查询不能只支持预设好的汇总指标,业务方还需要临时下钻、按任意维度组合分析,这就意味着底层存储不能只是一堆预先算好的 Redis Key,必须有一个能扛住灵活查询的 OLAP 引擎。
为什么选腾讯云而不是自建机房,当时权衡下来有三个原因:一是团队没有专职大数据运维,托管服务能省掉组件部署、版本升级、故障恢复这些体力活;二是腾讯云的 CKafka、流计算 Oceanus、StarRocks 这些产品之间在同一个 VPC 里天然打通,链路配置非常顺畅;三是后续要做离线回填和交叉校验,直接对接 COS 和 EMR 就能搞定,不用额外写一堆数据同步脚本。
当然,托管不等于不用懂原理。恰恰相反,越是被托管服务包住,越要清楚底层运行逻辑。比如 Flink 的 Checkpoint、状态后端、反压这些概念,如果不理解,出了问题在控制台上看半天也定位不到原因。后面我会结合实操一个一个说。
1.2 技术选型:Kappa 还是 Lambda
实时数仓绕不开两种典型的架构流派:Lambda 和 Kappa。Lambda 是“离线 + 实时”两条链路并行,最终做结果合并;Kappa 是只保留实时一条链路,数据需要重算时通过 Kafka 这类消息队列重放。我们最终没有选纯 Kappa,也没有完全照搬 Lambda,而是用了“以 Kappa 为主、Lambda 为辅”的混合方式。
为什么不全部上 Lambda?原因很简单:维护两套逻辑的成本太高。同一个指标,离线一个口径,实时一个口径,两边数据对不上时排查问题极其痛苦。业务方不会关心你是离线算的还是实时算的,他们只看到数字不对。而且 Lambda 链路里实时和离线需要分别做数据质量监控,资源和人力都是双份。
为什么又不完全 Kappa?因为 Kafka 的存储成本摆在那里,不可能把所有历史数据永久保留。有些指标要回溯 30 天甚至更久,比如活动效果复盘、月度趋势分析,这时候让实时链路重新消费 Kafka 的回放成本太高。所以我们保留了原有的 Hive 离线链路,专门做长周期回溯和结果校验。这样实时链路负责秒级、分钟级的高频指标,离线链路负责日级、月级的历史分析,两条链路通过每天的对账任务互相校验口径。
具体到腾讯云上的组件选型,当时定的是:
- 消息队列:CKafka,负责承接业务 binlog 和埋点日志;
- 实时计算:流计算 Oceanus,支持 Flink SQL,省去自己维护 Flink 集群;
- OLAP 存储:StarRocks,承担实时明细和汇总指标查询;
- 离线旁路:COS + EMR,用于数据回填、长期存储、对账。
这套组合用起来比较顺的关键原因,是各组件之间基本都提供了官方 Connector,Flink SQL 写起来很顺手。但要注意的是,托管服务的版本会跟随云厂商更新,尽量不要在 SQL 里用太新的语法特性,否则每次平台升级都可能出现兼容性问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 架构设计与核心组件解析
2.1 整体链路拓扑
实时链路整体长这样:业务数据库通过 Canal/Debezium 同步 binlog 到 CKafka,客户端埋点日志通过日志服务直接推送到 CKafka;流计算 Oceanus 上的 Flink SQL 作业消费 CKafka,做数据清洗、维表关联、窗口聚合;结果写入 StarRocks;最后提供给 BI 看板或 API 查询。
这里每个环节都有明确的职责划分。CKafka 是缓冲层,负责削峰填谷,避免业务洪峰直接打到实时计算层。Flink 是计算层,承担最核心的清洗、关联、聚合逻辑。StarRocks 是存储和查询层,既要能支撑高并发点查,也要能跑复杂的多维聚合。还有一个很容易被忽视的环节是维表关联,我们用的是 Redis + HBase 搭配:Redis 放高频小维表,比如用户等级、渠道类型、城市信息;HBase 放大体积的状态维表,比如商品完整画像、历史标签。为什么不把维表全部塞进 Flink 内存?因为大数据量维表会导致状态膨胀,checkpoint 压力大,很容易 OOM,而且维表更新时内存数据没法及时感知。
实际跑起来之后,第一个让我印象深刻的坑是消费倾斜。最开始创建 CKafka topic 时分区数拍脑袋设了个默认值,Flink 并行度也直接用默认值,结果高峰时期有个别分区 lag 一直涨,其他分区很空闲。原因是一个热门店铺的订单量远大于普通店铺,Hash 规则落到固定分区,导致单分区积压。后来我们重新评估了上游数据量分布,把分区数和并行度调整到合理范围,消费倾斜才缓解。所以“分区数 + 并行度”这对参数,真的不能随便填。
