前言

春节放假期间,一个项目上的积分接口被刷,而且不止一个人在刷,并且东西也被兑走,放假晚上被人叫起来排查问题,通过这个人的积分明细观察,基本一秒就能获取一次,远远超过了积分规则限定的次数,这肯定是用脚本了,虽然后期联系死活说自己是正常途径获取。由于是业主,我们还是决定自己来承担这个损失,被项目方从合同中扣除奖品费用1万余元。

问题原因

先说下接口的逻辑层次结构:

–controller 积分获取接口,用PointController表示

–service 积分获取接口service,用PointService表示

我用伪代码来表示整个调用逻辑:

PointController

@RestController
public class PointController {@Resourceprivate PointService pointService;@GetMapping(/addPoint)public Response addPoint() {//分布式锁,使用redis的NX命令RedisDistributedLock lock = new RedisDistributedLock();//创建一个3s过期,100ms休眠的锁if(lock.lock("POINT_KEY", 3000L, 100L)) {try {//调用pointService.addPoint();} catch (Exception ex) {e.printStackTrace;} finally {//解锁lock.unlock("POINT_KEY");}}return Response.ok(getLastPoint());}
}
  1. 创建一个分布式锁对象,该分布式锁使用redis的NX命令实现
  2. 随后创建一个3s过期的分布式锁,以便锁住该新增积分的请求
  3. 最后在新增积分执行完后,在finally中释放锁
  4. 最后返回该用户的最终积分

PointService

public class PointService {@Transactional(rollbackFor = Exception.class)public void addPoint() {//查询积分规则PointRule pointRule = getPointRule();//查询用户该积分项的积分获取记录总数Integer total = getPointRecords();//判断该用户的积分记录总数是否大于 积分规则限定的次数//大于则不处理,返回if(total - pointRule.getRuleTimes >= 0) {return;}//生成积分记录int insert = insertPointRecords();//更新用户总积分if(insert > 0) {updateUserPoint();}}
}

PointService 中的添加积分逻辑:

  1. 首先查询该项目积分规则,查询用户该积分项的积分获取记录总数
  2. 判断该用户的积分记录总数是否大于 积分规则限定的次数,大于则不处理,返回
  3. 生成积分记录
  4. 更新用户总积分

该添加积分的逻辑整体上看好像没什么问题,也确实在一切正常的情况下运行是不会有问题的。

如果PointService 中的添加积分逻辑在分布式锁有效期3s内执行完,是不会有问题的。

但如果PointService中的添加积分逻辑超过3s…那是不是后续请求又可以获取锁了,这也正是这次事故的原因。

因为PointService中的添加积分逻辑超过了3s,并且上一个请求的事务还未提交,后续请求已经获取锁进入PointService,在查询积分记录后,判断还是满足规则,继续执行后续的逻辑,造成用户能够获取多次积分。

问题处理

原因总结一下:

  1. 添加积分逻辑处理时间过长
  2. 分布式锁超时

第一个问题:逻辑改动过大,需要时间调整,没有采用

第二个问题:换成Redisson,因为redisson在即使超时的情况下也会续锁,避免锁超时

总结

一方面因为忙于做项目,忽略了代码Review,另一方面测试的时候没有对接口进行并发测试,或者根本没有测出来,第三没有监控工具监控长事务,以及频繁请求。

作者其他文章:
《Prometheus+Grafana 实践派》专栏火热更新中

  1. Grafana 的介绍和安装
  2. Grafana监控大屏配置参数介绍(一)
  3. Grafana监控大屏配置参数介绍(二)
  4. Grafana监控大屏可视化图表
  5. Grafana 查询数据和转换数据
  6. Grafana 告警模块介绍
  7. Grafana 告警接入飞书通知

Spring Boot Admin 系列

  1. Spring Boot Admin 参考指南
  2. SpringBoot Admin服务离线、不显示健康信息的问题
  3. Spring Boot Admin2 @EnableAdminServer的加载
  4. Spring Boot Admin2 AdminServerAutoConfiguration详解
  5. Spring Boot Admin2 实例状态监控详解
  6. Spring Boot Admin2 自定义JVM监控通知
  7. Spring Boot Admin2 自定义异常监控
  8. Spring Boot Admin 监控指标接入Grafana可视化

因为锁的问题,我们被扣了1万相关推荐

  1. 万向球头的锁紧结构图_联动锁紧球关节万向杆的制作方法

    本实用新型涉及五金工具领域,具体说是一种联动锁紧的万向杆 背景技术: 万向杆是一种常用器件,是由多段杆件经回转关节连接而成的.通过各关节转动,其末端可以达到多种不同的位置和方向.末端可配置台灯.照相机 ...

