30 Ağustos 2022 Salı

SpringIntegration Redis RedisLockRegistry Sınıfı

Giriş
Açıklaması şöyle. Kilidi @RedisLockable ile otomatik bırakmak yerine kodla bırakmak için kullanılabilir
To release the lock early, you can use the LockRegistry interface provided by Spring Integration. You can inject the LockRegistry bean and obtain a lock on the same key used by the @RedisLockable annotation.
constructor - RedisConnectionFactory + registryKey
Örnek
Şöyle yaparız
private static final String LOCK_NAME = "lock";

@Bean(destroyMethod = "destroy")
public RedisLockRegistry redisLockRegistry(
  RedisConnectionFactory redisConnectionFactory) {
    return new RedisLockRegistry(redisConnectionFactory, LOCK_NAME);
}
constructor - RedisConnectionFactory + registryKey + expireAfter
Açıklaması şöyle
When creating a RedisLockRegistry instance, you need to provide three parameters: `connectionFactory`, `registryKey`, and `expireAfter`.

The `connectionFactory` parameter is used to generate the redisTemplate instance field within the RedisLockRegistry. This redisTemplate facilitates interaction with Redis using string values.

The `registryKey` parameter serves as a prefix for key names. These key names are formed by combining the `registryKey` and the key’s specific value, separated by a colon. For example, if `registryKey` is set to “Spring” and you intend to lock a key with the value “Integration”, the actual key used to communicate with Redis would be “Spring:Integration”.

The `expireAfter` parameter, of type long, determines the Time To Live (TTL) for the lock status data inserted into Redis by RedisLock instances.
Örnek
Şöyle yaparız
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.integration.support.locks.ExpirableLockRegistry;

@Configuration
public class RedisDistributedLockConfiguration {
    private static final String LOCK_REGISTRY_REDIS_KEY = "MY_REDIS_KEY";
    private static final Duration RELEASE_TIME_DURATION = Duration.ofSeconds(30);

  @Bean(LOCK_REGISTRY_BEAN)
  public ExpirableLockRegistry lockRegistry(RedisConnectionFactory redisConnectionFactory){
    RedisLockRegistry redisLockRegistry =
      new RedisLockRegistry(redisConnectionFactory, LOCK_REGISTRY_REDIS_KEY,
        RELEASE_TIME_DURATION.toMillis());
      return redisLockRegistry;
  }
}
expireUnusedOlderThan metodu
Açıklaması şöyle
In some situations, you might need to acquire a lock but not release it. For example, you have a @Scheduled task that runs each 15 seconds on each instance and you don’t want it to be run more often than once per 15 seconds.
To do it you can get a lock and exit from a method without releasing. In such cases, I suggest calling lockRegistry.expireUnusedOlderThan(TTL) each time before obtaining a lock (actually it is better to call it for all cases). This method removes old not released locks from the map locks and prevents the situation when one instance has a map with old locks and all threads of this instance (except the one which acquired this lock) cannot acquire it.
obtain metodu
Açıklaması şöyle
Each object LockRegistry has a random id of type UUID and contains a map of locks (lock name / lock object) that are called locks and that are held by the current instance. When we do lockRegistry.obtain(lockKey), lockRegistry first checks if the map contains this lock (in other words, if the current instance has the lock with the same name acquired at this moment), if so then this lock is returned. Otherwise, lockRegistry checks if Redis contains the key with the name “registry key:lock name” and if the value equals the id of the lockRegistry object. If so, it returns this lock, else it tries to create the key “registry key:lock name” in Redis. When you got a lock and call lock.tryLock() basically the similar steps are performed as in lockRegistry.obtain(lockKey), first the map locks with locks is checked, then Redis.
Şöyle yaparız
import org.springframework.integration.support.locks.ExpirableLockRegistry;

@Slf4j
@Component
public class LockService implements ILockService {

  @Qualifier(LOCK_REGISTRY_BEAN)
  @Autowired
  private ExpirableLockRegistry lockRegistry;

  @Override
  public boolean update(UpdateRequest request) {
    Lock lock = lockRegistry.obtain(request.getId());
    boolean success = lock.tryLock();

    if (!success) {
      return false;
    }
        
    // ...
    // update a shared resource  
    // ... 
        
    lock.unlock();
    return true;
  }
}
Örnek
Şöyle yaparız
@Service
public class MyService {

  @Autowired
  private RedisLockRegistry redisLockRegistry;

  @RedisLockable(key = "my-lock-key", leaseTime = 60_000, waitTime = 5_000)
  public void doSomethingWithLock() throws InterruptedException {
    Lock lock = redisLockRegistry.obtain("my-lock-key");
    try {
      // Do something with the lock
    } finally {
       lock.unlock();
    }
  }
}
setRedisLockType metodu
Açıklaması şöyle
... there can be configured 2 types of locks (both Reentrant ones)
- RedisLockType.SPIN_LOCK - the lock is acquired by periodic loop (100ms) checking whether the lock can be acquired. Default.
- RedisLockType.PUB_SUB_LOCK - The lock is acquired by redis pub-sub subscription.

The pub-sub is preferred mode — less network chatter between client Redis server, and more performant — the lock is acquired immediately when subscription is notified about unlocking in the other process. However, the Redis does not support pub-sub in the Master/Replica connections (for example in AWS ElastiCache environment), therefore a busy-spin mode is chosen as a default to make the registry working in any environment.



Hiç yorum yok:

Yorum Gönder