728x90

스프링 배치를 사용하여 시간 기반 트리거로 특정 조건(읽지 않은 알림이 일주일 지난 경우 다시 알림 발송)을 구현했을 때 다중 인스턴스 환경에서는 인스턴스마다 배치 작업이 중복 실행되는 문제가 발생할 수 있다. 그 외로 스프링 배치 관련해서 어떤 질문이 나올지 정리할려고 한다.

 

 

 

 

예상 질문 1: "인스턴스가 두 대 이상일 때, 알림이 중복 발송되는 문제를 어떻게 해결할 수 있나요?"

 

답변:

"스프링 배치에서 다중 인스턴스 환경에서 중복 작업이 발생하지 않도록 하기 위해서는 배치 작업의 동시성 제어가 필요합니다. 이 문제를 해결하기 위해 다음과 같은 방법을 사용할 수 있습니다.

  1. Spring Batch의 JobInstance 및 JobExecution을 활용한 중복 방지: 스프링 배치는 기본적으로 JobInstance라는 개념을 사용하여 동일한 파라미터로 실행된 배치 작업이 여러 번 실행되지 않도록 방지합니다. 이를 통해 동일한 작업이 두 인스턴스에서 동시에 실행되지 않도록 제어할 수 있습니다. 특정 배치 작업에 고유한 ID나 파라미터를 부여하여 같은 작업이 중복 실행되지 않도록 처리할 수 있습니다.
  2. 쿼츠 스케줄러(Quartz Scheduler)를 사용한 클러스터 환경 지원: 클러스터링된 환경에서 배치 작업이 중복 실행되지 않도록 Quartz Scheduler를 사용할 수 있습니다. 쿼츠 스케줄러는 분산된 여러 인스턴스에서 하나의 작업만 실행되도록 스케줄링을 관리할 수 있는 기능을 제공합니다. 이를 통해 각 인스턴스가 스케줄링된 작업의 소유권을 체크하고, 작업을 중복 실행하지 않도록 보장할 수 있습니다.
  3. DB를 활용한 분산 락(Distributed Lock): 배치 작업이 실행되기 전에 데이터베이스를 활용하여 분산 락(Distributed Lock)을 구현할 수 있습니다. 락을 획득한 인스턴스만 배치 작업을 실행하게 하고, 나머지 인스턴스는 작업을 대기하거나 실행하지 않도록 처리할 수 있습니다. Redis와 같은 캐시 서버의 락 기능을 활용해 배치 트리거를 하나의 인스턴스에서만 실행할 수 있도록 구현할 수 있습니다."

=> 분산락이 제일 많이 사용되는 방

 

예상 질문 2: "분산 락을 사용하는 방법은 무엇인가요?"

 

답변:

 

분산 락(Distributed Lock)은 여러 대의 서버나 인스턴스가 동시에 동일한 자원에 접근할 때 하나의 인스턴스만 자원에 접근할 수 있도록 제어하는 메커니즘이다. 분산 시스템에서 여러 서버나 인스턴스가 동일한 작업을 중복해서 수행하지 않도록 하는 것이 목적이다.

서버 A와 서버 B가 동시에 동일한 데이터베이스 테이블을 갱신하려고 하면 충돌이나 데이터 불일치가 발생할 수 있습니다. 이때 분산 락을 통해 한 번에 하나의 서버만 해당 테이블을 갱신할 수 있도록 제어하는 것이다.

 

분산 락의 주요 개념

  1. 락 획득: 특정 자원을 사용하기 전에 인스턴스가 락을 먼저 획득해야 한다. 락을 획득한 인스턴스는 해당 자원에 대해 독점적으로 작업할 수 있다.
  2. 락 해제: 작업이 완료되면 락을 해제하여 다른 인스턴스가 자원에 접근할 수 있도록 한다.
  3. TTL(Time To Live): 락이 너무 오래 걸리거나, 시스템 오류로 인해 락이 해제되지 않을 경우를 대비해 일정 시간이 지나면 자동으로 락을 해제하는 방식이다.

Redis를 사용한 분산 락 예시

  1. setnx 명령: Redis의 setnx(Set if Not Exists) 명령은 주어진 키가 존재하지 않을 때만 값을 설정하는 명령이다. 이를 통해 하나의 인스턴스만 특정 키에 락을 설정할 수 있게 된다.
  2. TTL 설정: 만약 배치 작업이 실패하거나 예기치 못한 오류가 발생할 경우 락이 계속 유지되는 것을 방지하기 위해 TTL을 설정하여 자동으로 락이 해제되도록 한다.
  3. 락 해제: 작업이 완료되면 해당 키를 삭제하여 락을 해제한다.