  2. java 锁表后事务提交_关于synchronized锁在Spring事务中进行数据更新同步,仍出现线程安全问题...

    #1 问题描述# 最近有小伙伴在做商品抽奖活动时,在对奖品库存进行扣减,有线程安全的问题,遂加锁synchronized进行同步,但发现加锁后并没有控制住库存线程安全的问题,导致库存仍被超发. 先简单 ...

  3. 扣减库存,redis你值得拥有

    扯扯犊子 并发知识点总结: 1.秒杀,物理业务隔离,抽成单独的服务器 2.接口设计,防止洪流访问数据库. 3.加redis缓存. 4.缓存雪崩,一个请求,多个key同时失效,避免同时失效.多个请求,一 ...

  4. 一文了解市面上的N种物理锁架构

    0x01 锁的概述 "锁"是人们日常生活中必不可少的东西之一,不管在家,在交通工具,在办公场所,"锁"一直扮演着保护场所.保护财产.保护人身安全的角色. 百科对 ...

  5. 【面试 分布式锁详细解析】续命 自旋锁 看门狗 重入锁,加锁 续命 解锁 核心源码,lua脚本解析,具体代码和lua脚本如何实现

    Redisson实现分布式锁原理 自己实现锁续命 在 controller 里开一个 线程 (可以为 守护线程) 每10秒,判断一个 这个 UUID是否存在,如果 存在,重置为 30秒. 如果不存在, ...

  6. Redis:基于SETNX解决分布式锁误删问题

    Redis:SETNX解决分布式锁误删问题 一.概述 二. 分布式锁(初级) (1)锁接口 (2)锁实现类+上锁 (3)释放锁 (4)存在的问题 三. 改进释放锁 (1)准备unlock.lua脚本 ...

  7. 【分布式锁】三种分布式锁的实现【原创】

    分布式锁 0x00 概述 0x02 实现方式 0x03 分布式锁:基于数据库 1. 实现思想 A. 悲观锁(排他锁) B. 乐观锁 2. 优缺点 0x04 分布式锁:基于Zookeeper 1. 实现 ...

  8. 关于synchronized锁在Spring事务中进行数据更新同步,仍出现线程安全问题

    为什么80%的码农都做不了架构师?>>>    #1 问题描述# 最近有小伙伴在做商品抽奖活动时,在对奖品库存进行扣减,有线程安全的问题,遂加锁synchronized进行同步,但发 ...

  9. Python多任务(4.多线程--Python中的互斥锁和死锁)

    互斥锁 1.互斥锁的概念 2.互斥锁的使用 3.使用互斥锁完成2个线程对同一全局变量各加100万次的操作,而不会出现问题 死锁 死锁的概念 避如何免死锁: 出现死锁的例子 互斥锁 1.互斥锁的概念 互 ...

最新文章

  1. 为应用程序增加文件压缩功能
  2. Android自定义RulerView
  3. 网页的js源文件被加密解决方案
  4. 程序员最反感的十件事,你有同感吗?
  5. Android之jni编译出现no matching function for call to ‘_JNIEnv::GetJava(JNIEnv* , Java VM**)‘解决办法)‘
  6. 机器学习笔记六之神经网络的学习
  7. python商业分析_科研进阶 | 纽约大学 | 商业分析、量化金融:基于Python的商业分析工具...
  8. 【Elasticsearch】Elasticsearch 存储桶聚合
  9. 推荐时代的内容理解技术探索.pdf(附下载链接)
  10. document.ready 与 onload 的区别
  11. Web应用程序中Resource Bundle技术概述
  12. javascript美术馆
  13. 分享十个在线听歌、免费下载无损音乐的网站
  14. java 打印 xps_使用PrintTicket打印XPS,OutputColor PagesPerSheet无效
  15. 安娜模特java_捧红了梦露的花花公子,首席模特安娜狂露身材,“神臀”不负此名...
  16. iOS Weak底层详解
  17. 前端-优雅的VueJS
  18. android 1.5 app,萌新编程app
  19. SRE学堂:OSS监控告警案例分析
  20. 京东DPG图片压缩调研

热门文章

  1. could not read a hi value - you need to populate the table: hibernate_sequen..
  2. DPVS适配博通100G网卡
  3. Android梅花布局
  4. WPS Excel做多级下拉菜单列表
  5. 编写10ms延时的子程序c语言,单片机定时器延时程序
  6. 关键周!非农携众多重量级数据来袭、黄金多头冲击千八大关!
  7. 怎么将txt转为html
  8. (pytorch进阶之路)Masked AutoEncoder论文及实现
  9. C#获取本地磁盘目录
  10. 计算机应用差错解释,计算机应用基础