闲鱼把各种玩法做成了一个平台:哆啦A梦

2023-11-05

玩法平台背景

在闲鱼内我们把供给用户的闲鱼红包、支付宝红包、包邮券、宝卡等统称为用户权益。是闲鱼用户运营的重要策略,在拉新、留存、促活、裂变等方面都展现了其重要价值。在阿里内部管理权益的平台是拉菲,拉菲对外提供概率抽奖和领奖两种能力。各个业务使用方根据自己的诉求结合拉菲的能力,定制自己业务侧玩法,基于此建立了闲鱼权益玩法平台——哆啦A梦。

痛点分析

早期闲鱼的营销活动有两个重要特点:低频、人工,闲鱼是c2c的二手交易平台,营销活动本身就不多,每年不超过10次。每次营销活动玩法都是简单的抽奖玩法,给中奖用户发奖,需要运营同学逐个联系然后发放权益。随着业务发展集团有了权益相关的平台,其中包括wlp、mrp、拉菲到最终统一的权益平台拉菲2,权益平台的目的就是收敛集团内的权益,简单的理解平台不生产权益、只是权益的搬运工。随着业务的丰富,平台也有了更丰富的权益包括支付宝红包、淘宝单品优惠券、淘宝店铺优惠券、淘宝满减券、闲鱼红包、包邮券等。闲鱼也更关注业务玩法产生了大转盘、翻牌子、九宫格等玩法。随着闲鱼业务的发展在玩法侧有了更多诉求产生了百币夺宝、PK赛、排行榜、签到领币等更复杂的玩法。同时也暴露出了越来越多的问题。

开发侧遇到的问题:

  • 开发周期长,活动业务层并不复杂,但每次活动都要考虑系统安全性、稳定性、数据一致性问题。

  • 发现和定位问题难,缺少监控和对账体系,导致活动中难以及时发现问题,往往是后知后觉。

运营侧遇到的问题:

  • 配置流程复杂,从前端页面配置到活动规则配置分散在多个系统。

  • 沟通成本高,开发侧概念不统一,每次运营对接不同的开发都要接受一套概念。

  • 活动效果无法实时关注,往往都是活动后才开始跑效果数据。

测试侧遇到的问题:

  • 测试成本高,在测试时需要构造多个测试用例条件的账户,用来测试不同情况,此时往往需要开发共同配合。

  • 反馈链路长,黑盒测试时遇到问题,但是不清楚具体问题是什么,该如何保持现场复现。

对于开发来最难以接受的事情莫过于重复,如果再给我一次机会,我一定要搞一个玩法平台,就这样闲鱼玩法平台来了。根据上面总结的问题,给玩法平台一期定下了三个目标:

  1. 沉淀能力可复用,拒绝重复开发,把可复用的能力沉淀

  2. 运营易用,为运营提供可配置平台,可自己完成活动配置上线

  3. 快速发现、定位、反馈问题,为测试提供测试工具

玩法平台1.0

一个平台怎么也要有个名字,大家刚开始希望可以给力的解决闲鱼玩法中遇到的问题,所以起了一个黑土味的名字——奥利给,后面想了想玩法平台主要追逐的是玩法,哆啦A梦的口袋里面什么都可以变出来,与玩法平台刚好契合,所以后面又改为——哆啦A梦。

业务架构

哆啦A梦的业务目标就是收敛闲鱼内的所有权益相关的玩法,所以很多玩法都是基于已有的系统建立的。如下图所示是哆啦A梦的整个业务架构主要分了三个层次,最底层是外部依赖、中间层是系统核心、最上层是业务。

外部系统依赖:哆啦A梦结合业务规则与这些已有的系统能力,开发了多种业务玩法。其中任务系统是玩法的一个重要依赖,其提供了父子任务、组合任务、有序任务等任务编排的能力;人群系统是进行用户身份验证的重要依赖,其提供了人群动态增加、删除、验证的能力;用户行为系统是进行用户行为采集与反馈的系统,其提供了行为编排与实时反馈的能力。个性推荐系统是对不同用户提供个性化的权益系统;对账系统保证系统数据的一致性;用户通知系统提供实时触达通知能力。

系统核心层:哆啦A梦用活动的概念把拉菲玩法和业务规则进行封装,运营只需要通过简单的配置即可完成活动配置,同时哆啦A梦在活动进行中提供了日志采集、流量监控、数据对账、数据报表的基础能力保障活动的稳定安全运行。

