先说一条核心信息:今天摆在我们面前的,是一套已经被闲鱼拉新业务验证过的投放系统设计思路。闲鱼现在是什么量级?国内最大的闲置物品交易平台。App里一个普通的banner,或者feeds里一张不起眼的卡片,每天可能有上千万双眼睛瞄过。
面对这么大的用户盘子,靠“一视同仁”去推内容,显然不够用了。要想真正服务好用户,就必须做到两件事:一是内容推荐更个性化,二是素材投放更精细化。这篇文章聊的核心问题就是这个——怎么设计一套投放系统,让它既能精准触达用户,又能让运营快速试错,还能把技术同学从重复劳动中解放出来。
思路分析
投放到底是什么?打个比方,城市广场上立着一块大广告牌。不同的时段、不同的场景,你去换上面贴的画,这就是投放。但互联网技术把人这个维度加了进来——不同的人路过,看到的广告画可能完全不同。
拆开来看,一个投放系统至少需要几个基础能力:
第一,资源位的概念。城市广场上那块广告牌,在系统里就叫资源位。前端需要有一个接口去拉取这个资源位要展示的素材。
第二,素材格式的多样性。不同资源位需要的素材格式不一样。有的要banner,有的要feeds,还有的可能只是运营同学手填的一段结构自由的数据——任何合理的数据结构都有可能。
第三,筛选与裁决机制。同一个资源位,不同时段、不同平台、不同人群,应该展示不同的素材。这就需要一个服务,在后台一堆素材里找到最合适的那一个。万一命中了多个,还得有一套规则来拍板——到底谁上。
详细设计
整套系统的角色很清晰:它是一座桥梁,连接的是前端的实体资源位和后端的各种数据源。它的工作就是,从不同的业务数据源中,根据既定规则筛选出需要透出的数据。基本的数据流可以参考下图:

资源位
所谓的资源位,在体系里就是指前端页面上具体的实体坑位。这是技术同学在产品开发阶段创建的。所以,资源位需要消费的数据结构,在开发阶段就已经定死了——是banner、是feeds,还是格式比较灵活的手填数据,都是确定的。
那怎么描述这个数据结构呢?答案是用schema。一个用JSON描述的schema。

具体做法是:技术同学在前端开发完实体资源位后,需要在系统中创建一个对应的虚拟资源位。然后通过一个图形化的JSON schema编辑器,来定义这个资源位到底要消费什么样的数据。

投放物料
有了schema,只是定义了数据格式,但资源位真正需要消费的是数据本身。所以我们在系统中做了一个动态表单模块——它根据schema自动生成一个表单,产品运营同学通过填写这个表单生产出来的数据,就是投放物料。资源位消费的,就是这些物料。
对于手填数据来说,表单直接产出的数据就已经够用了。但如果是Feeds这类特殊类型的数据源,表单通常只能定义一些特征字段——比如选品逻辑。这时候服务端就不能简单地原样返回数据了,它需要根据这些特征字段,去做数据查询和解析,最终返回给前端一个完整规范的数据。

投放单元
前面提到,同一个banner,对不同的人要展示不同的内容。比如新用户给红包,年轻男孩子推手机数码,年轻女孩子推美妆服饰。这一切的背后,需要一个东西把资源位、投放物料和多个投放因子连起来。我们把它叫做投放单元。
投放单元需要多少投放因子?这取决于业务。但基础的因子至少包括:投放时段、投放人群、投放平台、投放AB配置等。
当资源位向投放系统发起请求拉取数据时,系统会在这个资源位上挂载的所有投放单元中,根据投放因子筛选出命中的那些单元,然后把命中的单元上挂载的投放物料返回给前端。如果命中了多个单元,就需要裁决出最终胜出的那一个。最简单的办法是在投放单元里配一个权重,选权重最高的。也可以引入算法,根据CTR数据做排序——哪种方式更优,视业务场景而定。

投放计划
投放计划本质上是产品运营管理多个资源位的一种组织形式。一个投放计划下面,可以挂载多个相关联的资源位。想象一下,一次大促活动,可能要涉及几十个资源位的投放——如果把它们组织在同一个投放计划里统一管理,操作和效果查看的体验都会顺畅很多。
端侧接入
对前端来说,我们希望接入越简单越好。所以封装了一个npm包,调用方只需要传入一个resourceId(资源位ID),就能拿到数据。

这种调用方式对业务方很友好,但对页面性能来说,却是个小麻烦。因为一个页面往往由多个资源位组成,如果每个都单独发起请求,就会形成大量并发请求——页面性能会下降,服务器QPS压力也会飙升。
针对这个问题,我们做了一个小优化:服务端提供一个批量查询接口。前端SDK内部,每10ms对模块的请求调用做一次聚合,把单个资源位的请求转化成批量查询。负面效果是,部分资源位的数据加载会有最多10ms的延时。但换来的好处是明显的:页面整体性能提升,服务器QPS压力也大幅下降。

效果
这套系统在闲鱼的拉新业务实践中运行得相当好。目前已经为闲鱼App内数百个资源位提供投放能力支持,每天服务数以千万计的用户。效果也很明确:资源位的精细化投放实现了,单个资源位的利用率提高了;运营同学有了更大的自由度去做各种拉新实验,试错成本大幅降低;技术同学再也不用频繁跟进运营实验的改造需求,生产力被真正解放了。
总结
综上所述,这套投放系统的设计核心,就是搭建一个连接前端实体资源位与后端多种数据源的桥梁。
当然,其中很多能力依赖了团队内部其他同学的成果。比如:JSON schema的设计方式、根据schema动态生成表单的实现、人群校验服务、AB测试能力、feeds的选品服务,以及个性化动态banner能力。
需要持续优化的方向也不少:数据回流怎么做更好?怎么引入算法能力对策略筛选进行优化?持续迭代、持续为业务创造价值——这始终是我们坚持的方向。
