红包这一IT产品自2014年微信支付首发之后,就迅速火遍社交圈,已经成为社交类,IM类,甚至电商类软件不可或缺的功能之一。红包市场需求如此广阔,当前除了微信红包,支付宝红包以外,还有多家第三方厂商的红包产品参与着垂直行业和细分市场的竞争,金融魔方云红包是其中之一。
金融魔方云红包面向IM类场景和电商场景分别推出了社交红包和运营红包两类产品,其中社交群红包就直面最典型的高并发高可用的应用需求,金融魔方在长期地商户考察和产品运维迭代中,总结了大量云红包的产品架构设计经验,特在此为技术讨论提供一点微薄的案例,以此抛砖引玉,希望跟技术专家做更深入的交流。
业务场景
首先典型的群红包基本收发场景如下图:
以上业务场景不算复杂,部分需求补充如下:
- 用户发送红包时指定该红包可被分领的份数,红包总额应该可按该份数分配,最少的一份至少可为1分。为兼顾公平和趣味性,每份红包分配数额可按一个幸运因子n随机划分,该因子意味着保障最大份红包金额不应超过所有份红包平均金额的n倍,1<=n<=max(1.3,份额/x),x为允许单个用户最多可得到红包总额的占比,可以根据商户需求设定。
- 一个红包只能被同一个用户抢取一次,群红包产品中,发包用户可以参与红包抢领。
产品联动
以上红包的需求虽然不多,但经过分析各式各样的商户定制化需求,我们最终得到的产品联动图是如下形式的:
解释一下,这其实是三个产品联动共同实现了红包业务。
首先,红包的入金实际上是一笔收银台的下单支付,红包支付,既可以使用用户账户的现有余额,又可以直接通过第三方支付平台进行银行卡支付。值得注意的是,红包支付生成之后,其实就隐含了一个红包的临时账户,这个账户记录了资金从用户账户转出,尚未被用户领取或退回时的中间态金额。
其后,红包的发送和抢取是红包产品专有的业务处理,这个业务处理流程才真正需要解决高并发并可用和最终一致性的问题。
之后,领取的红包通过账户中心的转账接口,从临时账户转入领取用户的钱包余额账户,实现到账,或通过收银台的退款接口,将超时未领取金额退回用户支付通道(如支付通道不支持部分退款需转而充值进入余额)。
最后,用户钱包的余额可由用户通过自主提现,回到绑定的银行卡。
为什么原本简单的一个业务场景我们要生生拆解成三个产品做复杂调用呢?因为在我们为客户做的大量定制化需求中,发现有的客户需要我们完整组合好的三个产品;有的已有了自己的收银入金通道,只需要我们提供红包和钱包;有的已有自己的钱包账户体系,但缺乏收银台和红包;还有的,收银台和钱包账户都已具备,只缺少红包。
因此,在做了高度的产品业务抽象之后,我们梳理设计出高内聚低耦合的三个独立产品,可通过排列组合,可快速适配各种客户需求,通过适配器模式兼容协同客户各种现有职能系统。
应对考验
通过以上分析我们知道,在红包发送之前与领入之后,其实都已脱离了高并发场景,只有红包产品的发领环节,才需要经历单秒内成百上千的并发压力,还要保证核心业务的一致性,多个群组多个红包,更是让这种压力可能成倍放大,对程序设计是极大的考验,那我们是怎么做的呢?
利用Redis设置分布式锁
首先我们通过redis为用户每一次请求申请了一个乐观锁,保证即使在异常情况下(客户端已做限制)一个用户其同时只可能有一个请求访问领取红包接口。
在一个用户领取红包成功后,将同步设置以其用户ID和红包ID的键值的红包领取信息进入redis;在一个用户领取红包之前,也将判定是否redis中具有其用户ID和红包ID组成的键值,若存在,则表明其已领取过,不可再领取。
利用Redis作为缓存
在生成红包成功之时,就将其发包人,祝福语,总额,份数等惰性信息设置于redis中,并同步生成按红包份数和幸运因子划分的每份金额,并将其作为List设置于redis中,。这样避免每次抢取时再实时计算造成的领取与领取之间长时间互斥。只需要从Redis中能成功获取到List中的一份数据,即可表示抢取成功。
同时,抢取的用户和金额同步设置于redis作为缓存以备实时查询。
异步同步数据库和账户
由于群红包领取场景中,用户关注点着重在于抢到红包的体验,而后才可能会转到钱包账户查看余额增减,因此红包领取记录的写入数据库,以及红包领取进一步更新钱包账户的余额,可以通过异步消息触发实施,提供弱一致性体验。
但基于任何环节都可能出错这一分布式架构的基本意识里,对于这个保存领取信息的环节,一旦异步消息未能成功写入消息队列(消息队列中间件崩溃等),马上就要实施降级B方案,调用同步接口完成数据的同步,若B方案失败,则实现C方案需将完整领取信息写入本地日志文件,待后续排除异常后,进行数据分析进行交易补偿。当然,具有着三重方案后,已尽最大程度保障了交易数据的完整性。
投入实践
在实施过程中,对于魔方自己的三类产品之间组合交易的相互调用,借助底层的账户中心的转账等原子化交易,我们通常可以通过本地化事务保障最后红包领取明细生成,余额变更等业务的原子性和一致性。但在与客户遗留系统对接的过程中,由于垂直化的微服务架构,我们往往需要借助状态查询交易和异步补偿流程去保障各系统业务记录的最终一致性。
这就需要加入对账与核账流程。
对账需保障红包明细的入金和收银台的支付订单记录相符,红包的分领需要和钱包账户中心的转账记录相符,红包的失效退余需要与收银台的退款订单记录相符。
核账需要保障在一个红包的生命周期内,其收支最后归0,在一个记账日内的其所有红包(已生成算)收支最后归0(跨切日红包T+1核算时归入上日差额)。
安全保障
由于红包业务本身具有资金收益性,所以安全性也被关注,其中防止被外挂盗抢是很刚需的要求。魔方云红包采用以下两种措施对外挂进行打击:
- 产生红包时,可同步传送参数群组成员ID集,后续所有可领取红包的用户ID必须在该集内才可领取红包。
- 通过对红包用户领取记录和日志的准实时分析,通过多维度的规则判定,可根据外挂账号明显异于人类操作的表现,筛查出可疑账号,提供给客户进行告警和处理。
以上,是魔方云红包实现方案的简单介绍,随着业务发展,业务场景和用户习惯的变迁,魔方云红包产品还将做不断的迭代和优化,以求为用户提供更好的体验,为客户创造更大的价值。
原文地址:http://blog.51cto.com/13801948/2128182