红包逻辑和状态处理

109 阅读6分钟

之前写过一篇红包算法的内容,最后采用了微信的方案,没有使用预分配的方式。今天这篇会介绍下红包业务处理中的更多细节,以及过程迭代中遇到的一些问题和对应处理。

红包业务逻辑简述

首先,和微信红包一样,我在处理红包时,也先做状态检查,可客户端合作,在点击时,先做check,然后根据状态进行对应的操作。如是否过期,是否符合条件,是否已经抢过,以及最终可以抢红包的结果状态,返回列表,计算手气最佳等。这里有个比较特殊的是,一般红包是由用户自己触发,目前有限制,只有两次机会。还有一种是主动发送,称为定时奖励红包,是全量的。这个后面会详细说到。

红包逻辑和状态处理

红包ID

这里是比较复杂的一块,首先说下红包id的生成,用userId+chartId+timestamp+KEY => md5 生成,标记唯一的一个红包。加时间戳和userId, chartId也是为了验证,包括一个私有的KEY作为一定的安全防范措施,防止恶意生成和领取。

生成红包

  1. 生成id
  2. 根据策略生成红包数量,总金额 ,如群人数,固定的比例。 2.1 获取群聊数量 2.2 根据不同类型计算数目,金额 2.3 保存红包记录。 2.3.1 红包 id 为key, size 红包id + remainCoin作为两个值 ,存在Redis,过期时间为1天,数据只有红包数量和总金币,结构简单。Redis存储可以提供一致性和大的并发量,为后续抢红包做准备。 2.3.2 保存数据库记录 。创建时间,名称,类型,消息。 发送者, 目标方,红包总数,总金额(不返回给用户)等,这里单独存储到数据库,做记录。 2.4 返回红包结果 注:这里用服务端返回给客户端结果,也可以考虑直接用Sdk作为消息发给客户端处理。

领取红包

分成两个步骤。 入参: 红包id,用户id, 群聊id, 创建时间 1 如上所述,先检查红包状态 1.1 根据红包id 查库, 获取红包,如果没有则记录不正确。 1.2 检查参数 查库拿到的红包创建者id 和 群聊id ,创建时间 再次生成红包id , 是否与参数红包id 相等,否则表示非法红包参数,这块作为安全验证。 1.3 检查状态 业务状态判断,这里是红包额外的一些业务限制检查,是否满足规定条件。 1.4 获取红包详情 根据红包id 从Redis获取, 红包 id + size 红包id + remainCoin 。 得到 该红包总数,总金额。 1.5 是否已空 该红包剩余的size 和 金币是否>0 1.6 获取红包领取记录 查询红包记录,通过红包id查询。 1.7 是否领取完毕 如果领取记录数 等于 1.4 获取的总数。 或者 1.5条件成立,则是已经领取完毕。 1.8 是否有当前用户领取记录 根据红包领取记录过滤,有当前记录则为有领取记录。 1.9 根据当前已知状态,最终返回状态。 红包非空 1.5 1.7 有当前用户记录 1.8 - 返回已经领取过。 没有当前用户领取记录 1.8 红包过期, 创建时间超过1天。 # 返回过期 红包没有过期 #返回可以领取。 红包已空 1.5 1.7 有当前用户记录 - 返回已经领取过 没有当前用户记录 红包过期, 创建时间超过1天。 # 返回过期 红包没有过期 #返回手慢了,领没了。 1.10 根据状态做对应的展示。

2 根据1中获得的状态,执行后续操作。 2.1 根据红包id 查库, 获取红包,如果没有则记录不正确。 2.2 检查红包参数 , 同1.2中处理。 2.3 查询领取记录 2.3.1 是否匹配到记录 2.3.2 红包是否过期 处理过期 过期:有匹配记录 - 返回消息为金币数 没有匹配记录 记录数等于红包总数 # 红包n个,已经抢光 , 标记手气最佳 - n个红包,已领取m个红包 最终返回状态为 # 过期 2.3.3 没有过期 2.3.4 检查是否足够时长 - 足够 继续 - 不足 返回状态为不足阅读时长 2.3.5 是否领取完毕 2.3.5.1 为空(总数==领取记录数) 如果记录包含当前用户,- 返回成功,用户金币数,已被抢光。 不包含当前用户 - 返回失败 标记手气最佳 检查是否领取过。 2.3.5.2 不为空,进行领取 1-1 记录包含当前用户 。 # 金币数 , 提示n个红包,已经领取m 个,状态为已经领取过 1-2 不包含当前用户 *********计算红包 得到单个金额 redis减少总数和金额,成功 减少成功,写入记录。增加金币,金币系统(加失败重试),最终失败回退 # 返回领取失败 返回剩余金币 - 返回 redis减少总数和金额,失败 状态红包已经被抢光 标记手气最佳 标记领取过

遇到的问题

以上比较仓促,细节对应到逻辑图会更好。红包自测试完备上线后,一直稳定运行,在1-3个月总数据量也到了千万级,不过限于业务限制,并发不高。其中定时红包在群总数逐渐增多后,遇到了几个问题。首先依赖的外部接口流控,导致很多超时,这块最后改为从本地的缓存获取每个群人数,目前看效果良好;其次,由于使用了一个封装好的Redis工具类,没有太注意相关参数,导致后面量增大之后,会有maxRedirection的异常,坑的是工具类的对应参数没法设置,只能自己做了更新,将底层jedis的maxAttempts修改为可配置,同时增大到10解决,之前是5,默认值;最后,定时红包按需求要保证100%的送达,目前遇到两个可能改进的点:一是在单机失败后,加到延迟队列或者在一段时间之后重试,这里延迟是防止当前压力过大,导致滚雪球效应。第二个是目前消息消息触发执行任务,有消息丢失的可能。这块看是否要自己支持结果回调,还是消息系统已经支持对应功能。

以上就是这篇总结,最近做的事,更加深入认识到业务量级所带来的不同挑战,同时也意识到做对应的技术积累和沉淀,未雨绸缪是很重要的事,否则只能被动,而且也不仅是个人,团队,部门,大到公司,集团都是如此,这是后话了。