码迷,mamicode.com
首页 > 其他好文 > 详细

redis分布式锁相关

时间:2021-06-02 12:48:39      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:时间设置   并且   word   value   pass   master   cli   Lua脚本   out   

基于Redisson的分布式锁。

使用apollo的addChangeListener方法监听配置。

Redis Pttl 命令以毫秒为单位返回 key 的剩余过期时间。
pexpire 以毫秒为单位设置 key 的生存时间
Psetex 命令以毫秒为单位设置 key 的生存时间

1、通过以下方法创建redis集群实例

JedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout,
int maxAttempts, String password, final GenericObjectPoolConfig poolConfig)

Set<HostAndPort> jedisClusterNode:redis服务器的端口和IP
connectionTimeout:链接超时时间
soTimeout:读超时
maxAttempts:最大重试次数
password:密码
poolConfig:redis池配置

2、获取redissonClient

Config config = new Config();
config.useClusterServers().addNodeAddress(nodesFormater);
nodesFormater:redis://29.2.211.41:7000
RedissonClient redissonClient = Redisson.create(config);

3、根据redissonClient获取锁、释放锁

RLock lock = redissonClient.getLock(lockName) lockName自定义
lock.unlock()

 

向Redis通过EVAL命令执行LUA脚本即可
redLock:多个相互独立没有集群协调机制或者主从复制关系的Redis Master 可重入锁
获取锁:
1、获取锁时向5个redis实例发送的命令
1.1 首先分布式锁的KEY不能存在,如果确实不存在,那么执行hset命令(hset REDLOCK_KEY uuid+threadId 1),并通过pexpire设置失效时间(也是锁的租约时间)
"if (redis.call(‘exists‘, KEYS[1]) == 0) then " +
"redis.call(‘hset‘, KEYS[1], ARGV[2], 1); " +
"redis.call(‘pexpire‘, KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
1.2 如果分布式锁的KEY已经存在,并且value也匹配,表示是当前线程持有的锁,那么重入次数加1,并且设置失效时间
"if (redis.call(‘hexists‘, KEYS[1], ARGV[2]) == 1) then " +
"redis.call(‘hincrby‘, KEYS[1], ARGV[2], 1); " +
"redis.call(‘pexpire‘, KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
1.3 获取分布式锁的KEY的失效时间毫秒数
"return redis.call(‘pttl‘, KEYS[1]);",
备注:这三个参数分别对应KEYS[1],ARGV[1]和ARGV[2]
Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));

释放锁:
2、向5个redis实例都执行如下命令
2.1 如果分布式锁KEY不存在,那么向channel发布一条消息
"if (redis.call(‘exists‘, KEYS[1]) == 0) then " +
"redis.call(‘publish‘, KEYS[2], ARGV[1]); " +
"return 1; " +
"end;" +
2.2如果分布式锁存在,但是value不匹配,表示锁已经被占用,那么直接返回
"if (redis.call(‘hexists‘, KEYS[1], ARGV[3]) == 0) then " +
"return nil;" +
"end; " +
2.3如果就是当前线程占有分布式锁,那么将重入次数减1
"local counter = redis.call(‘hincrby‘, KEYS[1], ARGV[3], -1); " +
2.3.1重入次数减1后的值如果大于0,表示分布式锁有重入过,那么只设置失效时间,还不能删除
"if (counter > 0) then " +
"redis.call(‘pexpire‘, KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
2.3.2重入次数减1后的值如果为0,表示分布式锁只获取过1次,那么删除这个KEY,并发布解锁消息
"redis.call(‘del‘, KEYS[1]); " +
"redis.call(‘publish‘, KEYS[2], ARGV[1]); " +
"return 1; "+
"end; " +
"return nil;",
备注:这5个参数分别对应KEYS[1],KEYS[2],ARGV[1],ARGV[2]和ARGV[3]
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(threadId));

1、set命令要用set key value px milliseconds nx;

String jedisResult = jedis.set(key, value, "NX", "PX", expireTimeMillis);
boolean tryLockResult = "OK".equals(jedisResult);

nx:当key不存在时,设置key的值,px milliseconds:并将key值的过期时间设置为milliseconds毫秒

此命令保证了原子操作:setNX+expireTime


2、value要具有唯一性;UUID+threadId
3、释放锁时要验证value值,不能误解锁:通过key获取value,再与给定的value比较

 

 





 





redis分布式锁相关

标签:时间设置   并且   word   value   pass   master   cli   Lua脚本   out   

原文地址:https://www.cnblogs.com/zt1991jskj/p/13023963.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!