画像数据怎么给到业务系统?接口设计和性能优化
先说结论
画像数据对外提供有三种模式:API接口、消息推送、文件同步。不同的下游系统适合不同的模式。推荐系统需要毫秒级API、营销系统需要人群包文件、实时风控需要消息推送。
API接口是最常见的模式,核心挑战是性能。千万级用户画像,高峰期QPS上千,P99延迟要控制在10ms以内。背后的存储必须用Redis或HBase,不能直接查Hive/MySQL。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
画像数据做好了存在Hive里,但推荐系统、运营后台、广告投放系统都需要实时获取用户画像。你不能让这些系统直接查Hive——延迟太高了。怎么把画像数据高效地给到业务系统?这道题考的是你的系统设计能力,从数据开发到数据平台的跨越。
三种对外提供模式
| 模式 | 适用场景 | 技术方案 | 延迟 | 数据时效 |
|---|---|---|---|---|
| API接口 | 推荐系统、实时风控 | Redis + Spring Boot API | 毫秒级 | 准实时 |
| 消息推送 | 实时营销触发、事件驱动 | Kafka消息通知 | 秒级 | 实时 |
| 文件同步 | 广告人群包、BI报表 | HDFS/OSS文件导出 | 分钟~小时 | T+1 |
API接口设计实战
我在某出海硬件品牌设计的画像API有两个核心接口:
画像API接口设计:
接口1:获取单用户全量画像
GET /api/v1/user/profile?user_id=10086
返回:该用户的所有标签(JSON格式)
用途:推荐系统获取用户画像
性能要求:P99 < 5ms, QPS > 2000
接口2:根据标签条件批量圈选用户
POST /api/v1/user/segment
Body: {conditions: [{tag: 'value_level', op: 'eq', val: 'high'},
{tag: 'country', op: 'eq', val: 'JP'}]}
返回:符合条件的用户ID列表
用途:运营圈选人群包
性能要求:P99 < 500ms, 结果集 < 10万
两个接口的后端存储不同:接口1用Redis(KV点查),接口2用ES(多条件圈选)。
Redis存储优化——从30GB到12GB
千万级用户画像全量存Redis,内存占用是最大的挑战。我在出海硬件品牌做了几个优化:
# 优化1:标签值编码压缩
# 原始存法:value_level = 'high_value_champion'(20字节)
# 优化后:value_level = '1'(1字节)+ 编码映射表
TAG_ENCODING = {
'value_level': {'high': '1', 'medium': '2', 'low': '3'},
'gender': {'M': '1', 'F': '2', 'unknown': '0'},
'rfm_segment': {'champion': '1', 'loyal': '2', 'at_risk': '3',
'lost': '4', 'new_user': '5', 'general': '6'},
}
# 优化2:Hash结构精简field名
# 原始:redis.hset('user:profile:10086', 'value_level', 'high')
# 优化:redis.hset('u:10086', 'vl', '1') # 缩短key和field名
# 优化3:只存核心标签(30个),非核心标签留在Hive
# 30个标签 x 1000万用户 x 平均50字节/用户 = 1.5GB(可控)
| 优化项 | 优化前 | 优化后 | 效果 |
|---|---|---|---|
| 标签值编码 | 存原始字符串(平均15字节) | 存编码值(1-2字节) | 内存减少80% |
| Key/Field缩短 | user:profile:10086 / value_level | u:10086 / vl | 内存减少40% |
| 只存核心标签 | 120个标签全存 | 只存30个高频使用的 | 内存减少75% |
| 综合效果 | 约30GB | 约12GB | 内存减少60% |
多级缓存架构——Redis不是万能的
当QPS非常高或者数据量非常大时,单靠Redis可能扛不住。我设计过一个多级缓存的方案:
多级缓存架构:
L1: 本地缓存(Caffeine/Guava Cache)
容量:每台应用服务器缓存10万热门用户
过期:5分钟TTL
命中率:约60%(热门用户重复访问多)
|
v miss
L2: Redis集群
容量:全量核心标签(千万级用户)
过期:24小时TTL(每天全量刷新)
命中率:约99%
|
v miss
L3: HBase / Hive(兜底)
容量:全量所有标签
延迟:50ms-秒级
只有极少量冷用户会走到这一层
为什么要本地缓存?减少网络请求。推荐系统一次请求可能要查50个用户的画像,如果每个都查Redis就是50次网络往返(即使是Pipeline也有开销)。热门用户缓存在本地后,60%的请求不需要访问Redis,整体延迟大幅降低。
面试高频追问
追问一:API接口的安全性怎么保证?画像数据是敏感数据
三层安全措施:①接口认证——每个下游系统有独立的API Key,通过网关验证身份;②字段级权限——不同系统能访问的标签不同,推荐系统能看兴趣偏好但不能看消费金额,运营后台能看全量标签;③审计日志——每次API调用都记录日志(who调了什么接口、查了谁的数据、什么时间),用于合规审计。出海业务还要考虑GDPR,欧洲用户的数据需要额外的脱敏处理。
追问二:Redis挂了怎么办?有降级方案吗?
Redis故障的降级策略:首先Redis本身做主从+哨兵,主节点挂了秒级切换到从节点;其次如果整个Redis集群不可用,API层返回兜底数据——用该用户群体的平均画像替代(比如该国家用户的平均消费水平),不至于推荐系统完全没有画像数据可用。同时触发告警通知数据组排查。我在出海硬件品牌遇到过一次Redis从节点同步延迟的情况,导致部分用户画像是5小时前的旧数据,最终通过增加从节点并调整同步策略解决。
追问三:ES圈选接口慢查询怎么优化?
ES圈选慢查询的常见原因和优化:①字段类型用keyword而不是text——keyword做精确匹配更快;②限制返回条数——圈选结果超过10万就分页返回,不要一次拉全量;③提前预计算热门组合——比如「高价值+活跃」是高频圈选条件,可以预计算一个物化字段hot_segment直接查,避免多条件组合查询。
实战踩坑
我在某出海硬件品牌做画像API时踩过一个大坑:推荐系统调用画像API的QPS从白天的500突然飙升到3000(因为运营做了一波全量推送,推荐系统为每个用户都要查画像)。Redis扛住了,但API服务的Java应用因为线程池打满了开始报错。
排查过程:
1. 监控告警:API服务P99延迟从5ms飙升到500ms
2. 查看线程池:200个线程全部在等Redis响应
3. 发现原因:每次请求查一个用户的30个标签 = 30次HGET
4. 根因:没用Pipeline!单个请求30次网络往返
修复:
- HGET x 30 改为 HMGET一次查30个标签
- 网络往返从30次减少到1次
- P99延迟从500ms回到3ms
教训:Redis查询一定要用批量操作(HMGET/MGET/Pipeline),不要逐个查。在低QPS时感觉不到差异,但QPS一上来,网络往返次数就是瓶颈。这是一个典型的「平时不出问题,上量就崩」的场景。
总结
画像数据对外提供三种模式:API接口(推荐系统)、消息推送(实时营销)、文件同步(广告投放)。API接口核心优化点:Redis存储压缩、多级缓存、批量查询。面试时能讲清楚接口设计、性能优化和故障处理,说明你不只是做数据加工的,更有系统设计的能力。
下一篇聊一个特殊场景:冷启动用户没有行为数据,画像怎么建?
你们画像API的QPS峰值有多少?用的Redis还是HBase?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长