Backend—— "Utilice el bloqueo distribuido de redis para resolver el problema de la ejecución repetida de tareas de tiempo en un entorno de clúster

En un entorno de clúster, las tareas de sincronización de operaciones no idempotentes generalmente solo se pueden ejecutar una vez. Pero el programa se distribuye en cada servidor y se ejecuta. En este momento, el bloqueo distribuido de redis se puede utilizar para garantizar que la tarea de temporización solo se pueda ejecutar una vez. La siguiente es una demostración:

 Inicié dos programas localmente, cada uno de los cuales contiene una tarea de sincronización con exactamente el mismo contenido para simular un entorno distribuido.

Se puede ver que con una frecuencia de una ronda por minuto, se puede ver que solo se ejecuta un programa para cada ronda de tareas de cronometraje.

La lógica específica es agregar operaciones para determinar si se debe ejecutar la lógica empresarial en la tarea de sincronización. El criterio para este juicio se logra mediante la tecla redis +:

Antes de que se ejecute la lógica empresarial, el método setIfAbsent se utiliza para determinar si hay una clave en redis. Si no hay una clave, la clave se establece. Si la configuración tiene éxito, devuelve verdadero. En este momento, la clave está en un estado desbloqueado, y si contiene una clave, devuelve falso.

El código de la tarea de cronometraje es el siguiente:

import com.baoji.service.DistributeLocker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.ParseException;

/**
 * Created by dearx on 2021/01/21.
 */
@Component
public class TestGenerater1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestGenerater1.class);

    @Autowired
    private DistributeLocker distributeLocker;

    //每隔1分钟执行一次
    @Scheduled(cron = "0 */1 * * * ?")
    private void configureTasks() throws ParseException {
        boolean locked = distributeLocker.lock("test-DingShiRengWu", distributeLocker.LOCK_TIME_ONE_HOUR);
        if(!locked){
            LOGGER.info("定时任务aaa已经被执行");
            distributeLocker.unlock("test-DingShiRengWu");
        }else{
            LOGGER.info("定时任务aaa开始执行");
            distributeLocker.lock("test-DingShiRengWu");
            try {
                Thread.currentThread().sleep(5000);
                /*业务逻辑处理*/
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            distributeLocker.unlock("test-DingShiRengWu");
            LOGGER.info("定时任务aaa执行完毕");
        }
        LOGGER.info("----------------这一轮执行结束,开始下一轮-------------");
    }

}

El código relacionado con redis es el siguiente:

import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;


@Component
public class DistributeLocker {

  private static final Logger LOGGER = LoggerFactory.getLogger(DistributeLocker.class);

  private static final String LOCK = "TRUE";

  private static final long DEFAULT_LOCK_TIME = 60000L;
  
  public static final long LOCK_TIME_ONE_HOUR = 60 * 60000L;

  public static final long LOCK_TIME_HALF_HOUR = 30 * 60000L;

  public static final long LOCK_TIME_FIVE_MINS = 5 * 60000L;
  
  @Autowired
  private RedisTemplate<String, String> stringRedisTemplate;

  /**
   * lock the operation with the default time, the default lock time is 60 seconds
   * @param key the given key
   * @return
   */
  public boolean lock(String key) {
    return lock(key, DEFAULT_LOCK_TIME);
  }
  
  /**
   * lock the operation with the given key
   * @param key the given key
   * @param lockTime unit is milliseconds, the lock time should greater than estimated operation time
   * @return true if lock success
   */
  public boolean lock(String key, long lockTime) {
    BoundValueOperations<String, String> operations = stringRedisTemplate.boundValueOps(key);
    boolean lockSuccess = operations.setIfAbsent(LOCK);
    if(lockSuccess) {
      operations.expire(lockTime, TimeUnit.MILLISECONDS);
    }

    return lockSuccess;

//    RedisConnection connection = null;
//    try {
//      connection = stringRedisTemplate.getConnectionFactory().getConnection();
//      lockSuccess = connection.setNX(key.getBytes(Charset.forName("UTF-8")), LOCK.getBytes(Charset.forName("UTF-8")));
//      if(lockSuccess) {
//        connection.expire(key.getBytes(Charset.forName("UTF-8")), lockTime);
//      }
//    } finally {
//      connection.close();
//    }
  }

  /**
   * unlock the operation with the given key
   * @param key
   */
  public void unlock(String key) {
    stringRedisTemplate.delete(key);
  }

}

 

Supongo que te gusta

Origin blog.csdn.net/nienianzhi1744/article/details/112994335
Recomendado
Clasificación