redislock使用回顾与思考

2022-10-06 14:45:53

最近工作上做一个需求,要求一个用户一天最多两次参与机会,参与一次要获得用户的一个虚拟值。参与接口涉及到关键数据的变化,考虑在这个接口做重复提交限制,以免用户提交时多次点击出现问题,另一个方面其实也是为了幂等,不管用户怎么提交,得到的结果应该都一样。于是用到redislock做重复点击控制。

说到redislock的常见用法,一种是限流,防止多个用户同事操作,流量激增,导致接口压力过大出现非预期问题,比如(有空的话也可以自己试下):

 通过Annotation定义切点方法,定义@Aspect进行切面,切到方法调用前-@Before("pointCut()"),在里面做限流。

一种是防止重复点击,也就是我这里要做的回顾与思考。

大概设计:我们的redis lock工具,加锁是往redis中设置一个key,设置默认超时时间,超时后key失效,设置默认客户端token,用于标识每个线程,当一个客户端多次提交请求,或者多个客户端请求,每个处理请求的线程的token都不一样,保证一个线程加的锁只能被自己解锁,不能被其它线程解锁。解锁通过lua脚本。为什么通过lua脚本因为要确保上述操作是原子性。这里有篇原理性文章大家文章可供参考:https://wudashan.com/2017/10/23/Redis-Distributed-Lock-Implement/

代码定义:

加锁解锁。DefaultRedisScript是RedisScript的默认实现,单例模式

 这边设置脚本的读取从master节点来读取,说从slaver节点读取会有问题。StringRedisTemplate实例是向master连接的实例

使用:

设置redislock超时时间为2秒,也就是线程持有锁持有2秒

如果没有机会提示机会不足

如果频繁点击提示不要频繁点击

 测试结果:

通过jmeter测试重复提交,发起4个请求,期望第一次成功,后面全部失败。第一次请求后等待1秒

正常提交

没有机会

提示不要频繁点击

提示不要频繁点击

 总结:涉及到与用户相关的关键数据变化时,要考虑相关条件的多重校验,健壮性、原子性。从业5年以来,之前做的业务或许也有此类场景,但以前没有做过类似考量,一方面是认知不够,另一方面也是能力有限,希望通过一些总结也慢慢让自己能提升这块能力。通过本次redislock的使用,让自己认识到redis中间件的其它用处,对后端编程有一些新的认识。希望我们一起进步。

其它:

其实说到锁,或许大家都比较熟悉,除了上面说的redislock,还有代码锁,数据库锁-行锁或表锁,行锁保证数据库中的XX特性,MySQLInnodb引擎是行锁,但有些情况会使用表锁,这里不做展开。可能平时用得比较多的是代码锁,可以锁方法,也可以锁代码。锁方法时保证方法调用是串行的(可以通过日志查看线程id观察是否如此),锁代码的话要求有一个唯一不变资源。

  • 作者:5年半码农的渣渣辉
  • 原文链接:https://blog.csdn.net/u011602668/article/details/119321196
    更新时间:2022-10-06 14:45:53