0%

SpringBoot-Redison

Redisson

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。

代码演示

RedLock

Redlock 算法的基本思路,是让客户端和多个独立的 Redis 实例依次请求加锁,如果客户端能够和半数以上的实例成功地完成加锁操作,就认为客户端成功地获得分布式锁了,否则加锁失败。即使有单个 Redis 实例发生故障,因为锁变量在其它实例上也有保存,所以,客户端仍然可以正常地进行锁操作,锁变量并不会丢失。

  • 操作流程
  1. 客户端获取当前时间

  2. 客户端按照N个Redis实例执行加锁操作

    • 加锁操作和在单实例上执行的加锁操作一样,使用 SET 命令,带上 NX,EX/PX 选项,以及带上客户端的唯一标识。还有一个超时时间。如果在某一个Redis实例上加锁失败,会直接在下一个实例上执行。加锁操作的超时时间需要远远地小于锁的有效时间,一般也就是设置为几十毫秒。

  3. 客户端完成了和所有 Redis 实例的加锁操作,客户端就要计算整个加锁过程的总耗时。

    • 当客户端加锁操作满足,以下条件才算成功。
      1. 客户端从超过半数(大于等于 N/2+1)的 Redis 实例上成功获取到了锁;
      2. 客户端获取锁的总耗时没有超过锁的有效时间。
  4. 客户端释放锁

    • 释放掉锁执行lua脚本即可。

Redisson实现RedLock

  • Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。

Redis主从版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* @author z201.coding@gmail.com
**/
@Configuration
public class RedisConfig {

@Bean
public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
return new RedissonConnectionFactory(redisson);
}

@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// key序列化方式
redisTemplate.setKeySerializer(redisSerializer);
// value序列化
redisTemplate.setValueSerializer(redisSerializer);
// value hashmap序列化
redisTemplate.setHashValueSerializer(redisSerializer);
return redisTemplate;
}

@Bean
public RedissonClient redissonClient() throws IOException {
Config config = new Config();
// 主从
config.useMasterSlaveServers()
//可以用"rediss://"来启用SSL连接
.setMasterAddress("redis://127.0.0.1:6379").setPassword("redis_pwd")
.addSlaveAddress("redis://127.0.0.1:6380","redis://127.0.0.1:6381").setPassword("redis_pwd")
.setRetryInterval(5000)
.setTimeout(10000)
.setConnectTimeout(10000);//(连接超时,单位:毫秒 默认值:3000);
return Redisson.create(config);
}
}

  • 单元测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Slf4j
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = AppApplication.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AppApplicationTest {

@Autowired
private RedissonClient redissonClient;

private static final String LOCK_TITLE = "redisLock_";

@Test
@Disabled
void contextLoads() throws InterruptedException {
int count = 10;
CountDownLatch countDownLatch = new CountDownLatch(count);
ExecutorService executorService = Executors.newFixedThreadPool(count);
String key = UUID.randomUUID().toString();
String lockKey = LOCK_TITLE + key;
for (int i = 0; i < count; i++) {
executorService.execute(() -> {
try {
RLock lock = redissonClient.getLock(lockKey);
//加锁,并且设置锁过期时间,防止死锁的产生
Boolean result = lock.tryLock(2, TimeUnit.MINUTES);
log.info(" {} lock {}", result, lockKey);
Thread.sleep(1000L);
//执行具体业务逻辑
redissonClient.getBucket("value").set(String.valueOf(System.currentTimeMillis()));
String value = (String) redissonClient.getBucket("value").get();
log.info(" {} value {}", Thread.currentThread().getName(), value);
} catch (Exception e) {
log.error("{}", e.getMessage());
} finally {
//获取所对象
RLock lock = redissonClient.getLock(lockKey);
//释放锁(解锁)
lock.unlock();
log.info(" {} unlock {}", Thread.currentThread().getName(), lockKey);
}
countDownLatch.countDown();
});
}
countDownLatch.countDown();
executorService.shutdown();
;
log.info("run end~~~");
Thread.sleep(11000L);
}
}

END