对于分布式服务的情况下,当只使用java原生相关锁(ReentrantLock)操作时,只能保证一个jvm进程中的操作受到锁的保护,但对于多个jvm进程就无法进行有效锁保护控制;
因此为了满足分布式场景, 需要使用一个统一管理位置,因此通过redis 来做作为锁控制
spring 提供的redis支持
https://docs.spring.io/spring-integration/reference/html/redis.html#redis-lock-registry
其利用java 本地锁和 redis SET相关指令 双重保证
引入相关组件
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-integration</artifactId> </dependency> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
在application.yml中添加redis的配置
spring: redis: host: localhost # Redis服务器地址 database: 0 # Redis数据库索引(默认为0) port: 6379 # Redis服务器连接端口 password: # Redis服务器连接密码(默认为空)
建立配置类,注入RedisLockRegistry
@Configuration public class RedisLockConfiguration { @Bean public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) { return new RedisLockRegistry(redisConnectionFactory, "redis-lock"); } }
@RestController @Api(tags = "RedisLockRegistryController") @RequestMapping("/redisLockRegistry") @Slf4j public class RedisLockRegistryController { @Resource private RedisLockRegistry redisLockRegistry; @ApiOperation("加锁") @GetMapping(value = "/tryGetDistributedLock") public void tryGetDistributedLock(@RequestParam String key, @RequestParam String value) { Lock lock = redisLockRegistry.obtain("redis"); try { //尝试在指定时间内加锁,如果已经有其他锁锁住,获取当前线程不能加锁,则返回false,加锁失败;加锁成功则返回true if (lock.tryLock(3, TimeUnit.SECONDS)) { log.info("lock is ready"); TimeUnit.SECONDS.sleep(5); } } catch (InterruptedException e) { log.error("obtain lock error", e); } finally { lock.unlock(); } } }
测试 启动多个实例,分别访问/lock/redis
端点,一个正常秩序业务逻辑,另外一个实例访问出现如下错误,说明第二个实例没有拿到锁,证明了分布式锁的存在。