作者 Mr_miao 稿

导读:短视频Push系统是一套支持百度内多款app及多业务场景的分布式Push系统,目前支撑着好看视频,直播,度小视,好看大字版等app的推送业务,提供基于用户基本特征的个性化推送,热门活动和热点事件的运营推送,基于关注关系或订阅关系的业务实时推送等场景的支持。旨在通过个性化推荐系统及运营编辑方式稳定高效的给用户通知栏消息推送自己喜欢的内容信息从而达到提高用户活跃度,提升用户留存的业务目标。

背景:

在这个信息爆炸的互联网时代,能够及时和准确获取信息是当今社会要解决的关键问题之一,Push技术改变了传统的靠"主动拉"获取信息的方式,而是变成了信息主动寻找用户的方式,更适合在移动网络中满足用户个性化信息的需求。本文主要通过介绍短视频Push系统的设计和实现以及系统的不断优化,从而向大家讲述亿级数据量的Push系统的建设经验。

名词解释:

消息推送(Push): 通知栏消息推送,由服务端发起推送,在用户设备的锁屏界面、通知栏、APP角标等位置展现的消息内容。

个性化Push: 通过用户画像和推荐模型挑选用户感兴趣的物料的Push。

运营Push: 由运营人员在Push后台手动编辑物料发送的Push(如:热门活动和热点事件等推送)。

实时Push: 根据用户在app产生互动操作(如:关注、点赞、评论等)或直播开播需要发送开播提醒时对时间要求相对精确的实时发送的Push。

01了解系统

系统简介

随着百度旗下短视频业务不断发展,app也有上亿级别的季活用户量。Push系统每天会给app的季活用户进行n条个性化推送和不固定条数的热门活动和热点事件运营推送,需要处理的数据量和并发量是系统设计需要考虑的重要问题,此外根据不同地域的用户群每天会发上百条的地域推送和大量的关注关系等实时推送,这对系统的稳定性要求也是很严格的,众所周知Push是一种很有效的拉活手段,其系统的稳定性重要程度可想而知。

系统全貌

Push系统服务于好看视频,直播,度小视,好看大字版等业务。系统会实时订阅更新视频物料信息和用户属性信息,保障构建Push消息体时信息的准确性,会在凌晨请求推荐服务进行个性化物料的召回,然后根据运营Push和个性化Push的时间点创建Push任务,任务创建完成后会提前半个小时进行任务的预处理操作(保障Push能按时间尽快的发送),用户互动消息和直播开播提醒等实时Push是通过api调用实时把要推送的内容发送给Push预处理服务。预处理完成将结果写进redis队列中,发送服务根据任务的优先级发送信息给云Push中台,云Push中台调用厂商代理or自己的长链接服务将Push信息发送到用户手机上。

总体架构如下图所示:

Push核心架构各模块简介

  • **物料中心:**存储Push时需要的视频物料信息,包含Push的标题,描述,物料图片及状态等信息,订阅B端视频变更消息队列实时更新。
  • **用户中心:**存储Push需要的用户基本信息及Push系统特有的一些用户属性(如:1.预估用户活跃时间。2.预估用户首末条个性化Push时间等),客户端上报用户信息实时更新。
  • **个性化召回:**每天凌晨1点开始对季活用户进行个性化物料召回用于白天个性化Push的发送。
  • **realtime-api服务:**实时写入预处理队列进行数据预处理及发送操作,用于实时Push等场景。
  • **频控服务(ufc):**防止打扰用户,分天级别和小时级别两种。天级别的频控设置,一个用户一天内设置最大Push条数。小时级别,每个用户每半小时内最多收到1条Push。
  • **预处理服务:**提前半小时对入库的任务进行切分,消息构造和入Push队列等处理,保障Push任务按时发送。
  • **发送服务:**根据任务的发送时间及任务的优先级从Push队列中获取相应厂商的任务将任务根据厂商的ups和qps进行切割后发送给云Push。
  • **回执服务:**根据各厂商的到达回执记录相关日志,用于数据统计及实时监控报警。
  • **控制中心(pcc):**重要Push功能的可视化配置系统。

Push核心架构各模块依赖图如下:

系统数据流

系统整体数据流

