背景
- 用于商家积分兑换商品活动
- 订单送积分
- 营销送积分
实现
要求
- 不允许超扣
- 需要幂等,应对网络问题和重复提交等情况
- 需要高性能
- 需要风控,避免薅羊毛
- 针对锁单需要支持积分预扣
- 针对退单需要积分回滚
步骤
- 用户校验
- 余额校验
- 用户限额校验(基于redis累加,计算剩余可赠送积分值)
- 调用存储过程
- 用户余额校验
- 加锁(MySQL lock 锁定用户id)
- 写入积分日志(开启事务)
- 更新用户余额
其他要求
如何避免超扣
MySQL层面的lock,也有遇到需要超扣的场景,用户一开始就可以使用一定积分,后面再来归还积分。
如何实现幂等
允许外部传入唯一id,通过redis的不存在写入函数,并且在值记录结果
- 值为空(执行中)
- 值不为空(执行成功)
- 执行失败清除值
高性能的实现设计
- 批量提交接口(异步处理)
- 分库分表(提高单表的并发能力)
- 幂等(快速成功或者失败)
- 积分日志同个库设计(避免跨库)
- tomcat线程数调优(原来200,调整至500)
- 数据库连接池调优(原来10,调整至20)
- redis连接池调优(原来200,调整为500)
风控设计
实时检测
允许商家设定每日单用户限额,达到额度后,再赠送积分无效
- redis缓存当前额度
- 每次扣减前判断额度
- 需要考虑用户id变更
每日检测
多维度(大额度,日总额度,频率)
- 创建钉钉机器人,获取token
- 配置告警规则,例如通过nick分组查询单日赠送积分总值超过1w的
基于大数据实时检测
Flink+kafka进行监控
- 执行环境
- 创建数据源
- 用户key分组