spring-boot-distributed-lock-starter
多种分布式锁的实现与spring-boot-starter封装
 共提供四种类型分布式锁:
- redis-expire: setNx与设置key的过期时间并通过随机uuid标记上锁人
- redis-get-set: setNx与getSet并设置当前时间戳来保证上锁与解锁
- red-lock: redisson红锁的再封装
- zookeeper: 顺序临时节点的公平锁实现
以上锁实现均可重入并提供了注解的aop支持。
required
- JDK 8+
- Maven or Gradle
- Spring boot
feature
- 实现的四种锁均支持可重入
- 单节点redis锁的实现较健壮,保证资源隔离
- zk锁的顺序支持
- 注解式的锁与编程性锁
- 提供自定义锁拓展点(自定义实现DLockFactory)
todo
- 单节点redis锁的续约
- 对于打到同一个服务的资源锁是否可以实现支持锁的降级策略
- 对于redis的sleep自旋的优化
install
Maven:
    <dependency>
        <groupId>com.github.lattice-boot.common</groupId>
        <artifactId>spring-boot-distributed-lock-starter</artifactId>
        <version>0.1.6-RELEASE</version>
    </dependency> 
Gradle:
    compile group: 'com.github.lattice-boot.common', name: 'spring-boot-distributed-lock-starter', version: '0.1.6-RELEASE'
config
以下均已yaml配置文件为实例
redis-expire/redis-get-set
locker:
  type: redis-expire # or redis-get-set
  redis:
    mode: single # single\cluster\sentinel @see com.noir.common.lock.properties.RedisDLockProperties
    single:
      address: xxxxxx
      conn-timeout: 300000
    pool:
      size: 10
      minIdle: 1 
redlock
locker:
  type: red-lock
  clients:
    - redis:
          mode: single # single\cluster\sentinel @see com.noir.common.lock.properties.RedisDLockProperties
          single:
            address: xxxxxx
            conn-timeout: 300000
          pool:
            size: 10
            minIdle: 1
    - redis:
              mode: single # single\cluster\sentinel @see com.noir.common.lock.properties.RedisDLockProperties
              single:
                address: xxxxxx
                conn-timeout: 300000
              pool:
                size: 10
                minIdle: 1
    - redis:
              mode: single # single\cluster\sentinel @see com.noir.common.lock.properties.RedisDLockProperties
              single:
                address: xxxxxx
                conn-timeout: 300000
              pool:
                size: 10
                minIdle: 1
    - redis:
              mode: single # single\cluster\sentinel @see com.noir.common.lock.properties.RedisDLockProperties
              single:
                address: xxxxxx
                conn-timeout: 300000
              pool:
                size: 10
                minIdle: 1 
zookeeper
locker:
  type: zookeeper
  zookeeper:
    address: xxx # Multiple support like: xx.xx.xx.xx,yy.yy.yy.yy,zz.zz.zz.zz
    timeout: 30000 
use
可以简单的通过注解上锁(支持元注解并使用alias annotation)
@Dlock("lock_#{#accountId}")
public void changeAccount(Long accountId) {
    ...
} 
通过LockFactory
@Autowired
private DLockFactory lockFactory;
public void changeAccount(Long accountId) {
    Lock lock = lockFactory.getLock("lock_" + accountId.toString(), 30, TimeUnit.SECONDS);
    
    try {
        lock.lock(); // or tryLock
        ...
    }
    finally {
        lock.unlock(); // 此处可能因为超过租期抛出LockExpiredException
    }
} 
需要注意的是,使用redis单点锁的两种方式都可能因为超过租期抛出LockExpiredException,通常我们应该使业务回滚,如果使用编程事务记得抓一下unlock
通过LockableService
@Autowired
private LockableService lockableService;
public void changeAccount(Long accountId) {
    lockableService.lockAndExecute("lock_" + accountId.toString(), () -> {
        ...
        return xxx; // or not return
    });
} 
以上方式上的锁均可重入。
 JarCasting
 JarCasting