客户端上报用户信息及一些用户行为的打点日志到数据中心,数据中心根据客户端打点产出相应的数据表,策略根据数据中心产出的数据表产出视频物料、Push发送用户集和代理配额用户集,架构侧根据策略模型进行Push物料的召回并进行任务创建和发送将信息发送给Push中台,Push中台发送给各厂商代理或长链接并产出Push相关数据表,厂商感知Push到达后发送回执消息给内部服务,架构根据到达回执记录日志并上报数据中心完成相关报表的产出。如下图所示:

客户端: 通过Push sdk完成Push_token的绑定,上报用户基本信息及用户行为打点日志。

数据中心: 根据业务打点产出活跃用户表、用户行为表和相关业务报表。

Push策略: 天级别产出Push物料并根据用户画像产出个性化Push物料。

Push架构: 凌晨进行个性化Push物料召回,定时进行任务发送并处理厂商的到达回执。

云Push中台: Push任务发送给各厂商代理或长链接并产出Push基础数据表。

厂商代理: 负责将各自厂商的Push任务发送到用户设备并发送到达回执。

Push到达回执数据流

Push到达回执分三种,各安卓代理厂商回执,Ios回执和长链接回执,都由Push中台服务接收然后写进消息队列,架构侧的Push-arrive服务消费消息队列,1.实时统计计算并将数据写入Redis供实时统计报表使用,1.记录本地Log,采集后做实时监控和报警,并上传到数据中心产出相关统计报表、Push物料候选集,此外还会产出Push的点展样本用作Push模型的训练。

如下图所示:

02 系统迭代及优化之路

定时预估个性化Push首末条发送时间

背景

原逻辑所有用户每天首条个性化push的时间为6:30,最后一条个性化Push的时间为21:45。而每个用户起床、入睡时间不同,不同时间对接收到的Push敏感度也不同,根据用户习惯选择时间发送,可以提高Push的点击率。


服务设计

通过用户的使用习惯预估不同用户每日的首末条发送时间,达到用户在想看手机的时候准时给他Push他感兴趣的内容。显而易见服务的难点在于怎么预估用户什么时间比较空闲会看手机,大致逻辑如下,首条发送时间预估,统计7天内用户在[5:30, 6:00]时段内的首次活跃天数,若大于1,则此用户的首条个性化发送时间由6:30调整为5:30;非上述区间,则统计7天内该用户在[5:30, 6:30]时段内的首次活跃天数,若大于1,则此用户的首条个性化发送时间由6:30调整为6:00;剩下的用户发送时间仍为6:30;末条发送时间预估,统计7天内用户在[22:15, 22:45]时段内的首次活跃天数,若大于1,则此用户的首条个性化发送时间由21:45调整为22:15;非上述区间,则统计7天内该用户在[22:15 23:59]时段内的首次活跃天数,若大于1,则此用户的首条个性化发送时间由21:45调整为22:45;剩下的用户发送时间仍为21:45;如下图所示:

Push系统用户分群服务优化

背景

此服务产出Push所需要的各种用户集合全量用户、个性化用户、兴趣用户、地域用户等,统称为用户包)用户包的产出依赖于不同的上游,包括用户中心、策略、数据组等,随着业务的迭代,存在以下几个问题:

1)缺乏统一管理,大多为部署在物理机上的定时脚本,存在单点问题,数据产出的监控、报警分散。

2)用户包的存储依赖物理机及hadoop集群,发送过程需要通过ftp、afs文件将用户包全量加载到内存,全量单任务耗时30s左右,影响时效性。

3)每种类型用户包都进行了单独的存储,存储资源存在浪费。

4)运营多选用户包时,加载重复的用户标识浪费内存资源,去重过程影响时效性。

5)直播召回模块重启时加载关注用户包及处理逻辑过程时间较长,影响上线效率及服务可用性,单机重启需20分钟。

服务设计

新老架构对比

  • 原架构

  • 新架构

1)为区别当前架构中基于物理机ftp、afs集群的用户包,使用用户群来表示符合某个单一维度特征的用户集合。

2)用户群的注册和管理通过 amis 平台统一配置,每个用户群拥有一个唯一标识。

3)用户群采用 bitmap 的方式进行表示及存储,bitmap 中每一位即表示一个用户,每个用户群都可以用一个 bitmap 来表示。

4)将Push 服务中原有的用户包地址替换为用户群标签,多个用户群之间支持逻辑运算,用逻辑表达式表示。

