1 Redis分布式锁
|1-1 定时任务重复执行-问题引入
最近小耶哥在做一个功能, 什么功能呢? 就是超时未支付的订单我们要定时关闭, 释放库存, 并且短信通知用户该订单因超时被取消了。由于小耶哥很难接到这么”隆重”的任务, 就挖空心思的想把这个功能做”好”。由于小耶哥超高的coding能力, 代码三下五除二就写好了, 话不多说, 直接上代码![手动狗头]
方塔园 by XiaoYeGe
暂且定义此版本为V1版本
// V1 @Scheduled(cron="0 */1 * * * ?")//每1分钟(每个1分钟的整数倍) public void closePaymentOrderTaskV1(){
log.info("关闭超时未支付订单定时任务启动"); int hour = 2; // TODO 此处直接调用service方法, 关闭超时未支付订单 log.info("小耶哥是最帅的,ThreadName->{}", Thread.currentThread().getName()); log.info("超时未支付订单定时任务结束"); }
心里那叫一个美呀!
可是, 美不过3秒, 同桌小鑫(小鑫的真实名字, 你们就别猜了, 不然刘老师知道会很尴尬的)来了一看, 上来就是一顿狂笑,,,,,,
心中暗想这位大胸弟竟然敢嘲笑小耶哥的代码, 简直不想活了吗?
这可是我”精心”coding的结果呀, 就这么不堪!
小鑫同学给我抛出两个问题
1: 分布式服务如何避免不被重复执行这个定时关闭未支付订单?
2: 即是不是分布式系统, 集群中有多台机器, 怎么保证不被重复执行?
身为中国男人, 绝不能认输, 虽然内心慌的一批, 但气势上绝不能输;
............
恩, 小鑫同学还是棒棒哒。
看来我还是有很长的路要走!!!!
怎么解决上面的两个问题, 其实可以有很多种实现方式, 方便一点的方案就是直接利用一些中间件的特性就可以实现, 比如zk, Redis;
要么使用分布式任务调度平台, 比如xxl-job, 唯评会Saturn
本文以Redis分布式锁来解决小耶哥遇到的问题。
不管是以那种形式来实现分布式锁, 总有以下特性
排他性:任意时刻,只能有一个client能获取到锁
容错性:分布式锁服务一般要满足AP,也就是说,只要分布式锁服务集群节点大部分存活,client就可以进行加锁解锁操作
避免死锁:分布式锁一定能得到释放,即使client在释放之前崩溃或者网络不可达
|1-2 Redis分布式原理锁常用命令
1-2-1 Setnx
Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。
语法
redis Setnx 命令基本语法如下:
redis 127.0.0.1:6379> SETNX KEY_NAME VALUE
可用版本
>= 1.0.0
返回值
设置成功,返回 1 。设置失败,返回 0 。
代码示例:
public static Long setnx(String key,String value){
ShardedJedis jedis = null; Long result = null; try {
jedis = RedisShardedPool.getJedis(); result = jedis.setnx(key,value); } catch (Exception e) {
log.error("setnx key:{} value:{} error",key,value,e); RedisShardedPool.returnBrokenResource(jedis); return result; } RedisShardedPool.returnResource(jedis); r