订阅更新

画像数据怎么给到业务系统?接口设计和性能优化

用户画像手册 第 14 题 约 7 分钟读完

本文目录
  1. 先说结论
  2. 三种对外提供模式
  3. API接口设计实战
  4. Redis存储优化——从30GB到12GB
  5. 多级缓存架构——Redis不是万能的
  6. 面试高频追问
  7. 实战踩坑
  8. 总结

先说结论

画像数据对外提供有三种模式: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_levelu: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年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器