Active-Active 환경에서 중복 실행이 발생한 사례

Active Active 환경에서 발생하는 중복 실행 문제의 이해
현대 IT 서비스는 24시간 중단 없는 운영을 보장하기 위해 여러 대의 서버를 동시에 가동하는 Active-Active 구성을 즐겨 사용합니다. 이는 한 서버가 다운되어도 다른 서버가 서비스를 지속할 수 있게 해주지만, 동시에 매우 까다로운 기술적 난제를 안겨줍니다. 그중 가장 대표적인 것이 바로 동일한 작업이 여러 서버에서 중복으로 실행되는 현상입니다. 예를 들어, 매일 새벽에 정산 데이터를 처리하는 배치 작업이 두 대의 서버에서 동시에 실행되어 고객의 계좌에서 돈이 두 번 빠져나가는 사고가 발생한다면 이는 치명적인 비즈니스 손실로 이어집니다.
중복 실행이 발생하는 근본적인 이유
Active-Active 환경에서 중복 실행이 발생하는 이유는 각 서버가 서로의 상태를 실시간으로 완벽하게 동기화하지 못하기 때문입니다. 시스템은 각자의 독립적인 스케줄러를 가지고 동작하며, 특정 시점이 되면 약속된 작업을 수행합니다. 이때 서버 간의 시간 차이, 네트워크 지연, 혹은 상태 공유 메커니즘의 부재로 인해 여러 서버가 동시에 동일한 트리거를 감지하게 됩니다. 특히 분산 시스템에서는 모든 서버가 동시에 동일한 판단을 내리도록 설계하는 것이 이론적으로 매우 어렵다는 ‘분산 시스템의 한계’가 존재합니다.
중복 실행을 방지하는 실용적인 전략
중복 실행을 막기 위해서는 단순히 서버를 늘리는 것보다 ‘어떻게 제어할 것인가’에 집중해야 합니다. 현업에서 가장 많이 사용하는 실무적인 방법들을 소개합니다.
- 분산 락 활용: Redis나 Zookeeper와 같은 외부 저장소를 사용하여 특정 작업이 수행 중인지 확인하는 깃발을 꽂는 방식입니다. 작업을 시작하려는 서버는 먼저 이 저장소에 ‘내가 지금 이 일을 하겠다’는 신호를 보내고 승인을 받아야 합니다.
- 멱등성 보장: 시스템 설계 단계에서 가장 권장되는 방법입니다. 작업이 여러 번 실행되더라도 결과가 단 한 번 실행된 것과 동일하게 유지되도록 로직을 짜는 것입니다. 예를 들어, 이미 결제된 주문 번호라면 두 번째 요청 시 오류를 뱉거나 무시하도록 구현하는 방식입니다.
- 작업 스케줄링 전용 노드 분리: Active-Active 구성이더라도 배치 작업만큼은 별도의 전용 노드에서만 실행되도록 정책을 수립하는 방법입니다. 운영 복잡도는 약간 올라가지만, 중복 실행의 위험을 원천적으로 차단할 수 있습니다.
- 데이터베이스 레벨의 고유 제약 조건: 데이터베이스의 유니크 키(Unique Key)를 활용하여 동일한 데이터가 두 번 삽입되지 않도록 강제하는 방법입니다. 가장 강력하면서도 비용 효율적인 안전장치입니다.
흔한 오해와 진실
많은 개발자와 운영자가 흔히 하는 오해 중 하나는 “코드를 더 정교하게 짜면 중복 실행은 사라진다”는 믿음입니다. 하지만 분산 환경에서는 코드의 논리적 완벽함보다 시스템의 구조적 제약이 더 큰 변수로 작용합니다.
- 오해: 서버 시간을 완벽하게 동기화하면 중복 실행이 사라진다.
- 진실: NTP 등을 통해 시간을 맞추더라도 1밀리초 단위의 오차는 발생합니다. 또한, 서버의 부하 상태에 따라 처리 속도가 다르기 때문에 시간 동기화만으로는 해결책이 될 수 없습니다.
- 오해: 모든 서버에 락을 걸면 성능이 저하된다.
- 진실: 성능 저하는 발생할 수 있지만, 데이터 정합성이 깨지는 비용보다 훨씬 저렴합니다. 성능이 우려된다면 락의 범위를 최소화하거나 낙관적 락(Optimistic Lock) 기법을 도입하는 것이 좋습니다.
전문가가 제안하는 비용 효율적인 운영 팁
시스템 아키텍처를 전면적으로 개편하는 것은 큰 비용이 듭니다. 따라서 현재 환경에서 가장 효율적으로 대응할 수 있는 로드맵을 제안합니다.
첫 번째로, 가장 중요한 핵심 트랜잭션부터 ‘멱등성’을 확보하세요. 외부 결제, 데이터 변경 등 복구가 어려운 작업은 반드시 한 번만 실행되도록 설계해야 합니다. 두 번째로, Redis를 활용한 간단한 분산 락을 도입하세요. Redis는 메모리 기반이라 속도가 매우 빠르며, 구현 난이도 대비 효과가 매우 뛰어납니다. 세 번째로, 로그와 모니터링을 강화하세요. 중복 실행이 발생했을 때 이를 즉시 감지하고 알림을 주는 모니터링 시스템은 사고의 피해 규모를 획기적으로 줄여줍니다.
현업에서 자주 묻는 질문과 답변
Q: 분산 락을 사용할 때 락이 해제되지 않고 서버가 죽으면 어떻게 하나요?
A: 락을 설정할 때 ‘만료 시간(TTL, Time To Live)’을 반드시 지정해야 합니다. 작업이 비정상적으로 종료되더라도 일정 시간이 지나면 자동으로 락이 해제되도록 구성하면 데드락 상태를 방지할 수 있습니다.
Q: 데이터베이스 유니크 제약 조건을 걸면 성능이 많이 떨어지나요?
A: 인덱스가 적절히 설정되어 있다면 성능 저하는 미미합니다. 오히려 데이터 정합성을 보장하기 위한 비용으로 생각하면 매우 저렴하고 확실한 투자입니다. 데이터 무결성을 희생하면서까지 얻는 성능 향상은 결국 더 큰 운영 비용을 초래합니다.
Q: 모든 작업을 멱등하게 만드는 것이 가능한가요?
A: 현실적으로 모든 작업이 멱등성을 갖기는 어렵습니다. 하지만 비즈니스적으로 민감한 작업(결제, 발송, 상태 변경 등)은 반드시 멱등성을 확보해야 합니다. 그 외의 단순 조회나 캐시 갱신 작업 등은 중복 실행되어도 큰 문제가 없는 경우가 많으므로 중요도에 따라 차등 적용하는 것이 현명합니다.
데이터 정합성을 지키기 위한 아키텍처의 자세
Active-Active 환경에서의 중복 실행 문제는 기술적인 결함이라기보다는 분산 시스템이 가진 근본적인 특성입니다. 이를 해결하려는 시도는 단순히 프로그램을 만드는 것을 넘어 시스템의 견고함을 만드는 과정입니다. 가장 효율적인 방법은 ‘시스템은 언제든 실패할 수 있고, 중복 요청이 들어올 수 있다’는 가정하에 설계하는 것입니다.
예를 들어, 결제 시스템을 설계할 때 ‘주문 번호’를 기반으로 중복 여부를 체크하는 테이블을 별도로 운용하는 것은 매우 좋은 전략입니다. 결제 요청이 들어오면 우선 이 테이블에 주문 번호를 넣으려 시도하고, 이미 존재한다면 ‘이미 처리된 요청’으로 판단하여 즉시 반환하는 것이죠. 이러한 설계는 서버가 10대이든 100대이든 상관없이 동일하게 동작하며, 시스템 전체의 신뢰도를 높여줍니다.
또한, 개발 과정에서의 테스트도 중요합니다. 일반적인 환경에서의 테스트뿐만 아니라, 의도적으로 네트워크 지연을 발생시키거나 여러 서버에서 동시에 동일한 요청을 보내는 스트레스 테스트를 수행해야 합니다. 이러한 ‘카오스 엔지니어링’적 접근은 서비스 오픈 전 중복 실행 문제를 발견할 수 있는 가장 확실한 방법입니다.
운영 중 중복 실행 사고 대응 지침
이미 중복 실행 사고가 발생했다면 당황하지 말고 다음의 절차를 따르는 것이 중요합니다. 첫째, 즉시 해당 작업을 중단하여 추가적인 중복 발생을 막아야 합니다. 둘째, 데이터베이스 로그와 애플리케이션 로그를 대조하여 어느 정도의 데이터가 중복 처리되었는지 정확한 범위를 산출합니다. 셋째, 중복된 데이터를 식별하고 이를 복구하기 위한 스크립트를 작성합니다. 이 과정에서 데이터의 일관성을 해치지 않도록 주의해야 합니다. 마지막으로, 사고 원인을 분석하고 위에서 언급한 분산 락이나 멱등성 로직을 적용하여 재발 방지 대책을 세워야 합니다.
결론적으로 Active-Active 환경에서의 중복 실행은 완벽한 제어가 아닌, 관리 가능한 위험으로 다루어야 합니다. 시스템의 복잡도가 높아질수록 기술적인 방어 기제와 운영 정책이 조화를 이루어야 합니다. 기술 도입에 앞서 우리 서비스의 어떤 부분이 중복 실행에 가장 취약한지, 그 피해 규모가 어느 정도인지 먼저 파악하는 것이 우선입니다. 이를 통해 비용 효율적이고 실용적인 방어 체계를 구축하시기 바랍니다.




댓글 0
첫 댓글을 남겨보세요.