第1页
商业产品的广告交互架构
金自翔
第2页
自我介绍
• 百度,商业产品开发 • 十几年软件开发经验
• 流程改进 系统架构 分布式系统
• 微博: 金自翔_Lotus • 微信:
第3页
122,000,000
224,000,000
第4页
Ø 广告交互平台简介
Ø 设计之前 Ø 可用与扩展 Ø 状态持久化与重建 Ø 读写比 Ø 一致性 Ø 保持简单
第5页
传统展示广告
选择
广告检索系统
展示广告
第6页
新型交互广告
交互广告
选择 广告检索系统
提供交互能力
广告交互平台
第7页
广告交互平台
• 可扩展
• 承担比广告检索系统更大的流量
• 高可用
• 不能交互的交互广告 = worse
第8页
Ø 广告交互平台简介
Ø 设计之前
Ø 可用与扩展 Ø 状态持久化与重建 Ø 读写比 Ø 一致性 Ø 保持简单
第9页
考虑可扩展和高可用的时机
验证版
正式版
改进版
重构版
100% 30%
1%
第10页
广告交互平台验证版
• 交互广告靠谱吗?
• 用游戏试试效果
• 尽快上线
• 2人 * 1周 • 后端 php/半台机器 • 每秒轮询后台 • 限制流量
• 正向反馈,快速改进
第11页
正式版首先要明确
• 设计要支持的整体吞吐量 • 所有请求能容忍的最低延迟
第12页
消息推送服务
Sever
会话
• 维持若干终端组成的会话 • 会话内实时推送消息 • 应用场景
• 联机游戏 • 多人聊天 • 遥控器 • 更多…
第13页
延迟和吞吐量
• 延迟
• 通过实验,整体延迟不能超过30 ms
• 后端服务延迟<20 ms (99.99%的请求)
• 吞吐量
• 总流量 × 接入比例 × 互动时长 × 交互频率 × 高峰系数
• 超过 500万 消息/秒
第14页
Ø 广告交互平台简介 Ø 设计之前
Ø 可用与扩展
Ø 状态持久化与重建 Ø 读写比 Ø 一致性 Ø 保持简单
第15页
可用性
• 如果要求>99.99%的可用性
• 年不可用时间<53分钟,可感知停服次数<=1次 • 扩容怎么办?
• 运维和部署
• 运维自动化 监控/报警/切换 • 同构部署 运行时获取个性化配置
• Keep Cool
• Anything that can go wrong will go wrong • 保留冷备份,以备万一
第16页
扩展性
• 分层
• 有针对性的调优和扩容
• 服务无状态
• 水平扩展
• 如何处理全局状态
• 集中存储,热点拆分 (要避免单点影响可用性) • 状态参数化,消除全局状态
第17页
设计高效的消息推送服务
• 路由层和应用层 • 同构部署
• BNS 探活/切流量
• 推送内容不持久化 • 路由信息参数化
路由层 (连接保持)
应用层 (消息推送)
BNS
第18页
会话内通信
client
无状态 client
client
路由层 server server server
集中存储
• 集中存储是单点 (性能&HA) • 额外的网络开销
client
会话保持 client client
client
session1
路由层
session2
server
server
• 如何实现可扩展的会话保持?
第19页
路由信息参数化
1 创建会话
2 选择/注册
5 加入会话
路由层
4 定位server
3 返回server位置
第20页
实现细节
• 安全性
• 加密传输 • 预防 DDOS
• 不考虑重建会话
• server 当机导致会话失效 • 会话延续时间较短,可以接受
• GC、锁与吞吐量
读锁+写锁
CopyOnWriteSet(读无锁)
GC 调优前 2.6万
7.7万
GC 调优后 3.9万
11.9万
第21页
并非所有状态都能参数化
数据落地
持久化
锁 状态 缓存
灾备和可用
第22页
Ø 广告交互平台简介 Ø 设计之前 Ø 可用与扩展
Ø 状态持久化与重建
Ø 读写比 Ø 一致性 Ø 保持简单
第23页
状态持久化与重建
• 同步 or 异步
• 安全 vs 性能和体验 • 存储系统的缺省配置能否满足需要(redis/MQ/
kafka)?
• 本机 or 网络
• 速度 vs 安全和复杂
• 重建状态
第24页
弹幕功能
• 目标
• 用户通过弹幕实现跨广告互动
• 无法直接用消息推送服务实现
• 保存弹幕 (持久化) • 时间长(重建会话状态) • 参与者极多 (原数据结构不合适)
第25页
弹幕解决方案
• 实现额外的弹幕应用
弹幕应用
持久化
存储
• 弹幕应用负责持久化
• 本机异步批量
推送弹幕
• 定时网络备份
消息服务 V2
• 用消息推送服务实现通信
• 消息推送服务升级
• 数据结构 CopyOnWriteSet -> ConcurrentHashSet
• 单机吞吐量 > 10万 QPS
• 支持重建会话状态
第26页
重建会话
依次找寻第一个可用server 加入或重建会话
指定server
1 一致性哈希环 1
路由层
第27页
Ø 广告交互平台简介 Ø 设计之前 Ø 可用与扩展 Ø 状态持久化与重建
Ø 读写比
Ø 一致性 Ø 保持简单
第28页
读写比
• 只读状态
• 复制到内存/机房中
• 读写比>100 缓存
• 写者更新 vs 读者更新
• 读写比<0.01
• 可容忍时考虑写归并
第29页
投票功能
• 目标
• 支持单选项每秒几千次投票
• 是否使用NoSQL? • 投票包含两个状态
• 选项描述信息变化很少 • 选项投票数是个自增变量
第30页
实现投票
定时更新投票信息
Vote
VoteFetcher
1. read
数据库
定时写回数据库
3. 校验
客户端
VoteWriter
4. 内存CAS自增
2. send
数据库压力 ∝ 集群规模
第31页
Ø 广告交互平台简介 Ø 设计之前 Ø 可用与扩展 Ø 状态持久化与重建 Ø 读写比
Ø 一致性
Ø 保持简单
第32页
一致性
业务需求
扩展性 处理方式
例子
强一致性 差 单拷贝,垂直扩展 财务信息
聚合值
中 分而治之,即时汇总 服务调用总数
最终一致性 好
分级缓存,异步刷新 CDN
第33页
抽奖功能
• 目标
• 每秒大几千次抽奖 • 中奖概率实时变化 • 不允许超发奖品 • 锁定和身份验证
第34页
抽奖解决方案
状态
访问频率 要求
方案
抽奖描述 高
奖品
高
抽奖结果 低
最终一致 内存缓存 定时刷新
强一致 Redis 分片/交叉热备
强一致 数据库
可用奖品数 高
?
可用奖品数 = 剩余奖品总数–锁定奖品数
怎么实现锁定和解锁,才能高效获取可用奖品数?
第35页
锁定和解锁(锁定奖品的方案)
奖品区
锁定的奖品放在哪儿?
• Redis • 无触发器,不好解锁
• 应用服务器 • 可解锁,不好HA
超时归还
中奖锁定
锁定区
验证
第36页
锁定和解锁(锁定奖品数的方案)
用Redis记录
奖品区
• 奖品区
• (分钟粒度)即将解锁总数
实时计算可抽奖品数
• 只需要Redis Expire (性能)
Redis
中奖锁定 • 应用服务器无状态(高可用)
Key Value 过期时间
• 以奖品区pop为准 (一致性)
K_0800 1
08:00
Sum K_0801 2
08:01
K_0810 1
08:10
共锁定 4 个奖品 当前可抽奖品数 5 - 4 = 1
第37页
Ø 广告交互平台简介 Ø 设计之前 Ø 可用与扩展 Ø 状态持久化与重建 Ø 读写比 Ø 一致性
Ø 保持简单
第38页
保持简单
有两种设计方法,一种简单清晰,使得明 显没有错误;一种周全完备,使得没有 明 显 错 误 。 前 一 种 方 法 更 困 难 。
Tony Hoare 图灵奖得主 Quick Sort 发明者
第39页
吹千 尽淘 黄万 沙漉 始虽 到辛 ⾦金 苦