业务层:前端提供了多种玩法组件,运营同学配置完活动后可以直接选择可使用的玩法组件,给用户呈现不同的玩法。

运营配置平台

配置平台主要面向运营同学,目标是运营可以不依赖开发,通过配置平台就可以完成一个活动上线,在哆啦A梦中一次营销称为一个活动,在一个活动中会有多种业务规则,每个业务规则中对应一个拉菲权益,举个例子:运营做一次营销活动分别为闲鱼的男性用户发放一种权益,为女性发放一种权益,为未知性别用户发放一种权益,那么该活动中将会对应三个业务规则,分别是男性、女性、未知性别。一个用户抽取权益时,首先判断其性别,然后获取对应规则下的权益。当一个用户符合多个规则时,将会利用规则决策来决定用户具体获取哪个规则下面的权益。

业务决策有两种方式一种是按照权重进行规则决策,一种是算法决策;算法决策目的是权益效率最大化。

开发基础链路

营销活动基础链路主要关心的是流量和安全,流量是对整个系统性能的一个考验,安全是对整个活动业务规则的考验。流量包含正常流量和非法流量,正常流量需要关注活动开始瞬时流量和活动的峰值流量,做好系统扩容和限流保证活动期间服务器不被打挂,非法流量需要关注类似爬虫的机器流量,需要在进入业务层前进行拦截,防止干扰正常的用户。其中安全侧包含业务逻辑和非业务逻辑,业务逻辑包括周期内限制中奖次数,业务规则条件等,非业务逻辑需要着重关注黑灰产的非法用户,其中包括同人账号、同设备账号、同IP账号等,防止活动权益被刷。解决方案如下:

其中霸下校验是集团提供的流量清洗工具,包含DDoS攻击防护、CC攻击防护、Web攻击防护、批量机器行为防御;限流校验接入是集团提供的可以设定单机流量和总流量,超过阈值则采用拒绝访问的限流平台;安全校验接入集团的RMB系统,对同人账号、同设备、同IP的账号进行防控;单用户并发校验利用全局分布式锁,保证同一个账号只能有一个请求进入业务逻辑层,防止同用户并发产生问题;活动码校验,其中活动码是根据活动、时间、用户三个维度生成,利用Base64简单加密和解码进行验证;实时对账主要关注业务规则,对每一个中奖用户进行实时的规则校验,防止规则编码漏洞。小时离线对账主要关注数量级,防止运营侧的配置错误导致奖品的超发。

测试工具

测试工具是面向测试同学的,需要解决两个问题:第一能快速的构造符合测试用例的用户,第二:快速发现、定位、反馈问题。

其中测试用例是依据运营设置的营销规则产生的,如果能灵活的给测试用户添加或者跳过规则校验即可满足测试同学的邀请,本文采用的是白名单的方法去解决构造用户测试用例,当用户需要校验规则时添加到校验的白名单,当用户需要跳过校验时候则提交跳过的白名单,当不添加白名单时走正常的业务校验逻辑。

发现问题方案本文采用的是通过在服务中打异常日志并日志监控系统完成,定位问题时日志打的越细越能快速的定位问题,但同时日志越细代表打的日志就越多,这对系统开销又很大,所以如何做取舍是个关键的问题,本文在解决这个问题上,产出了详细日志和粗略日志两套日志方案,首先把整个抽奖流程分为如下几个步骤如下图所示:

对于线上的正常用户只需要打印最终成功日志和异常日志即可这里采用的是粗略日志,对于测试用户打印每个步骤的详细日志这里采用的是详细日志。最终解决方案流程图如下:

首先测试用户在调用抽奖接口前,可以通过扫码的方式加入白名单,在调用抽奖接口的流程中进行规则校验时,会对该用户进行白名单校验,白名单用户是个复杂对象里面包含了是否校验各个规则,通过校验后最终调用抽奖接口。同时利用Spring的AOP能力在调用抽奖的每个阶段都进行日志的打印,在打印的时候先校验是否是白名单用户,如果是白名单用户则打印每个步骤的详细入参出参,如果是正常线上用户则只需打印异常节点和最终的结果节点即可。为了提高校验白名单的性能,白名单用户信息是存储在内存中的,多台机器的白名单配置同步利用的是Diamond(外部zookeeper同样具有该能力)。

业务效果

