添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
粗眉毛的薯片  ·  JavaScript forEach() ...·  11 月前    · 
寂寞的日光灯  ·  Getting Started | ...·  1 年前    · 
胡子拉碴的手术刀  ·  .net core web api ...·  1 年前    · 

在这片文章中,使用Jedis clien进行lua脚本的相关操作,同时也使用一部分jedis提供的具有原子性set操作来完成值和过期时间的同时设置。使用lua脚本根本原因也是为了保证我们两个redis操作之间的原子性,使分布式锁更加可靠。

JedisCluster相关代码配置

在博主的实现例子中使用redis集群实现分布式锁,所以在开始分布式锁实现之前需要进行JedisCluster的相关配置。博主是在spring boot的下进行开发,JedisCluster需要做的配置如下。

首先是依赖包引入,如下代码所示。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

加入必要的配置信息

#redis集群连接配置
spring.redis.cluster.nodes=192.168.0.15:6379,192.168.0.15:6380,192.168.0.15:6381,192.168.0.15:6382,192.168.0.15:6383,192.168.0.15:6384
#redis
spring.redis.cluster.max-redirects=6
spring.redis.jedis.pool.max-active=80
spring.redis.jedis.pool.max-idle=30
spring.redis.jedis.pool.max-wait=2000s
spring.redis.jedis.pool.min-idle=10

其次就是JedisCluster的配置方式,单机环境下Jedis也有相应的配置,在此不多说。JedisCluster配置如下。

