背景

  • 用于商家积分兑换商品活动
  • 订单送积分
  • 营销送积分

实现

要求

  • 不允许超扣
  • 需要幂等,应对网络问题和重复提交等情况
  • 需要高性能
  • 需要风控,避免薅羊毛
  • 针对锁单需要支持积分预扣
  • 针对退单需要积分回滚

步骤

  1. 用户校验
  2. 余额校验
  3. 用户限额校验(基于redis累加,计算剩余可赠送积分值)
  4. 调用存储过程
    1. 用户余额校验
    2. 加锁(MySQL lock 锁定用户id)
    3. 写入积分日志(开启事务)
    4. 更新用户余额

其他要求

如何避免超扣

MySQL层面的lock,也有遇到需要超扣的场景,用户一开始就可以使用一定积分,后面再来归还积分。

如何实现幂等

允许外部传入唯一id,通过redis的不存在写入函数,并且在值记录结果

  • 值为空(执行中)
  • 值不为空(执行成功)
  • 执行失败清除值

高性能的实现设计

  • 批量提交接口(异步处理)
  • 分库分表(提高单表的并发能力)
  • 幂等(快速成功或者失败)
  • 积分日志同个库设计(避免跨库)
  • tomcat线程数调优(原来200,调整至500)
  • 数据库连接池调优(原来10,调整至20)
  • redis连接池调优(原来200,调整为500)

风控设计

实时检测

允许商家设定每日单用户限额,达到额度后,再赠送积分无效

  • redis缓存当前额度
  • 每次扣减前判断额度
  • 需要考虑用户id变更

每日检测

多维度(大额度,日总额度,频率)

  1. 创建钉钉机器人,获取token
  2. 配置告警规则,例如通过nick分组查询单日赠送积分总值超过1w的

基于大数据实时检测

Flink+kafka进行监控

  1. 执行环境
  2. 创建数据源
  3. 用户key分组