上面简单的介绍了整个系统的业务架构和一些主要问题的解决方案,下面主要展示一下使用哆啦A梦平台承接的几种玩法:

玩法平台持续探索

    本文通过对日常营销活动中遇到的问题进行整理,针对这些问题提出相应的解法,进而形成一个业务侧的玩法平台。限于篇幅限制本文主要介绍了系统的整体架构和几个重点解决的问题,对于系统中沉淀出的玩法、测试工具的实现细节、安全体系单独进行分享。后面规划中期望可以把玩法和玩法平台解耦开,作为一种玩法能力对外输出。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

闲鱼把各种玩法做成了一个平台:哆啦A梦 的相关文章

  • 在Maven中生成Version.java文件

    我有一个使用 Ant 脚本构建的 Java 项目 我正在尝试将项目转换为 Maven 其中一项任务生成一个名为 Version java 的 Java 源文件 其中包含编译时间戳的静态字符串表示形式 如下所示 package com foo
  • “源兼容性”和“目标兼容性”有什么区别?

    之间有什么关系 区别sourceCompatibility and targetCompatibility 当它们设置为不同的值时会发生什么 根据工具链和兼容性 https docs gradle org current userguide
  • 在Windows Server 2003下如何在本地系统帐户下运行jvisualvm.exe?

    我在带有 Java 1 6 u 20 的 Windows Server 2003 下将 GlassFish 3 0 1 作为 Windows 服务运行 总体上我很满意 我希望能够在这个 JVM 上使用 VisualVM 并使用无法在 Tom
  • 非易失性领域的出版与阅读

    public class Factory private Singleton instance public Singleton getInstance Singleton res instance if res null synchron
  • 如何在 Android 应用程序中隐藏 Flutterwave API 密钥

    我正在构建一个 Android 应用程序 目前正在将 Flutterwave 集成到我的应用程序中以进行支付 建议我永远不要将 Flutterwave API 密钥放在我的应用程序上 那么我该如何隐藏这些键呢 我正在使用 Retrofit
  • Java 中的 <-- 是什么? [复制]

    这个问题在这里已经有答案了 我遇到了下面的片段 它输出到4 3 2 1 我从来没有遇到过 lt 在爪哇 Is lt 使 var1 的值变为 var2 的运算符 public class Test public static void mai
  • 有人用过 ServiceLoader 和 Guice 一起使用吗?

    我一直想通过我们的应用程序 构建系统进行更大规模的尝试 但更高的优先级不断将其推到次要地位 这似乎是加载 Guice 模块的好方法 并且避免了关于 硬编码配置 的常见抱怨 单个配置属性很少会自行更改 但您几乎总是会有一组配置文件 通常用于不
  • 将类转换为 JSONObject

    我有好几堂这样的课 我想将类转换为 JSONObject 格式 import java io Serializable import com google gson annotations SerializedName public cla
  • JAXB - 忽略元素

    有什么方法可以忽略 Jaxb 解析中的元素吗 我有一个很大的 XML 文件 如果我可以忽略其中一个大而复杂的元素 那么它的解析速度可能会快很多 如果它根本无法验证元素内容并解析文档的其余部分 即使该元素不正确 那就更好了 例如 这应该只生成
  • ThreeTen 向后移植与 JSR-310 的比较

    由于某些原因 我们现在无法使用 java 8 我们仍然停留在 java 7 上 不过 我想使用新的JSR 310 date time APIs现在 使用官方向后移植 ThreeTen http www threeten org threet
  • 在java程序中使用c++ Dll

    我正在尝试使用System LoadLibrary 使用我用 C 编写的一个简单的 dll UseDllInJava java import com sun jna Library import com sun jna Native imp
  • 如何自定义舍入形式

    我的问题可能看起来很简单 但仍然无法得到有效的东西 我需要自定义 Math round 舍入格式或其他格式以使其工作如下 如果数字是 1 6 他应该四舍五入到 1 如果大于或等于 1 7 他应该四舍五入到 2 0 对于所有其他带有 6 的小
  • UseCompressedOops JVM 标志有什么作用以及何时应该使用它?

    HotSpot JVM 标志是什么 XX UseCompressedOops我应该做什么以及什么时候使用它 在 64 位 Java 实例上使用它 与不使用它 时 我会看到什么样的性能和内存使用差异 去年大多数 HotSpot JVM 都默认
  • 我们如何使用 thymeleaf 绑定对象列表的列表

    我有一个表单 用户可以在其中添加任意数量的内容表对象这也可以包含他想要的列对象 就像在 SQL 中构建表一样 我尝试了下面的代码 但没有任何效果 并且当我尝试绑定两个列表时 表单不再出现 控制器 ModelAttribute page pu
  • Azure Java SDK:ServiceException:ForbiddenError:

    尝试了基本位置检索器代码 如下所示 String uri https management core windows net String subscriptionId XXXXXXXX 5fad XXXXXX 9dfa XXXXXX St
  • 我所有的 java 应用程序现在都会抛出 java.awt.headlessException

    所以几天前我有几个工作Java应用程序使用Swing图书馆 JFrame尤其 他们都工作得很好 现在他们都抛出了这个异常 java awt headlessexception 我不知道是什么改变了也许我的Java版本不小心更新了 谢谢你尽你
  • 使用 Apache 允许 Glassfish 和 PHP 在同一服务器中协同工作

    是否可以建立从 Java 到 php 文件的桥梁 我有一个用 Java 编写的应用程序 我需要执行http piwik org http piwik org 这是用 PHP 编写的 在服务器中 我正在运行 PHP 但无法从浏览器访问 php
  • 什么是 Java2D 处理程序线程?

    我创建了一个使用 Hibernate 的示例 java 应用程序 当我进行线程转储时 我观察到一个名为 Java2D Disposer 的奇怪线程 有人能告诉我该线程的功能吗 AWT 系统中的某些实体需要最终确定以释放资源 最突出的例子是j
  • 在会话即将到期之前调用方法

    我的网络应用程序有登录的用户 有一个超时 在会话过期之前 我想执行一个方法来清理一些锁 我已经实现了sessionListener但一旦我到达public void sessionDestroyed HttpSessionEvent eve
  • GAE 无法部署到 App Engine

    我正在尝试从 Eclipse 发布 Web 应用程序 我在 GAE 上创建了四个项目 可以通过登录我的帐户并查看控制台来查看它们 我已经改变了appengine web xml到项目的应用程序 ID 如果我将其更改为 GAE 上第一个创建的

