因为锁的问题,我们被扣了1万
前言
春节放假期间,一个项目上的积分接口被刷,而且不止一个人在刷,并且东西也被兑走,放假晚上被人叫起来排查问题,通过这个人的积分明细观察,基本一秒就能获取一次,远远超过了积分规则限定的次数,这肯定是用脚本了,虽然后期联系死活说自己是正常途径获取。由于是业主,我们还是决定自己来承担这个损失,被项目方从合同中扣除奖品费用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());}
}
- 创建一个分布式锁对象,该分布式锁使用redis的
NX
命令实现 - 随后创建一个3s过期的分布式锁,以便锁住该新增积分的请求
- 最后在新增积分执行完后,在finally中释放锁
- 最后返回该用户的最终积分
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 中的添加积分逻辑:
- 首先查询该项目积分规则,查询用户该积分项的积分获取记录总数
- 判断该用户的积分记录总数是否大于 积分规则限定的次数,大于则不处理,返回
- 生成积分记录
- 更新用户总积分
该添加积分的逻辑整体上看好像没什么问题,也确实在一切正常的情况下运行是不会有问题的。
如果PointService 中的添加积分逻辑在分布式锁有效期3s内执行完,是不会有问题的。
但如果PointService中的添加积分逻辑超过3s…那是不是后续请求又可以获取锁了,这也正是这次事故的原因。
因为PointService中的添加积分逻辑超过了3s,并且上一个请求的事务还未提交,后续请求已经获取锁进入PointService,在查询积分记录后,判断还是满足规则,继续执行后续的逻辑,造成用户能够获取多次积分。
问题处理
原因总结一下:
- 添加积分逻辑处理时间过长
- 分布式锁超时
第一个问题:逻辑改动过大,需要时间调整,没有采用
第二个问题:换成Redisson,因为redisson在即使超时的情况下也会续锁,避免锁超时
总结
一方面因为忙于做项目,忽略了代码Review,另一方面测试的时候没有对接口进行并发测试,或者根本没有测出来,第三没有监控工具监控长事务,以及频繁请求。
作者其他文章:
《Prometheus+Grafana 实践派》专栏火热更新中
- Grafana 的介绍和安装
- Grafana监控大屏配置参数介绍(一)
- Grafana监控大屏配置参数介绍(二)
- Grafana监控大屏可视化图表
- Grafana 查询数据和转换数据
- Grafana 告警模块介绍
- Grafana 告警接入飞书通知
Spring Boot Admin 系列
- Spring Boot Admin 参考指南
- SpringBoot Admin服务离线、不显示健康信息的问题
- Spring Boot Admin2 @EnableAdminServer的加载
- Spring Boot Admin2 AdminServerAutoConfiguration详解
- Spring Boot Admin2 实例状态监控详解
- Spring Boot Admin2 自定义JVM监控通知
- Spring Boot Admin2 自定义异常监控
- Spring Boot Admin 监控指标接入Grafana可视化
因为锁的问题,我们被扣了1万相关推荐
- 万向球头的锁紧结构图_联动锁紧球关节万向杆的制作方法
本实用新型涉及五金工具领域,具体说是一种联动锁紧的万向杆 背景技术: 万向杆是一种常用器件,是由多段杆件经回转关节连接而成的.通过各关节转动,其末端可以达到多种不同的位置和方向.末端可配置台灯.照相机 ...
- java 锁表后事务提交_关于synchronized锁在Spring事务中进行数据更新同步,仍出现线程安全问题...
#1 问题描述# 最近有小伙伴在做商品抽奖活动时,在对奖品库存进行扣减,有线程安全的问题,遂加锁synchronized进行同步,但发现加锁后并没有控制住库存线程安全的问题,导致库存仍被超发. 先简单 ...
- 扣减库存,redis你值得拥有
扯扯犊子 并发知识点总结: 1.秒杀,物理业务隔离,抽成单独的服务器 2.接口设计,防止洪流访问数据库. 3.加redis缓存. 4.缓存雪崩,一个请求,多个key同时失效,避免同时失效.多个请求,一 ...
- 一文了解市面上的N种物理锁架构
0x01 锁的概述 "锁"是人们日常生活中必不可少的东西之一,不管在家,在交通工具,在办公场所,"锁"一直扮演着保护场所.保护财产.保护人身安全的角色. 百科对 ...
- 【面试 分布式锁详细解析】续命 自旋锁 看门狗 重入锁,加锁 续命 解锁 核心源码,lua脚本解析,具体代码和lua脚本如何实现
Redisson实现分布式锁原理 自己实现锁续命 在 controller 里开一个 线程 (可以为 守护线程) 每10秒,判断一个 这个 UUID是否存在,如果 存在,重置为 30秒. 如果不存在, ...
- Redis:基于SETNX解决分布式锁误删问题
Redis:SETNX解决分布式锁误删问题 一.概述 二. 分布式锁(初级) (1)锁接口 (2)锁实现类+上锁 (3)释放锁 (4)存在的问题 三. 改进释放锁 (1)准备unlock.lua脚本 ...
- 【分布式锁】三种分布式锁的实现【原创】
分布式锁 0x00 概述 0x02 实现方式 0x03 分布式锁:基于数据库 1. 实现思想 A. 悲观锁(排他锁) B. 乐观锁 2. 优缺点 0x04 分布式锁:基于Zookeeper 1. 实现 ...
- 关于synchronized锁在Spring事务中进行数据更新同步,仍出现线程安全问题
为什么80%的码农都做不了架构师?>>> #1 问题描述# 最近有小伙伴在做商品抽奖活动时,在对奖品库存进行扣减,有线程安全的问题,遂加锁synchronized进行同步,但发 ...
- Python多任务(4.多线程--Python中的互斥锁和死锁)
互斥锁 1.互斥锁的概念 2.互斥锁的使用 3.使用互斥锁完成2个线程对同一全局变量各加100万次的操作,而不会出现问题 死锁 死锁的概念 避如何免死锁: 出现死锁的例子 互斥锁 1.互斥锁的概念 互 ...
最新文章
- 为应用程序增加文件压缩功能
- Android自定义RulerView
- 网页的js源文件被加密解决方案
- 程序员最反感的十件事,你有同感吗?
- Android之jni编译出现no matching function for call to ‘_JNIEnv::GetJava(JNIEnv* , Java VM**)‘解决办法)‘
- 机器学习笔记六之神经网络的学习
- python商业分析_科研进阶 | 纽约大学 | 商业分析、量化金融:基于Python的商业分析工具...
- 【Elasticsearch】Elasticsearch 存储桶聚合
- 推荐时代的内容理解技术探索.pdf(附下载链接)
- document.ready 与 onload 的区别
- Web应用程序中Resource Bundle技术概述
- javascript美术馆
- 分享十个在线听歌、免费下载无损音乐的网站
- java 打印 xps_使用PrintTicket打印XPS,OutputColor PagesPerSheet无效
- 安娜模特java_捧红了梦露的花花公子,首席模特安娜狂露身材,“神臀”不负此名...
- iOS Weak底层详解
- 前端-优雅的VueJS
- android 1.5 app,萌新编程app
- SRE学堂:OSS监控告警案例分析
- 京东DPG图片压缩调研
热门文章
- could not read a hi value - you need to populate the table: hibernate_sequen..
- DPVS适配博通100G网卡
- Android梅花布局
- WPS Excel做多级下拉菜单列表
- 编写10ms延时的子程序c语言,单片机定时器延时程序
- 关键周!非农携众多重量级数据来袭、黄金多头冲击千八大关!
- 怎么将txt转为html
- (pytorch进阶之路)Masked AutoEncoder论文及实现
- C#获取本地磁盘目录
- 计算机应用差错解释,计算机应用基础