Upload
others
View
35
Download
0
Embed Size (px)
Citation preview
面临的挑战
• 横向扩展 • 从几百QPS到几万QPS • 从单个数据中心到多个数据中心
• 响应速度 • 响应速度直接影响广告的转化率 • DSP的响应时间不得超过100MS
• 灵活伸缩 • 节假日流量暴涨 • 每天流量高峰,低谷时段
• 海量数据 • 毫秒级DMP数据快速存取 • 多维度自由组合查询报表
横向扩展
随着流量的增长,以一种优雅的方式加机器提高吞吐量是很重要的,我们的主要思路是高低频操作分离,读写分离,需要横向扩展的机器做到无状态。 根据这个思路我们首先对我们的投放结算逻辑进行了拆分。 原来的方式的问题: 1. 结算时需要用到一个时段内的效果数据,没法拆分 2. 投放要求快速返回,结算需要较多的计算 存在这些前提: 1. 结算相对于投放广告频率不高 2. 结算结果并不需要返回给用户
AD Request AD Effect&Billing
Redis
MySQL
通过日志传输服务分离结算
效果记录上报上来,逻辑层马上将效果记录传给消息队列,汇集到日志服务器的磁盘,日志服务器每分钟分析最新的日志,将结果写入数据库。
Redis
MySQL
AD Request
AD Effect
MQ
Filesystem Analytics Cron
Logic Node
Log Node
日志传输服务
当时大概2012年,我们的服务在物理机房,考察了多种消息队列。 最终我们看中了ZeroMQ的性能和非中心化的功能,自己封装了一层,实现了producer和consumer,并且加上了重传保障。 刚开始我们用C语言来实现,不久就用Golang来重写,因为Golang有良好的并发调度特性可以简化程序编写。
RabbitMQ Redis ZeroMQ
性能 6k+ IOPS 3w+ QPS 6w QPS
中心化 YES YES NO
其它优势 Topic Simple
日志传输服务
使用ZeroMQ的Push模式,整个日志传输服务包含3个角色。 • Register:类似Zookeeper,服务发现。 • Client:接收WebAPP传来的日志,推送
给Server。 • Server:接收Client传来的日志,写入磁
盘。
Register
Server Client
Register,Heartbeat Servers
Data Client Server
File
日志传输服务
ZeroMQ方案日志传输服务的优点: • 资源占用极少,在1w/s日志的时候全部server加起来也只要用满一个CPU • 避免Server进程单点 • 性能比较强,生产环境上峰值1w+/s日志没问题 缺点: • 和业务耦合度太高,无法成为通用组件 • 只能将日志写到一个磁盘里面,日志的分析都要读那个磁盘
日志传输服务改用Kafka
• 灵活的Topic和Partition机制 • 同一个内容可以有多个消费者对内容进行不同的处理 • 很好支持Spark Streaming • 4台c4.xlarge支持10w/s 日志读写没问题 • 有很直观的 Kafka Offset Manager
多节点部署
• MySQL主从同步 • 日志分析结果通过队列的同步
细节处理: • DMP数据同步 • 节点间网络延迟延伸出的结算限
量等问题
Master
Slave
node1
node2
Logic
Logic
Read
Read Log
rabbitmq
Log
rabbitmq
Result
Result
Logic Logic
Logic
负载均衡策略
我们采用Nginx+Constistent Hash的负载均衡方案 • 一个用户的请求固定路由到特定的机器 • 充分利用本地缓存,本地缓存的命中率可以达到70% • 减少机器增减的影响
0
2^32-10
0
2^32-10
灵活伸缩
现象: • 每天晚上10点和凌晨4点是请求量的高峰低谷 • 节日期间流量会大涨 在AWS上我们不再需要服务器时刻保持可以对抗峰值请求的性能,我们在流量涨起来时添加广告投放服务器,在流量低时缩减服务器可以有效节约成本。 考虑到我们实际情况:我们需要Consistent Hash,以及一天多次发布新代码的频率;我们自己通过Nginx插件,AWS的API,以及Ansible的Dynamic Inventory 功能实现了一套对业务开发同事无感知的快速扩容方案。
快速扩容系统
1. Controller通过QPS,负载等指标发现需要增加机器
2. Controller调用AWS的API给运行中的Logic机器创建镜像
3. Controller通过新创建的镜像启动n台新的机器 4. Controller确认新的机器可用 5. Controller发送新的Upstream列表给Nginx 6. Nginx reload 后将流量分配到新机器
Nginx
Logic Logic Controller
Proxy Add
Start&Check
Logic Logic
快速扩容技术要点
• 使用 lua_nginx_module 加上几段lua代码可以很方便得出每个域名的统计信息 • 使用 ngx_http_dyups_module 可以增加减少 upstream,再配合我们写的几段lua代码
将更新后的upstream保存到 Nginx的配置文件里 • 通过AWS的API,我们在扩容之前制作镜像并使用最新镜像启动,并且通过EC2的
cloud-init 脚本确保运行的代码最新 • Controller可以配置健康检查链接,只有在新增机器确认状态正常时才添加到 upstream • 我们通过给新增的机器设置标签或者 autoscaling group 将广告投放机器分为一组,通
过 Ansible 的 Dynamic Inventory 特性可以方便地批量操纵这一组机器
广告行为
原来的广告行为存取方案 • 数据存放在 SSD 上的 MariaDB • 一张表分512个 Partition • 根据业务精简每一行数据 • 开启数据库的压缩功能 • 将 MariaDB 当作KV数据库来用 • 多个从库
缺点: • 复杂
ID Data
x {1:1,2:1}
y {1:1,3:1}
MariaDB
Key Value
1 BundleID1
2 BundleID2
Merge
1
2
Logic
3
广告行为
DynamoDB
ID Data
x {BundleID1:1,BundleID2 :1}
y {BundleID2:1,BundleID3:1}
Logic
现在的广告行为存取方案 • 使用DynamoDB直接存
优点: • 简单 • 不用担心容量问题 • 可配置吞吐量 • 访问延迟有保障
报表和日志的存储和分析
以前的方案 • 日志先落地到磁盘然后转存S3 • 将重要的日志存到MongoDB供查询 • 将汇总的结果存到MySQL
缺点 • 单机实时数据分析吞吐量小 • 用crontab跑脚本难以让处理过程可视化 • MongoDB Cluster 维护相对麻烦
File
S3
EMR
Mongo MySQL
报表和日志的存储和分析
现在的方案 • 日志不再落地到磁盘后再分析而是使用Spark
Streaming • 分析得到的报表存放到Redshift • 分析得到的用户相关的信息存放到DDB
优势 • EMR的Spark Streaming足够实时分析每秒好几万行
的日志并且支持热扩容 • 使用支持存放海量数据的Redshift可以方便快速存取
上百个维度的报表数据 • DDB中的数据可供投放服务快速获取
S3
EMR
MySQL
Kafka
Spark Streami
ng
Redshift DDB