支撑马蜂窝会员体系全面升级背后的架构设计
流量红利正逐渐走向终结,这已经不再是什么秘密。后互联网时代,如何维系住用户群,提升用户在平台上的体验是整个行业都需要考虑的事情。正是出于这一原因,现在全行业都在关注会员体系的搭建,这也是马蜂窝 2019 年重点投入的方向之一。
面对这个全行业都在发力的会员市场,要对「马蜂窝特色」的会员体系进行有力的支撑,无疑对会员体系的架构设计提出更高的要求。
马蜂窝会员体系建设从 2018 年 9 月份开始启动,经过前期对会员身份和会员权益的摸索,伴随业务的快速发展,到 2019 年上半年,为了让更多用户体验到马蜂窝高质量的会员服务,公司推出了更灵活、维度更多、权益更丰富的会员模式。在这样的背景下,初期较为粗旷的底层技术也需要及时做出调整,对核心架构和服务进行升级。
一、会员身份策略改造
早期的会员身份模块由会员产品、用户属性和时间属性共同构成:
可以看到早期的会员产品比较单一,因此将产品信息设计成一级结构。这种设计的好处是逻辑简单,可以快速实现,但不易扩展,一旦新增会员类别以及不同卡种之间出现复杂关系时,不论是对项目或者对代码本身而言,维护成本都将成倍增长。
从 2019 年年初开始,马蜂窝会员体系进行了全面升级,主要体现在以下几个方面:
-
更完善的获客渠道,增加了在小程序端的服务展示;
-
更丰富的会员类别,新增了非常多卡种,在最初的年度金卡和体验金卡基础上,增加了季度金卡、 7 日卡、「蜂享卡」,未来还计划推出月度金卡、学生卡等;
-
更低的获取门槛,早期的会员身份只能通过在 app 中购买获得,为了让更多用户享受到品质更高的服务,增加了通过完成用户激励任务、供应商合作、产品搭售、线下实体卡等会员获取方式。
这也意味着,同一时间段内用户的会员身份将变得愈发复杂,早期单一的会员身份策略和模型设计已经不能满足需求。重新设计会员身份的时候,我们明确了未来无论业务线如何划分会员身份,底层结构都要能够较好地支持,因此决定把会员模块身份抽离出来。会员体系升级后,产品信息调整为以 sku 作为最小粒度重新划分,同时增加了用户信息中的来源以及获取渠道信息:
二、会员中心架构设计和优化
在明确了新的会员身份策略后,我们对整个会员体系进行了梳理,将现阶段的会员中心架构设计如下:
合上面的架构图来看,目前马蜂窝会员中心系统主要划分为数据存储、核心服务、接口层、应用层四大部分:
-
数据储存:主要基于 mysql 和 redis,以及马蜂窝统一日志系统 mes
-
核心服务:这是当前马蜂窝会员体系中最重要的一层。核心服务又可以分为三大块:
(1)「四驾马车」:会员身份、权益、增值服务接入、会员积分,驱动着整个会员体系的运转;
(2)交易营销:辅助四驾马车快速往前跑;
(3)支撑模块:与会员体系对接的公司级别支撑模块,包括风控、监控、日志、消息总线、商家结算对账等
-
接口层:会员体系对外暴露的接口,包括了会员身份、权益领取、蜂蜜消费等接口
-
应用层:主要是面向 c 端的应用,包括会员频道页、蜂蜜中心、用户权益中心、任务中心等
下面重点围绕「核心服务」层展开介绍。
2.1「四驾马车」
2.1.1 会员身份
目前,市面上很多常见的会员产品都是采用普通的续费模式,比如一些视频平台的年度会员、季度会员。这种模式的特点是只进行时间的区分,在会员身份后生效后享受的权益完全相同,通过续费使权益时效得到相应延长。
但是马蜂窝由于业务的特殊性,会员体系需要设计得更为立体。如果只采用单纯的续费模式,会影响高忠诚度用户的使用体验。
-
首先,在同一类别的会员身份下,时长不同的产品对应的权益也不同。以金卡会员为例,季度金卡、年度金卡这种同类别下的会员身份,可以通过续费升级,但它们彼拥有的权益不完全相同,比如年度金卡 96 折抵额上限为 500 元,季度金卡只有 100 元。
-
另外,同一用户在同一时间内,只要满足条件,就可同时拥有不同类别的卡种,比如金卡和蜂享卡。
为了满足上述需求,我们决定引入用户身份的叠加以及续费模型。通过增加会员 sku 叠加、续费关系表,使用户在一个时间段内不仅可以同时拥有多种身份,还可以续费已有卡种。
上图是会员身份的时间轴示意。横轴代表时间,纵轴代表不同的卡种。我们通过最终 sku 时间轴便可以确认用户当前的会员身份。
我们将用户已有的每个 sku 时间轴拉平,当用户在某个时间点发出购买新卡种的请求时,查看当前生效的时间轴中是否已有用户正在购买的 spu,如果没有则叠加,如已有则需要再判断 sku 之间的配置策略,决定是叠加还是续费;然后继续计算出正在购买的 sku 生效时间轴;接下来根据配置好的规则,对比当前购买生效时间轴和已有 sku 时间轴的身份关系,决定用户是否可以完成此次购买,如:
-
前置身份:指必须已经购买某个 sku,才可以购买当前 sku
-
冲突身份:指如果已经购买某个 sku,就不可以购买当前 sku
为了满足不同的业务需求,这里的叠加、续费关系都是可以通过运营来配置的。整个流程大致示意如下:
为了让用户的体验更好,当同时拥有多重身份的时候,我们会根据数据分析结果调整会员 spu 权重,优先展示权重高的权益。比如当前会员同时拥有金卡和门票卡,数据显示金卡权益的使用率或者关注度高于其他产品,则提升金卡权重,金卡身份和相关权益会在用户进入会员频道页时首先展示。
2.1.2 权益中心
除了身份体系,最重要的就是会员权益,它直接体现会员的不同级别。会员项目发展初期,一切都是从零开始,对拓展性要求不高,每出现一种新的身份、卡种,都需要从头设计其所含权益,开发效率很低,后台的配置也很分散。后期为了支撑业务快速发展,我们开始考虑将权益中心进行拆分,分成两部分进行改造。
第一步是权益池的搭建,下图是权益池的基本模型:
我们将会员权益中通用的属性抽象出来,定义为原则上不变的基础属性,形成「权益物料」存放在权益池中,通用的属性主要包括:
-
权益类型:主要有兑换码、折扣购买、优惠券、三方跳转 4 种,目前能支持到马蜂窝所有的权益类型
-
供应商:不同供应商提供了不同的权益,甚至还有不同的权益接入流程和权益消费流程,同时和涉及了不同的供应商结算模式
-
下发时机:主动下发或者被动下发,例如金卡 96 折权益,是用户购买会员的核心权益,这种权益在用户购卡之后便直接下发至用户账户。其他的权益例如机场贵宾厅、qq 绿钻、腾讯视频季卡等则需要用户主动领取。
-
基础属性:权益的基础属性依赖于权益类型、下发时机、供应商,也就是说不同的供应商或者不同的权益类型和下发时机,都会组合出不同的权益基础属性,这里的属性大多是这些权益的固定属性。最终这 4 大属性共同组成了基本的权益物料。
下图是用户开卡及权益发放的流程示意:
当会员产品支付完成后,会员中心会通知权益中心发放权益;权益中心进行权益过滤之后通知优惠中心,最终由优惠中心完成被动权益的发放;需要用户主动领取的权益则只为用户发放使用权利,最终由用户决定是否领取。
第二步权益规则的配置。有了第一步的基础之后,会员中心为权益池中的权益物料配置相应的权益规则,之后展示给用户。
权益规则主要划分为:
-
条件规则:指确定权益的一些基本前提,主要指会员身份、前求来源、当前业务等
-
通用规则:指对外展示的标准,包括文案、排序、上下线时间、权益说明等等
-
运营规则:这是权益规则中变动最多,也是体现权益中心精细化运营的一部分。不同的用户身份拥有不同的权益价格、兑换价格以及不同的标签,差异化地显示用户的身份特权
我们抽象出了权益规则中的通用属性,形成权益对外展示统一的标准。当然,只有通用的权益规则配置是远远不够的,因此在不影响核心权益规则的前提下,在后台加入了扩展规则模板的配置,以便满足特殊权益不同规则的需求,实现动态规则配置,使用起来更加灵活。
2.1.3 第三方权益接入
权益池中有一部分是站内权益,比如核心的金卡商品 96 折、马蜂窝优惠券、接送机等。这些权益的发放和消费在站内建立的统一规则下完成,接入起来相对容易。
权益池中有一部分是站内权益,比如核心的金卡商品 96 折、马蜂窝优惠券、接送机等。这些权益的发放和消费在站内建立的统一规则下完成,接入起来相对容易。
另外一部分是需要接入的站外权益,也就是为会员供提的增值服务,比如机场贵宾厅、旅行保险等。不同的第三方都有自己权益规则的特殊性,目前无法抽象成统一标准,也就无法采用 openapi 的方式接入。
现阶段我们把第三方权益的接入进行了流程上的整合,最终形成了两大类方式:
-
一类是权益领取在马蜂窝内完成,用户所有的操作完全在我们的应用里进行,完成后异步再调用第三方接口为用户发放权益。
-
第二类是权益领取过程完全在第三方系统中进行,主要针对一些积分兑换的权益。用户点击领取权益后跳转至第三方页面,交互完成之后异步回调马蜂窝接口,马蜂窝系统根据回调情况进行积分的增加或者扣减。这种方式的弊端是用户体验完全由第三方决定,可控性不高;但优势在于能够快速接入一些复杂的权益玩法,比如一些游戏类权益,避免投入大量精力去开发。
上图是两种领取模式的流程对比图,可以看到每一步的三方对接都是通过异步方式进行的,这样当第三方系统出现异常不会影响到马蜂窝的正常服务,使系统可用性得到保证。
2.1.4 会员积分
成长体系对于搭建完整的会员体系非常重要,以内容社区起家的马蜂窝在这方面有天然的优势。我们决定引入已有的用户积分体系「蜂蜜」来承载一部分会员积分的功能。通过与会员中心打通增强与会员用户的线上互动,提高用户活跃度和黏性。在不同的蜂蜜场景和蜂蜜策略下,用户可以赚取积分,满足相应条件后可以兑换所需权益;此外,我们也正在拓展更多蜂蜜和 b 端的结合方式,希望促进平台和商家的共赢。
上图是会员体系利用蜂蜜中心提供的服务以及一些近期规划示意。如何利用好激励机制使整个会员体系更加完善,实现对会员用户更加精细化的运营,对于马蜂窝「内容+交易」战略的深化而言是一个重要的课题,也是研发团队需要不断探索的方向。
2.2 营销活动的性能优化
实现了会员身份、权益中心、第三方权益接入、蜂蜜中心的改造后,会员中心也完成了升级之路的第一步。
为了让更多用户了解会员机制并体验会员权限,我们推出了很多营销活动。其中不少活动都存在秒杀的场景。以下部分就来重点介绍为保障这些营销活动的稳定可靠而进行的技术优化。
2.2.1 并发控制
在秒杀场景中,需要防止由高并发导致的库存超卖。关于这个问题业界已经有不少成熟的解决方案,比如采用悲观锁、分布式锁、乐观锁、队列串行、redis 原子操作等等,当然最理想的是用分布式锁来实现。
考虑到目前的并发量级以及技术成本,我们决定先采用 mysql 乐观锁的方式来实现现阶段的秒杀功能。大家知道数据库内部 update 同一行是不允许并发的,只有当该行被更新后才会释放。我们的方案是通过增加唯一的 version 来防止超卖的情况发生:在每次数据 update 的时候判断版本号是否和数据库中的一致,不一致则表示当前库存已经被其他用户占用,此时抛出异常;如果一致则完成当前用户对库存的占用。
2.2.2 流量削峰
要缓解由瞬间流量爆发造成的数据库压力,我们首先要明确会引起瞬间 qps 剧增的场景。
一种情况是接口被恶意重刷。由于我们的秒杀业务需要用户必须登录,伪造 session 的可能性较低,因此如果这种情况发生,很有可能是由同一个 uid 遍历刷接口导致的。这里只需要加上 uid 的 redis 锁,使一个 uid 在一定时间内只能透过一次请求,这样绝大部分的遍历刷接口行为就能被拦住。
还有一种情况是由流量突发引起,可能是真实的抢购用户数量巨大,也可能是对方使用了大量设备请求,这才是我们目前面对的实际场景。前面我们提到的加 mysql 乐观锁来避免超卖,如果瞬时流量巨大 mysql 的读写、锁表等现象会比较严重,当数据库压力达到极限就会被打挂。因此为了减小数据库的瞬时压力,我们需要在服务层做好限流。比如当库存只有 1000 件,但是有 1w 请求打到数据库时,其实后面的请求都没有意义。我们知道不论是 memcache 还是 redis,单机下每秒扛住 10w 请求都不会有太大问题。所以在没有完成分布式锁的情况下,我们是用 redis 来做最基本的限流,使大部分的请求被拦截在服务层,只有少量请求会穿透到数据库。
上图是当前秒杀体系简单的流程图。后续如果这类会员营销活动依旧是业务重点,我们还是会采用 redis 分布式锁的方式来优化,搭建更为完善的秒杀体系。
2.3 风险控制
关于支撑模块的部分主要分享与风险控制相关的内容。为了保证享受到会员服务的是真实用户,我们需要识别并抵御由黑产带来的潜在风险,保障系统的正常运行,严控由此带来的损失。
上图是目前会员体系中安全控制的结构示意。api 路由层主要负责数据收集和风险预估,收集上来的数据统一写入到公司的日志系统 mes 中存储。我们使用了滑窗模式的限流方式,当发现总访问量超过一定阈值则会将大流量或者过快的请求记录到会员疑似黑名单的表中,再进行路由层的限流处理并接入公司级别风控体系,根据对不同业务场景的识别采用相关风控策略;最终通过邮件、短信等方式通知到路由层相应的技术负责人,尽快处理。
三、总结和展望
在进行马蜂窝会员体系架构的搭建的实战过程中,我们积累了很多有价值的经验,其中感受最深的就是切忌盲目优化,系统层面上的重构更要首先以业务为导向去关注核心框架的升级和技术体系的演进,不要因为过度陷入技术细节而迷失方向。
今后,我们还将积极调研和应用更多主流、前沿技术,比如会员标签、用户画像体系的引入,真正把这些技术用好用活,使会员中心发挥更大价值。
本文作者:马蜂窝电商会员项目研发团队。
彩蛋
欢迎大家关注马蜂窝技术公众号后台,并针对本文积极留言,发表观点或者进行更多相关的技术交流。截至 7 月 27 日 7:00 pm,我们将从公众号后台筛选出留言质量最高的 7 位读者赠送马蜂窝季度金卡,千万别错过!(扫描下方二维码关注公众号)