Bloqueio Distribuído com Redisson no Spring Boot

Configuração Inicial do Projeto

Para implementar bolqueio distribuído em uma aplicação Spring Boot, utilize a biblioteca Redisson. Adicione a dependência correspondente ao seu arquivo pom.xml:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.5</version>
</dependency>

Configure a conexão com o cluster Redis no arquivo application.yml:

spring:
  redis:
    cluster:
      nodes: cache-server1:7000,cache-server2:7001,cache-server3:7002
    password: senha_segura123

Implementação do Serviço de Bloqueio

Crie um serviço dedicado para gerenciar bloqueios. Esta abordagem encapsula a lógica de aquisição e liberação de bloqueios.

package com.example.distributed.service;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;

@Service
public class ResourceLockService {

    private final RedissonClient redissonClient;

    public ResourceLockService(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    public boolean acquireLockWithTimeout(String resourceIdentifier, long timeoutSeconds) {
        RLock lockHandle = redissonClient.getLock(resourceIdentifier);
        try {
            return lockHandle.tryLock(timeoutSeconds, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    public void releaseLock(String resourceIdentifier) {
        RLock lockHandle = redissonClient.getLock(resourceIdentifier);
        if (lockHandle != null && lockHandle.isHeldByCurrentThread()) {
            lockHandle.unlock();
        }
    }

    public void executeProtectedOperation(String resourceId, Runnable operation) {
        RLock lock = redissonClient.getLock(resourceId);
        lock.lock();
        try {
            operation.run();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}

Exemplo de Uso no Controlador

Demonstre a utilização do bloqueio em um cenário concorrente:

package com.example.distributed.controller;

import com.example.distributed.service.ResourceLockService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DataProcessorController {

    private final ResourceLockService lockService;

    public DataProcessorController(ResourceLockService lockService) {
        this.lockService = lockService;
    }

    @PostMapping("/process-data")
    public String processData() {
        String lockKey = "data:processing:task-001";
        
        for (int i = 0; i < 3; i++) {
            new Thread(() -> performTask(lockKey)).start();
        }
        return "Tasks submitted";
    }

    private void performTask(String lockKey) {
        boolean acquired = lockService.acquireLockWithTimeout(lockKey, 30);
        if (!acquired) {
            System.out.println("Failed to acquire lock - exiting");
            return;
        }
        
        try {
            System.out.println(Thread.currentThread().getName() + " started processing");
            Thread.sleep(8000);
            System.out.println(Thread.currentThread().getName() + " completed processing");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lockService.releaseLock(lockKey);
        }
    }
}

Diretrizes para Implementação Segura

  • Especificidade das chaves: Use identificadores únicos para cada recurso protegido, como order:creation:4567, em vez de chaves genéricas.
  • Prevenção de erros: Verifique sempre se a thread atual é proprietária do bloqueio antes de liberá-lo, evitando exceções de monitoramanto ilegal.
  • Gerenciamento de tempo: Defina tempos de espera adequados para evitar bloqueios indefinidos e timeouts excessivos.
  • Recuperação de falhas: Implemente tratamento adequado para interrupções de thread durante a espera do bloqueio.

Tags: spring-boot Redis Redisson distributed-lock java

Publicado em 7-9 03:54