5)发送过程中首先通过用户群标签的逻辑表达式查询用户群服务,获取一个最终要发送用户的bitmap;再通过 bitmap 从用户群服务中批量获取 用户标识,流式处理并发送。

用户群管理设计

用户群配置:

1)配置层通过 amis 平台进行用户群的统一管理,以任务形式存于mysql中,支持用户群标签、用户包产出地址、更新频率、重试次数等配置;

2)调度层针对每个任务进行抢占式定时调度,将抢到的任务发给服务层执行;

3)服务层获取到任务,开始建库过程:

1、根据用户包地址拉取远程文件,成功则继续向下,失败则修改执行记录表任务状态及重试次数;

2、加载文件中的用户标识,计算对应crc64/fnv64值,并将结果映射存储在redis 中(k:crc64/fnv64,v:用户标识);

3、计算当前用户群的 bitmap(RaoringBitmap算法),并将结果存储在 redis 中(k:用户群标签,v:用户群bitmap)。

在线服务交互设计

在线服务交互流程:

1)Push 任务通过用户群标签来指定发送用户集合(amis/定时任务写入 mysql),多个标签使用逻辑表达式表示;

2)Push 服务层获取发送任务后,使用标签表达式请求用户群在线服务;

3)用户群在线服务根据逻辑表达式,从 redis中读取出所有用户群标签的 bitmap,进行逻辑运算,得到最终发送用户群的 bitmap,返回给 push 服务层;

4)Push 服务层遍历 bitmap,按位获取crc64/fnv64值,批量请求用户群服务;

5)用户群服务从 redis将crc64/fnv64映射回对应用户标识,返回给 Push 服务层。

Push系统频控服务(ufc)优化改造

频控服务主要有如下功能:

1)基础功能限制一个用户在30分钟内不能收到两条Push消息,一天内Push总条数不能超过max条

  1. 结合策略的提供的白名单数据,时间段频控,用户标识+推送类型的权重策略数据,到达回收数据,进行个性化频控
  2. 永久PushType和用户标识 白名单功能,针对这类PushType,用户标识不进行频控

背景

  1. ufc目前通过hash(用户标识)的值取mod的形式分配固定的物理存储频控数据,固定了分配服务器个数,服务器ip,不容易扩展,且扩展后会影响当天的用户频控数据,扩展上线大约1个小时。

2)推送类型、用户标识白名单经常变化的配置采用配置文件形式,每次改动上线耗费时间长。

  1. 服务混合部署物理机,与其他服务竞争资源,会影响或者受到其他服务的影响,服务不稳定。

服务设计

动态扩容,一致性hash算法

  1. 首先求出服务器(节点)的哈希值,并将其配置到0~2^32^ 的圆(continuum)上。
  2. 然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
  3. 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过2^32^ 仍然找不到服务器,就会保存到第一台服务器上。

资源压缩,使用protobuf协议进行数据压缩

Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。Protobuf 由如 JSON 和 XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对你的结构化数据轻松读写。

**一句话描述:**protobuf是二进制协议, 通过给json设计了schema来提供更快的解析速度,主要是把比如{,",key 等值舍弃,采用tag|value存值,传输效率极高,传输体积很小,在tcp/rpc里的使用很普及。

序列化耗时对比:

bytes字节数对比:

Push业务个协议对比:

结论: proto的Marshal 比 json的Marshal快2倍,压缩后数据大小proto是json的 1/4,且数据越大优势越明显。最终频控数据压缩后节省75%的redis资源。

03 总结

消息推送(Push)是移动端App产品运营的重要手段,成本低效益高。随着移动互联网的高速发展,手机应用的开发越来越成熟,应用的更新频率也随之提高,同时各应用推送的消息也是五花八门,能否及时和准确给用户推送他感兴趣的消息内容,提升推送信息的消费率是Push系统的核心价值。

“苹果之父”乔布斯曾说:“根据大众的需要去设计产品其实是非常难的。因为在很多情况下,人们并不知道自己想要什么,所以需要你去展示给他看。”我感觉这句话用在推送上也是合适的,对于明确自己想要什么样的消息内容的用户,推送内容可以投其所好(个性化推送)。对于不明确自己想要什么样的消息内容的用户,App运营者在推送消息时需要考虑消息的可行性。不只是内容