MySQL 기반 분산 락 구현 가이드

MySQL 데이터베이스를 활용한 분산 락(Distributed Lock)은 멀티 인스턴스 환경에서 스케줄링 작업이 중복 실행되지 않도록 보장하는 효과적인 방법이다.

락 테이블 생성

CREATE TABLE app_lock (
    resource_name VARCHAR(64) PRIMARY KEY,
    locked_by VARCHAR(64),
    locked_at DATETIME,
    expires_at DATETIME
);

락 획득

락을 획득할 때는 app_lock 테이블에 레코드를 삽입한다. 삽입 성공 시 락 획득, 실패 시 다른 인스턴스가 점유 중임을 의미한다. 다음은 락 획득을 위한 SQL 예제다:

INSERT INTO app_lock (resource_name, locked_by, locked_at, expires_at)
VALUES ('my_resource', 'node_001', NOW(), DATE_ADD(NOW(), INTERVAL 15 SECOND))
ON DUPLICATE KEY UPDATE 
    locked_by = VALUES(locked_by), 
    locked_at = VALUES(locked_at), 
    expires_at = VALUES(expires_at)
WHERE expires_at < NOW();

락 해제

락 해제는 해당 레코드를 삭제하거나 만료 시간을 갱신하는 방식으로 처리한다. 간단한 삭제 예제:

DELETE FROM app_lock WHERE resource_name = 'my_resource';

스케줄러 작업 로직

스케줄러에서는 먼저 락 획득을 시도하고, 성공 시 작업을 수행한 뒤 반드시 락을 해제한다.

@Scheduled(cron = "0 0/5 * * * ?")
public void processScheduledJob() {
    boolean isLockAcquired = tryAcquireLock("my_resource", "node_001");

    if (isLockAcquired) {
        try {
            // 비즈니스 로직 실행
        } finally {
            releaseLock("my_resource");
        }
    }
    // 락 획득 실패 시 작업 스킵
}

구현 상세

다음은 락 획득 및 해제를 위한 메서드 구현 예시다:

public boolean tryAcquireLock(String resourceName, String nodeId) {
    String sql = "INSERT INTO app_lock (resource_name, locked_by, locked_at, expires_at) " +
                 "VALUES (?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 15 SECOND)) " +
                 "ON DUPLICATE KEY UPDATE locked_by = VALUES(locked_by), " +
                 "locked_at = VALUES(locked_at), expires_at = VALUES(expires_at) " +
                 "WHERE expires_at < NOW()";
    int affected = jdbcTemplate.update(sql, resourceName, nodeId);
    return affected > 0;
}

public void releaseLock(String resourceName) {
    String sql = "DELETE FROM app_lock WHERE resource_name = ?";
    jdbcTemplate.update(sql, resourceName);
}

락 만료 메커니즘

락 획득 시 만료 시간(예: 15초)을 설정하여, 인스턴스 장애 시에도 다른 인스턴스가 일정 시간 후 락을 재획득할 수 있도록 한다.

주의사항

  • 스케줄러 작업의 실행 시간이 락 만료 시간을 초과하지 않도록 주의한다.
  • 만료되었으나 해제되지 않은 락 레코드를 주기적으로 정리하여 테이블 데이터 증가를 방지한다.

태그: MySQL Distributed Lock Database Lock Scheduled Task Concurrency Control

6월 24일 23:47에 게시됨