随机推荐

  • 区块链中的去中心化

    想知道更多区块链技术知识 请百度 链客区块链技术问答社区 链客 有问必答 去中心化 是加密经济学领域中使用频率最高的词汇之一 同时也是区块链中最为关键的特性 但是其定义一直模糊不清 为了实现去中心化 迄今为止 人们已经花费数千小时的研究 投
  • android studio 华为手机真机测试

    手机的开发人员选项打开 USB 调试打开 在拨号界面输入 2846579 进入测试菜单界面 然后 Project Menu 后台设置 LOG设置 LOG 开关 LOG 打开 LOG 级别设置 VERBOSE Dump Log 全部选中 重启
  • GDI+ 中图片的绘制

    背景 GDI 中使用 Graphics 类的成员函数 DrawImage 来绘制图片 原样绘制 使用 Graphics 类的 成员函数 DrawImage 来绘制图片 当仅指定绘制起始位置时按照图片大小原样绘制 void DemoGDI D
  • Spark学习(六) 数据结构(迭代器、数组、元组)

    Spark学习 六 数据结构 迭代器 数组 元组 1 迭代器 Iterator 1 在Scala中迭代器不是一种集合 但是它提供了访问集合的一种方法 2 迭代器包含两个基本操作 next和hasNext next可以返回迭代器的下一个元素
  • 哈希表(Hash Table)原理及其实现

    原理 介绍 哈希函数构造 冲突处理 举例 拉链法 hash索引跟B树索引的区别 实现 原理 介绍 哈希表 Hash table 也叫散列表 是根据关键码值 Key value 而直接进行访问的数据结构 也就是说 它通过把关键码值映射到表中一
  • 逻辑回归(梯度上升、交叉验证)Python实现

    目录 1 介绍 2 算法实现 3 代码 4 实验结果 1 介绍 logistic回归又称logistic回归分析 是一种广义的线性回归分析模型 常用于数据挖掘 疾病自动诊断 经济预测等领域 例如 探讨引发疾病的危险因素 并根据危险因素预测疾
  • [shell/脚本]检索某个文件夹下的所有文件夹并且复制文件夹下文件到指定目录

    写一个脚本实现不同分支下的代码sync 递归去检索某个文件下的所有文件 bin bash usage source sync code sh 源码路径 目标路径 SOURCEDIR 1 TARGETDIR 2 if d SOURCEDIR
  • node、npm、cnpm踩坑

    文章目录 前言 一 cnpm i 报错无法使用 二 解决步骤 1 查看cnpm 是否安装 2 查看 node 和 npm 版本 3 处理 总结 前言 提示 npm install g cnpm registry https registry
  • vue项目请求控制请求头必须为https

    前言 因为很多项目必须要求是严格模式 不能有http请求 需要限制我们的请求头必须为https 如果是http的话 手动转成https来实现请求效果 实现方法 在 public index html 的 head 标签里面加入以下代码 效果
  • Step4:Angular调试方法

    1 方法一 采用VSCode编译器 下载插件debugger for chrome 选择调试 然后再选择chrome浏览器 在运行中输入npm start执行 就可以在代码中打断点了 2 方法二 在浏览器中按F12打开开发者工具 Sourc
  • Python第二课

    枭 Python第二课 今天讲解了Python的 内置函数 模块导入 序列 列表 切片操作 内置函数 divmod x y 用法 x y divmod a b 其中x返回值a b y返回值a b map func iterablies 用法
  • 4g网络设置dns地址_4G网速越来越慢,通过这三个简单的操作,网速成倍提升

    随着互联网的进步 从零几年开始移动手机在全国开始普及起来 网速也像火箭一样快速飙升 从2G发展到了现在的5G 不过 有很多网友表示 刚从2G或者3G升级到4G时 网速体验非常好 但近两年来的4G网速越来越慢 还卡顿 甚至感觉还不如以前的3g
  • 忘记网站服务器密码怎么办,忘记远程服务器的密码怎么办

    忘记远程服务器的密码怎么办 内容精选 换一换 如果在创建弹性云服务器时未设置密码 或密码丢失 过期 可以参见本节操作重置密码 密码丢失或过期前 已安装密码重置插件 公共镜像创建的弹性云服务器默认已安装一键重置密码插件 私有镜像创建的云服务器
  • Matlab—M_Map的实战学习笔记(一)M_Map库的安装

    最近在做美赛集训 做到了2020年的美赛A题 有关苏格兰附近鲭鱼和鲱鱼分布预测问题 在写论文的过程中 为了画几张精美的地图 可谓是历经千难万险 花费了不少时间 走了不少弯路 现在对使用matlab的m map映射库进行地图绘制做一个总结 力
  • Python:UnicodedecodeError编码问题解决方法汇总-彻底解决

    今天真的被编码问题一直困扰着 午休都没进行 也真的见识到了各种编码 例如 gbk unicode utf 8 ansi gb2312等 如果脚本程序中编码与文件编码不一致 就会报出UnicodedecodeError的错误 1 情景一 读文
  • python语法-面向对象(构造方法、魔术方法)

    python语法 面向对象 构造方法 魔术方法 1 构造方法 构造方法 python类可以使用 init 方法 称之为构造方法 可以实现 在创建类对象时 会自动执行 在创建类对象时 将传入参数自动传递给 init 方法使用 演示使用构造方法
  • Android中的定时器Timer、AlarmManager、CountDownTimer的使用

    1 Timer和TimerTask的使用 java util Timer定时器 实际上是个线程 定时调度所拥有的TimerTasks 1 创建一个Timer code class hljs cs has numbering style di
  • 解析 Linux 内核可装载模块的版本检查机制

    解析 Linux 内核可装载模块的版本检查机制 王 华东 系统工程师 自由职业者 简介 为保持 Linux 内核的稳定与可持续发展 内核在发展过程中引进了可装载模块这一特性 内核可装载模块就是可在内核运行时加载到内核的一组代码 通常 我们会
  • js获取到的时间减1秒或加1秒

    如题 使用时间戳来计算 function setDate time isAdd var date getCurTime time 也可以直接透传如 2021 5 8 var d new Date date var t s d getTime
  • 闲鱼把各种玩法做成了一个平台:哆啦A梦

    玩法平台背景 在闲鱼内我们把供给用户的闲鱼红包 支付宝红包 包邮券 宝卡等统称为用户权益 是闲鱼用户运营的重要策略 在拉新 留存 促活 裂变等方面都展现了其重要价值 在阿里内部管理权益的平台是拉菲 拉菲对外提供概率抽奖和领奖两种能力 各个业