분산 락이 필요한 이유

분산 환경에서 여러 인스턴스가 동일한 자원에 동시에 접근하게 되면 데이터 일관성 문제가 발생하거나 작업이 중복으로 실행될 수 있다. 분산 락은 이를 방지하고 자원을 안전하게 제어하여 시스템의 안정성을 높이는 데 중요하다.

이러한 락을 잘못 관리하면 데드락(Deadlock) 같은 문제가 생길 수 있으므로 락의 적절한 관리가 필요하다.


"분산 락을 사용하여 여러 인스턴스에서 배치 작업이 중복되지 않게 제어하는 방법은 보통 데이터베이스Redis와 같은 캐시 시스템을 활용하는 방식입니다. 그 중 하나인 Redis를 사용한 분산 락 예를 들면:

배치 작업을 실행할 때 Redis의 setnx 명령을 사용하여 락을 생성합니다. 이 락은 하나의 인스턴스만 획득할 수 있으며, 다른 인스턴스들은 이 락을 획득하지 못하게 됩니다.

락을 획득한 인스턴스가 배치 작업을 실행하고, 작업이 끝나면 락을 해제합니다.

TTL(Time To Live)을 설정하여, 만약 작업이 예상보다 오래 걸리거나 예기치 못한 상황이 발생하더라도 락이 자동으로 해제되도록 할 수 있습니다.

이 방법을 사용하면 하나의 인스턴스만 작업을 실행하므로, 알림이 중복 발송되는 문제를 방지할 수 있습니다."

 

 

예상 질문 3: "스프링 배치에서 트랜잭션 관리를 어떻게 처리했나요?"

 

답변:

"스프링 배치는 기본적으로 트랜잭션 관리를 지원하며, 각 단계(Step)마다 트랜잭션 경계를 설정할 수 있습니다. 알림 발송과 같은 중요한 작업에서는 데이터의 일관성을 보장하기 위해 트랜잭션을 적용하여 작업이 성공적으로 완료되지 않으면 롤백하도록 설정했습니다. 예를 들어, 읽지 않은 알림을 조회하고 다시 알림을 보내는 과정에서 문제가 발생할 경우, 해당 작업은 롤백되어 알림이 중복되거나 잘못된 상태로 저장되지 않도록 했습니다.

또한, 알림을 발송한 후 성공적으로 처리된 데이터에 대해서만 커밋이 이루어지도록 하여 데이터 일관성을 유지했습니다."

 

 

예상 질문 4: "만약 한 인스턴스에서 배치 작업 중 오류가 발생하면 어떻게 처리할 수 있나요?"

 

답변:

"배치 작업 중 오류가 발생할 수 있는 다양한 상황에 대비해 스프링 배치의 재시도 및 실패 처리 메커니즘을 적용했습니다. RetryTemplate을 사용하여 특정 단계에서 오류가 발생했을 때, 자동으로 재시도하도록 구성하였습니다. 오류가 발생해도 일정 횟수 동안 재시도할 수 있는 구조를 쉽게 구현할 수 있습니다. 또한, SkipPolicy를 설정하여 일정 횟수 이상의 오류가 발생한 경우 해당 배치 작업을 중단하고, 오류를 로깅하거나 별도의 실패 처리 로직을 실행할 수 있습니다.

이외에도, 실패한 작업을 별도의 에러 큐에 넣어 나중에 다시 처리할 수 있도록 설정할 수 있습니다. 이렇게 하면 시스템 장애나 예기치 않은 오류 발생 시에도 작업이 중단되지 않고, 안정적으로 복구할 수 있도록 대비할 수 있습니다."

 

기본적으로 RetryTemplate을 사용해서 배치 오류 해결을 위해 재전송을 사용하는데 트랜잭션 관리로도 가능하다.

배치 작업의 각 스텝에 대해 트랜잭션을 설정하여 작업 중 오류가 발생하면 트랜잭션을 롤백하고 작업을 재시도하지 않도록 할 수 있다. 트랜잭션을 사용하면 배치 작업에서 일부 데이터가 처리된 후 오류가 발생해도 처리된 데이터가 커밋되지 않게 하여 데이터 일관성을 유지할 수 있다.

728x90

+ Recent posts