1. 项目概述:当广告技术遇上Doris
在数字广告行业,实时竞价(RTB)系统每秒钟要处理数百万次竞价请求,传统的关系型数据库在这种高并发写入场景下往往捉襟见肘。我们团队最近基于Apache Doris构建的实时竞价分析系统,成功将数据处理延迟从小时级降低到秒级,同时支撑了日均千亿级数据点的实时分析。
这个系统的核心价值在于:当广告主在后台刷新数据看板时,他们看到的不再是几分钟前的"历史数据",而是真实反映当前市场竞争态势的实时信息。比如某电商客户发现某个关键词的CPM突然上涨30%时,可以立即调整出价策略,而不是等到第二天报表出来才发现预算已经超支。
2. 为什么选择Doris?
2.1 技术选型对比
我们曾评估过几种主流方案:
- Elasticsearch:查询性能优秀但写入吞吐有限,且复杂分析能力不足
- ClickHouse:单表查询快但多表join性能差,不适合广告业务的多维度分析
- Druid:实时摄入尚可但SQL支持较弱,运维成本高
Doris的独特优势体现在:
- 毫秒级响应:通过预聚合和物化视图,关键指标查询控制在100ms内
- 高并发写入:单个BE节点可支持10w+ QPS的写入吞吐
- 标准SQL支持:业务人员可以直接用熟悉的方式查询
- 成本效益:相同硬件配置下,存储成本比ES低40%左右
2.2 广告业务场景适配
广告技术场景有几个典型特征:
- 数据时效性敏感:竞价策略调整需要分钟级反馈
- 查询模式复杂:需要同时满足OLAP和点查询需求
- 数据规模庞大:单个DSP日增数据量可达TB级
Doris的MPP架构完美匹配这些需求。我们实测在16核64G的BE节点上,单条INSERT语句可完成50万行数据的批量写入,配合Flink实时管道,数据从产生到可查询的平均延迟仅8秒。
3. 系统架构设计
3.1 整体数据流
[广告交易平台] --(实时日志)--> [Flink] --(清洗后数据)--> [Doris] | v [Redis实时缓存]这个架构的关键设计点:
- Flink做流式ETL:处理原始日志的脏数据问题
- Doris分桶策略:按
advertiser_id哈希分桶,保证相同广告主的数据物理集中 - 双写机制:关键维度数据同时写入Redis供实时查询
3.2 核心表结构
CREATE TABLE rtb_events ( event_time DATETIME NOT NULL, bid_id VARCHAR(64) NOT NULL, advertiser_id INT NOT NULL, campaign_id INT NOT NULL, creative_id INT NOT NULL, device_type TINYINT, country_code SMALLINT, bid_price DECIMAL(12,4), win_price DECIMAL(12,4), is_win BOOLEAN ) PARTITION BY RANGE(event_time) ( PARTITION p202301 VALUES LESS THAN ('2023-02-01'), PARTITION p202302 VALUES LESS THAN ('2023-03-01') ) DISTRIBUTED BY HASH(advertiser_id) BUCKETS 32 PROPERTIES ( "replication_num" = "3", "storage_medium" = "SSD" );这个schema设计有几个优化点:
- 按天分区+哈希分桶实现两级数据分片
- 将高频过滤条件字段设为前缀列
- 使用DECIMAL精确存储金额避免浮点误差
4. 性能优化实战
4.1 写入优化配置
在fe.conf中关键参数:
flush_interval_sec=5 tablet_write_interval_ms=500 streaming_load_rpc_max_alive_time_sec=1200在be.conf中调整:
write_buffer_size=1073741824 # 1GB tablet_writer_open_interval_ms=500重要提示:flush_interval_sec不宜设置过小,否则会导致频繁刷盘影响吞吐。我们通过测试发现5-10秒是吞吐和延迟的最佳平衡点。
4.2 查询加速技巧
- 物化视图预计算:
CREATE MATERIALIZED VIEW mv_rtb_hourly_stats DISTRIBUTED BY HASH(advertiser_id) REFRESH ASYNC AS SELECT advertiser_id, campaign_id, DATE_TRUNC('HOUR', event_time) AS hour, COUNT(*) AS bid_count, SUM(is_win) AS win_count, SUM(bid_price) AS total_bid, SUM(win_price) AS total_spend FROM rtb_events GROUP BY 1,2,3;- 冷热数据分离:
ALTER TABLE rtb_events SET ( "storage_cooldown_time" = "7 days" );5. 踩坑实录
5.1 内存配置陷阱
初期我们遇到BE节点频繁OOM的问题,后发现是默认配置不合理。调整方案:
- BE节点:预留30%内存给操作系统
- JVM配置:堆内存不超过物理内存的70%
- 查询内存限制:
exec_mem_limit=8G
5.2 数据倾斜处理
某广告主数据量特别大导致查询变慢,解决方案:
- 动态分桶:对大广告主单独分桶
- 本地join优化:
set enable_local_shuffle=true - 倾斜检测:定期执行
SHOW DATA SKEW
6. 监控与运维
6.1 关键监控指标
通过Prometheus采集:
doris_be_scanner_thread_num:扫描线程繁忙度doris_fe_query_latency_ms:查询延迟百分位doris_be_mem_usage:内存水位线
6.2 扩容操作步骤
- 增加BE节点:
./bin/start_be.sh --daemon- 数据均衡:
ADMIN SET REPLICA DISTRIBUTION BALANCE;- 验证状态:
SHOW BACKENDS\G7. 业务价值体现
这套系统上线后带来的直接收益:
- 异常检测时效性:从2小时提升到3分钟
- 日报生成耗时:从45分钟缩短到90秒
- 服务器成本:相比原ES方案降低60%
- 最大支持QPS:从5k提升到50k+
某快消客户的实际案例:通过实时监测到凌晨时段的异常流量激增,及时调整投放策略,单月节省无效点击支出$120万。