* @author zhoujy * @date 2018年12月19日 @Configuration public class RedisDistributeLockConfig { @Value("${spring.redis.cluster.nodes}") String redisNodes; @Bean //定义分布式锁对象,稍后讲解实现 public RedisDistributeLock redisDistributeLock(JedisCluster jedisCluster){ return new RedisDistributeLock(jedisCluster); @Bean //定义JedisCluster操作bean public JedisCluster jedisCluster(){ return new JedisCluster(pharseHostAnport()); private Set<HostAndPort> pharseHostAnport(){ if (StringUtils.isEmpty(redisNodes)){ throw new RuntimeException("redis nodes can't be null or empty"); String[] hps = redisNodes.split(","); Set<HostAndPort> hostAndPorts = new HashSet<>(); for (String hp : hps) { String[] hap = hp.split(":"); hostAndPorts.add(new HostAndPort(hap[0], Integer.parseInt(hap[1]))); return hostAndPorts;

分布式锁实现

在完成JedisCluster的所需配置之后,可以看看分布式锁的如何实现的

所有代码如下所示。

* JedisCluster + lua脚本实现分布式锁 * @author zhoujy * @date 2018年12月19日 public class RedisDistributeLock { private Logger logger = LoggerFactory.getLogger(RedisDistributeLock.class); private JedisCluster jedisCluster; * lua脚本:判断锁住值是否为当前线程持有,是的话解锁,不是的话解锁失败 private static final String DISTRIBUTE_LOCK_SCRIPT_UNLOCK_VAL = "if" + " redis.call('get', KEYS[1]) == ARGV[1]" + " then" + " return redis.call('del', KEYS[1])" + " else" + " return 0" + " end"; private volatile String unlockSha1 = ""; private static final Long UNLOCK_SUCCESS_CODE = 1L; private static final String LOCK_SUCCESS_CODE = "ok"; public RedisDistributeLock(JedisCluster jedisCluster) { this.jedisCluster = jedisCluster; * 根据loopTryTime循环重试 * @param lockKey 锁key * @param lockVal 锁值,用于解锁校验 * @param expiryTime 锁过期时间 * @param loopTryTime 获取失败时,循环重试获取锁的时长 * @return 是否获得锁 public boolean tryLock(String lockKey, String lockVal, long expiryTime, long loopTryTime){ Long endTime = System.currentTimeMillis() + loopTryTime; while (System.currentTimeMillis() < endTime){ if (tryLock(lockKey, lockVal, expiryTime)){ return true; return false; * 根据loopTryTime循环重试 * @param lockKey 锁key * @param lockVal 锁值,用于解锁校验 * @param expiryTime 锁过期时间 * @param retryTimes 重试次数 * @param setpTime 每次重试间隔 mills * @return 是否获得锁 public boolean tryLock(String lockKey, String lockVal, long expiryTime, int retryTimes, long setpTime){ while (retryTimes > 0){ if (tryLock(lockKey, lockVal, expiryTime)){ return true; retryTimes--; try { Thread.sleep(setpTime); } catch (InterruptedException e) { logger.error("get distribute lock error" +e.getLocalizedMessage()); return false; * 一次尝试,快速失败。不支持重入 * @param lockKey 锁key * @param lockVal 锁值,用于解锁校验 * @param expiryTime 锁过期时间 MILLS * @return 是否获得锁 public boolean tryLock(String lockKey, String lockVal, long expiryTime){ //相比一般的分布式锁,这里把setNx和setExpiry操作合并到一起,jedis保证原子性,避免连个命令之间出现宕机等问题 //这里也可以我们使用lua脚本实现 String result = jedisCluster.set(lockKey, lockVal, "NX", "PX", expiryTime); return LOCK_SUCCESS_CODE.equalsIgnoreCase(result); * 释放分布式锁,释放失败最可能是业务执行时间长于lockKey过期时间,应当结合业务场景调整过期时间 * @param lockKey 锁key * @param lockVal 锁值 * @return 是否释放成功 public boolean tryUnLock(String lockKey, String lockVal){ List<String> keys = new ArrayList<>(); keys.add(lockKey); List<String> argv = new ArrayList<>(); argv.add(lockVal); try { Object result = jedisCluster.evalsha(unlockSha1, keys, argv); return UNLOCK_SUCCESS_CODE.equals(result); }catch (JedisNoScriptException e){ //没有脚本缓存时,重新发送缓存 logger.info("try to store script......"); storeScript(lockKey); Object result = jedisCluster.evalsha(unlockSha1, keys, argv); return UNLOCK_SUCCESS_CODE.equals(result); }catch (Exception e){ e.printStackTrace(); return false; * 由于使用redis集群,因此每个节点都需要各自缓存一份脚本数据 * @param slotKey 用来定位对应的slot的slotKey public void storeScript(String slotKey){ if (StringUtils.isEmpty(unlockSha1) || !jedisCluster.scriptExists(unlockSha1, slotKey)){ //redis支持脚本缓存,返回哈希码,后续可以继续用来调用脚本 unlockSha1 = jedisCluster.scriptLoad(DISTRIBUTE_LOCK_SCRIPT_UNLOCK_VAL, slotKey);

针对上面的代码,逐步分析。

相比一般的redis分布式锁,这里操作jedis的操作方式进行加锁,好处就是Jedis保证set与设置有效期两个操作之间的原子性,避免在set值之后,程序宕机,导致没有设置过期时间,锁就一直被锁住。

这一步操作我们单独使用lua脚本实现也可以,但是幸好jedis已经帮我们进行实现。

* 一次尝试,快速失败。不支持重入 * @param lockKey 锁key * @param lockVal 锁值,用于解锁校验 * @param expiryTime 锁过期时间 MILLS * @return 是否获得锁 public boolean tryLock(String lockKey, String lockVal, long expiryTime){ //相比一般的分布式锁,这里把setNx和setExpiry操作合并到一起,jedis保证原子性,避免连个命令之间出现宕机等问题 //这里也可以我们使用lua脚本实现 //NX表示setNX操作,PX表示过期时间是mills String result = jedisCluster.set(lockKey, lockVal, "NX", "PX", expiryTime); return LOCK_SUCCESS_CODE.equalsIgnoreCase(result);

同时加锁操作也有几个简单的重载实现,分别是重试获取和循环获取锁的重载,根据业务场景适当调整使用。

这里的分布式锁的解锁操作使用lua脚本帮助实现。

我们都知道,分布式锁在解锁时一定需要验证是不是锁的持有者,这种情况下,我们需要进行的操作就有获取key的对应value,然后验证value的值,这个过程,存在一种情况,导致误删别的持有者的锁。分析如下的操作顺序图

上面的操作顺序可能出错的情况就是当lock1尝试释放时,先获取值,判断是否是锁的持有者,如果是,就再发指令删除锁。这个过程可能存在问题就是,lock1在获取值之后,刚好到了有效期了,那么锁可能会在此时被锁竞争者2获得,并且设置锁lock2,然而这时锁竞争者1删除锁的指令刚好重新发送到redis-server,就会误删lock2,导致后续会被其他锁竞争者3获取,发送不可知业务错误。

使用lua脚本的好处就是保证redis指令之间执行的原子性,把get和del执行放在脚本中,保证不会误删别的锁竞争者的锁,假如刚好出现get之后锁值过期,最多就是del操作结果为0,不会出现误删结果。

* 释放分布式锁,释放失败最可能是业务执行时间长于lockKey过期时间,应当结合业务场景调整过期时间 * @param lockKey 锁key * @param lockVal 锁值 * @return 是否释放成功 public boolean tryUnLock(String lockKey, String lockVal){ List<String> keys = new ArrayList<>(); keys.add(lockKey); List<String> argv = new ArrayList<>(); argv.add(lockVal); try { Object result = jedisCluster.evalsha(unlockSha1, keys, argv); return UNLOCK_SUCCESS_CODE.equals(result); }catch (JedisNoScriptException e){ //没有脚本缓存时,重新发送脚本并缓存 logger.info("try to store script......"); storeScript(lockKey); //重试获取 Object result = jedisCluster.evalsha(unlockSha1, keys, argv); return UNLOCK_SUCCESS_CODE.equals(result); }catch (Exception e){ e.printStackTrace(); return false; * lua脚本:判断锁住值是否为当前线程持有,是的话解锁,不是的话解锁失败 private static final String DISTRIBUTE_LOCK_SCRIPT_UNLOCK_VAL = "if" + " redis.call('get', KEYS[1]) == ARGV[1]" + " then" + " return redis.call('del', KEYS[1])" + " else" + " return 0" + " end";

lua脚本缓存

在redis集群中,为了避免重复发送脚本数据浪费网络资源,可以使用script load命令进行脚本数据缓存,并且返回一个哈希码作为脚本的调用句柄,每次调用脚本只需要发送哈希码来调用即可。

127.0.0.1:6381> script load "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"
"e9f69f2beb755be68b5e456ee2ce9aadfbc4ebf4"

上面是在redis-cli中缓存脚本的方式,在程序中,存储lua脚本的方式是如下所示。使用jedis可以很方便就完成脚本缓存,先判断脚本缓存是否存在,不存在就进行脚本数据缓存并且保存哈希码,以备接下来调用脚本。

注意事项:需要注意的是,在redis集群环境下,每个节点都需要进行一份脚本缓存,否则就会出现

NOSCRIPT No matching script. Please use EVAL. 

错误,因此我在程序中加了处理。

* 由于使用redis集群,因此每个节点都需要各自缓存一份脚本数据 * @param slotKey 用来定位对应的slot的slotKey public void storeScript(String slotKey){ if (StringUtils.isEmpty(unlockSha1) || !jedisCluster.scriptExists(unlockSha1, slotKey)){ //redis支持脚本缓存,返回哈希码,后续可以继续用来调用脚本 unlockSha1 = jedisCluster.scriptLoad(DISTRIBUTE_LOCK_SCRIPT_UNLOCK_VAL, slotKey);

slotKey就是我们set值时的key,redis根据crc16函数 计算key应该对应哪一个slot,如果slot所在的redis节点没有缓存脚本数据就会报处NOSCRIPT No matching script. Please use EVAL.异常,因此当捕捉到这个异常时,我们在代码中重新发送脚本数据进行缓存即可。

* 释放分布式锁,释放失败最可能是业务执行时间长于lockKey过期时间,应当结合业务场景调整过期时间 * @param lockKey 锁key * @param lockVal 锁值 * @return 是否释放成功 public boolean tryUnLock(String lockKey, String lockVal){ List<String> keys = new ArrayList<>(); keys.add(lockKey); List<String> argv = new ArrayList<>(); argv.add(lockVal); try { Object result = jedisCluster.evalsha(unlockSha1, keys, argv); return UNLOCK_SUCCESS_CODE.equals(result); }catch (JedisNoScriptException e){ //没有脚本缓存时,重新发送脚本并缓存 //根据lockkey计算slot,在对应redis节点重新缓存一份脚本数据 logger.info("try to store script......"); storeScript(lockKey); //重试获取 Object result = jedisCluster.evalsha(unlockSha1, keys, argv); return UNLOCK_SUCCESS_CODE.equals(result); }catch (Exception e){ e.printStackTrace(); return false;

以上就是redis集群+lua脚本实现分布式锁的方式。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ActivityServiceApplication.class})
@Slf4j
public class ActivityServiceApplicationTests {
    @Resource
    private RedisDistributeLock redisDistributeLock;
    @Test
    public void testRedislock() throws InterruptedException {
        for(int i=0;i < 50;i++){
            int finalI = i;
            new Thread(() ->{
                    if (redisDistributeLock.tryLock("TEST_LOCK_KEY", "TEST_LOCK_VAL_"+ finalI, 1000* 100, 1000*20)){
                        try {
                            log.warn("get lock successfully with lock value:-----" + "TEST_LOCK_VAL_"+ finalI);
                            Thread.sleep(2000);
                            if (!redisDistributeLock.tryUnLock("TEST_LOCK_KEY", "TEST_LOCK_VAL_"+ finalI)){
                                throw new RuntimeException("release lock fail");
                            log.warn("release lock successfully with lock value:-----" + "TEST_LOCK_VAL_"+ finalI);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                    }else {
                        log.warn("get lock fail with lock value:-----" + "TEST_LOCK_VAL_"+ finalI);
            }).start();
        Thread.sleep(1000*1000);

设置50个线程尝试获取分布式锁,每个线程尝试时间为20秒;获取到锁的线程,sleep2秒,然后释放锁。

最终会出现,10个线程能够依次获得锁,40个线程获取锁超时失败。

2018-12-24 15:35:16.462  WARN 42580 --- [      Thread-61] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_47
2018-12-24 15:35:18.710  WARN 42580 --- [      Thread-61] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_47
2018-12-24 15:35:18.711  WARN 42580 --- [      Thread-14] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_0
2018-12-24 15:35:20.788  WARN 42580 --- [      Thread-14] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_0
2018-12-24 15:35:20.789  WARN 42580 --- [      Thread-51] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_37
2018-12-24 15:35:22.831  WARN 42580 --- [      Thread-47] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_33
2018-12-24 15:35:22.831  WARN 42580 --- [      Thread-51] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_37
2018-12-24 15:35:25.177  WARN 42580 --- [      Thread-47] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_33
2018-12-24 15:35:25.177  WARN 42580 --- [      Thread-55] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_41
2018-12-24 15:35:27.227  WARN 42580 --- [      Thread-55] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_41
2018-12-24 15:35:27.228  WARN 42580 --- [      Thread-36] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_22
2018-12-24 15:35:29.586  WARN 42580 --- [      Thread-36] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_22
2018-12-24 15:35:29.587  WARN 42580 --- [      Thread-35] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_21
2018-12-24 15:35:31.609  WARN 42580 --- [      Thread-35] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_21
2018-12-24 15:35:31.610  WARN 42580 --- [      Thread-28] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_14
2018-12-24 15:35:34.071  WARN 42580 --- [      Thread-28] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_14
2018-12-24 15:35:34.071  WARN 42580 --- [      Thread-31] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_17
2018-12-24 15:35:36.089  WARN 42580 --- [      Thread-31] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_17
2018-12-24 15:35:36.089  WARN 42580 --- [      Thread-54] g.learn.ActivityServiceApplicationTests  : get lock successfully with lock value:-----TEST_LOCK_VAL_40
2018-12-24 15:35:36.449  WARN 42580 --- [      Thread-60] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_46
2018-12-24 15:35:36.450  WARN 42580 --- [      Thread-52] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_38
2018-12-24 15:35:36.450  WARN 42580 --- [      Thread-56] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_42
2018-12-24 15:35:36.450  WARN 42580 --- [      Thread-59] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_45
2018-12-24 15:35:36.453  WARN 42580 --- [      Thread-38] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_24
2018-12-24 15:35:36.453  WARN 42580 --- [      Thread-37] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_23
2018-12-24 15:35:36.453  WARN 42580 --- [      Thread-45] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_31
2018-12-24 15:35:36.453  WARN 42580 --- [      Thread-43] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_29
2018-12-24 15:35:36.453  WARN 42580 --- [      Thread-49] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_35
2018-12-24 15:35:36.453  WARN 42580 --- [      Thread-39] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_25
2018-12-24 15:35:36.453  WARN 42580 --- [      Thread-34] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_20
2018-12-24 15:35:36.454  WARN 42580 --- [      Thread-16] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_2
2018-12-24 15:35:36.454  WARN 42580 --- [      Thread-26] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_12
2018-12-24 15:35:36.454  WARN 42580 --- [      Thread-21] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_7
2018-12-24 15:35:36.454  WARN 42580 --- [      Thread-22] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_8
2018-12-24 15:35:36.454  WARN 42580 --- [      Thread-15] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_1
2018-12-24 15:35:36.454  WARN 42580 --- [      Thread-27] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_13
2018-12-24 15:35:36.454  WARN 42580 --- [      Thread-17] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_3
2018-12-24 15:35:36.455  WARN 42580 --- [      Thread-25] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_11
2018-12-24 15:35:36.455  WARN 42580 --- [      Thread-62] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_48
2018-12-24 15:35:36.455  WARN 42580 --- [      Thread-57] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_43
2018-12-24 15:35:36.455  WARN 42580 --- [      Thread-40] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_26
2018-12-24 15:35:36.455  WARN 42580 --- [      Thread-33] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_19
2018-12-24 15:35:36.455  WARN 42580 --- [      Thread-30] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_16
2018-12-24 15:35:36.455  WARN 42580 --- [      Thread-41] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_27
2018-12-24 15:35:36.455  WARN 42580 --- [      Thread-42] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_28
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-48] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_34
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-63] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_49
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-29] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_15
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-32] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_18
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-50] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_36
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-46] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_32
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-19] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_5
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-20] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_6
2018-12-24 15:35:36.456  WARN 42580 --- [      Thread-53] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_39
2018-12-24 15:35:36.457  WARN 42580 --- [      Thread-23] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_9
2018-12-24 15:35:36.457  WARN 42580 --- [      Thread-58] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_44
2018-12-24 15:35:36.457  WARN 42580 --- [      Thread-18] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_4
2018-12-24 15:35:36.457  WARN 42580 --- [      Thread-24] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_10
2018-12-24 15:35:36.457  WARN 42580 --- [      Thread-44] g.learn.ActivityServiceApplicationTests  : get lock fail with lock value:-----TEST_LOCK_VAL_30
2018-12-24 15:35:38.091  WARN 42580 --- [      Thread-54] g.learn.ActivityServiceApplicationTests  : release lock successfully with lock value:-----TEST_LOCK_VAL_40
				不知道大家有没有遇到过jedisCluster.set()方法上锁时出现上锁成功但返回结果并不是OK,具体需求如下:1.跑批量订单,需要对每个订单进行操作。2.其他地方可能操作这些订单。3.为了只有一...
											来自:	 it小小弟的博客
				1,redis集群的配置文件redis.cluster.nodes=192.168.1.102:7000,192.168.1.102:7001,192.168.1.102:7002,192.168.1...
											来自:	 qq_36305027的博客
				Redis实现分布式锁单机模式的Redis分布式锁集群模式的Redis分布式锁RedlockRedis实现分布式锁单机模式的Redis分布式锁优缺点实现比较轻,大多数时候能满足需求;因为是单机单实例部...
											来自:	 Haiyoung
				转载请标明出处。在分布式系统中,经常会出现需要竞争同一资源的情况,本代码基于redis3.0.1+jedis2.7.1实现了分布式锁。redis集群的搭建,请见我的另外一篇文章:《redis3.0.1...
											来自:	 江宁山人的专栏
				一.搭建redis单机本文搭建redis3.0,3.0版本主要增加了rediscluster集群功能。1.下载地址:http://download.redis.io/releases/redis-3....
											来自:	 localhost01
				第一种:使用setnx关键在getShortMessageByRedis方法中packagecom.oppo.baed.ids.service.service.impl;importcom.oppo....
											来自:	 nameIsHG的博客
				redis集群对lua集群的支持有限,阿里的文档描述也比较简单,没有demo,研究了好久才把单例的lua脚本修改成集群版单例模式的lua脚本localstrs={};localresult={};lo...
											来自:	 mushuntaosama的博客
				抢红包的需求分析抢红包的场景有点像秒杀,但是要比秒杀简单点。因为秒杀通常要和库存相关。而抢红包则可以允许有些红包没有被抢到,因为发红包的人不会有损失,没抢完的钱再退回给发红包的人即可。另外像小米这样的...
											来自:	 横云断岭的专栏
				原文链接译者:yy-leo校对:方腾飞(红体标记重点)用Redis构建分布式锁在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。有很多三方库和文章描述如何用Redis实现一个分布式...
											来自:	 weixin_33742618的博客
				好久没写博客了,突然想起来以前看老外博客上redis做分布式锁的想法。实现一个DLM(distributedlockmanager)主要需要考虑一下几个问题:1.lockserver本身需要是高可用的...
											来自:	 load2006的专栏
				Redis+lua实现分布式锁Lua脚本功能是Reids2.6版本的最大亮点,通过内嵌对Lua环境的支持,Redis解决了长久以来不能高效地处理CAS(check-and-set)命令的缺点,并且可以...
											来自:	 sinat_27548257的博客
				1.分布式锁概念:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。场景:分布式情况下(多JVM),线程A和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布...
											来自:	 weixin_34129696的博客
				lua脚本能保证redis的原子性操作,redis使用springboot的redistemplate/***createbyabel*createdate2018/11/1611:28*descri...
											来自:	 u012903200的博客
			搭建了个redis单机小集群,使用sentinel做监控和主从切换,redis实例之间不沟通。 java代码通过客户端分片操作redis集群,并且订阅sentinel主从切换事件(通过jedis),通
				前些天我去面试,面试官问了我一个问题,Redis缓存怎么在高并发情况下保证数据操作的原子性,我当时后懵逼了,于是回来后我就花了点时间想想怎么去完成这个功能.具体怎么实现请接着往下看在看这篇文章的时候希...
											来自:	 浮华饰浮华的博客
				1、问题单机模式下,执行lua脚本没有问题。放到集群执行后,报错ERRErrorrunningscript(calltof_4a610f5543b3c3450220da7bd47825d3b6bffa...
											来自:	 xixingzhe2的博客
				最近项目中需要用到一个分布式的锁,考虑到基于会话节点实现的zookeeper锁性能不够,于是想使用redis来实现一个分布式的锁。看了网上的几个实现方案后,发现都不够严谨。比如这篇:用Redis实现分...
											来自:	 axe的专栏
				1.方法lock(Stringlock,intexpire):获取锁expire,锁的过期时间setnx(),只有当lock不存在时才会赋值,赋值成功返回1,赋值失败返回0publicbooleanl...
											来自:	 GitYang的博客
				Java实现基于Redis的分布式锁 单JVM内同步好办,直接用JDK提供的锁就可以了,但是跨进程同步靠这个肯定是不可能的,这种情况下肯定要借助第三方,我这里实现用Redis,当然还有很多其他的实现方...
											来自:	 莫名的拉风的博客
				分布式锁的解决方式基于数据库表做乐观锁,用于分布式锁。(适用于小并发)使用memcached的add()方法,用于分布式锁。使用memcached的cas()方法,用于分布式锁。(不常用)使用redi...
											来自:	 weixin_33951761的博客
				redis中文网官方案例redis127.0.0.1:6379>eval"return{KEYS[1],KEYS[2],ARGV[1],ARGV[2]}"2key1key2firstsecond1)"...
											来自:	 jing956899449的博客
				        之前2片文章介绍了               spring利用注解实现定时任务:https://blog.csdn.net/QiaoRui_/article/details/8299...
											来自:	 乔瑞的博客
				参考文档 redis分布式锁官方介绍前言多线程并发执行情况下如何保证一个代码块在同一时间只能由同一线程执行(同一个JVM中多线程同步执行)?可以使用线程锁的机制(如synchronized,Reent...
											来自:	 zl_momomo的博客
				redis集群搭建请自行百度已有redis集群如下图:先连接某个实例,设置key,执行如下命令,key中带了hashtag[root@iz2ze8wdyinfuhcncz3me3zsrc]#./red...
											来自:	 EonianGlutton的专栏
				使用jedis执行lua脚本(实现一个对IP的限流)上一篇学习了怎么安装lua,这一篇学习编写一个lua脚本用jedis执行,实现对一个IP的限流LUA脚本如下,第一次使用incr对KEY(某个IP作...
											来自:	 文若书生的专栏
				   连接单机版第一步:创建一个Jedis对象。需要指定服务端的ip及端口。第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。第三步:打印结果。第四步:关闭Jedis@Testpu...
											来自:	 ycmnzmm的博客
				版本说明jedis2.9.0redis3.2.5这里只是几个简单的demo,直接上代码吧,没啥好说的importorg.apache.commons.pool2.impl.GenericObjectP...
											来自:	 刘本龙的专栏
				redis作为一个缓存数据库,在绝大多数java项目开发中是必须使用的,在web项目中,直接配合spring-redis,各种配置都直接在spring配置文件中做了,一般都是使用redis连接池。在非...
											来自:	 feinifi的博客
				分布式锁的应用场景当多个机器(多个进程)会对同一条数据进行修改时,并且要求这个修改是原子性的。这里有两个限定:多个进程之间的竞争,意味着JDK自带的锁失效;原子性修改,意味着数据是有状态的,修改前后有...
											来自:	 不能说的秘密的博客
				RedisJedis、jedisCluster的使用1、Jedis客户端https://redis.io/clients2、Jedis源码包与使用介绍https://github.com/xetort...
											来自:	 徐小冠
				RedisCluster集群主从方案(附JedisCluster教程)本文介绍一种通过Jedis和Cluster实现Redis集群(主从)的高可用方案,该方案需要使用Jedis2.8.0(推荐),Re...
											来自:	 永远的VC的专栏
				https://my.oschina.net/u/2263956/blog/799016  摘要: Redis服务器的部署方式可分为单机和集群的方式,使用Jedis的对应访问接口也相应不用。如何使用J...
											来自:	 haiyang4988的博客
				Java客户端Jedis 这里只讲Jedis常规用法和五种数据结构的方法(关于集群的搭建以后再写)     2.稍微修饰下  3.运行效果4.相应的jar包(第一个不兼容,没用,junit4.4:@t...
											来自:	 IronStrong的博客
				jedis操作lua脚本测试Java代码收藏代码importstaticorg.hamcrest.CoreMatchers.equalTo;importjava.util.ArrayList;impo...
											来自:	 weixin_34221332的博客
			If SETNX returns 1 the client acquired the lock, setting the lock.foo key to the Unix time at which
				在分布式场景下,有很多种情况都需要实现最终一致性。在设计远程上下文的领域事件的时候,为了保证最终一致性,在通过领域事件进行通讯的方式中,可以共享存储(领域模型和消息的持久化数据源),或者做全局XA事务...
											来自:	 云深不知处
				 redis集群配置:在使用spring的RedisTemplate执行lua脚本时,报错EvalShaisnotsupportedinclusterenvironment,不支持cluster。代码...
											来自:	 u012899746的博客
				Lua是一个小巧的脚本语言。是巴西里约热内卢天主教大学(PontificalCatholicUniversityofRiodeJaneiro)里的一个研究小组,由RobertoIerusalimsch...
											来自:	 iteye_6945的博客
				这个问题是在Redis集群下才会发生的。在Redis集群版实例中,事务、脚本等命令要求所有的key必须在同一个slot中,如果不在同一个slot中将返回以下错误信息(commandkeysmustin...
											来自:	 AAA821的专栏
				背景我们大家都知道,在一个电商系统里面,库存是一个很敏感的系统组成部分。这是因为在这一点上,我们的程序执行模型必须在一个点上做出改变,那便是从并行执行模型到串行执行模型的切换。因我们的某一个商品的库存...
											来自:	 zhang6622056的专栏
				在腾讯云服务器上面通过定时任务使用redis(云redis2.8主从版)的EVAL执行一段lua脚本然后神奇的一幕出现了,如下图:时而正常,时而报:ERRunknowncommand’EVAL’神助攻...
											来自:	 阿飞的博客
				从redis2.6.0版本开始,redis内置了Lua解释器,并提供了eval命令来解析Lua脚本求值。1.语法格式语法:evalscriptnumkeyskeysargs参数:eval—redis提...
											来自:	 sym542569199的博客
				项目地址:https://github.com/HouChenggong/springboot_redis_transaction.gitimportcom.pf.org.cms.manage.Red...
											来自:	 胃病的不良少彦
				java结合redis+lua获取数据单机版注意:redis+lua不支持集群环境packagebhz.redis01;importorg.apache.commons.pool2.impl.Gene...
											来自:	 nameIsHG的博客
				有时我们需要在特定时间执行特定的任务,然而一般的定时任务又不满足我们的需求。如重推任务:我们向第三方发送话单,但是有可能推送失败,此时我们需要隔一段时间再重推。重推N次后,仍然失败,则不重推,标志无法...
											来自:	 不积跬步无以至千里; 不积小流无以成江海