Deadlock (교착 상태)

아투·2026년 4월 21일

Operation System

목록 보기
9/22
post-thumbnail

1. 데드락의 정의와 발생 원리

1) 정의

  • 데드락이란 2개 이상의 프로세스가 서로의 자원을 얻을 때까지 자기가 가진 것을 절대 놓지 않아서 시스템이 어떠한 작업도 진행하지 못헤서 무한히 멈추는 현상을 의미한다.

  • 동작 예시

    • 프로세스 1이 자원 A(예: DB 테이블 락)를 점유 -> 프로세스 2가 자원 B(예: 파일 수정 권한)를 점유 -> 이때, 프로세스 1이 작업을 마치기 위해 자원 B를 요청하며 기다린다. -> 동시에 프로세스 2도 작업을 마치려고 자원 A를 요청하며 기다린다.
  • 결과

    • 프로세스 1과 2는 서로의 자원을 얻을 때까지 자기가 가진 것을 절대 놓지 않는다.
    • CPU는 이들이 작업 중이라고 판단할 수 있지만, 실제로는 아무런 진전이 없는 무한 루프(Livelock과는 다른 완전한 멈춤) 상태에 빠진다.

2) 대규모 서비스에서 데드락이 치명적인 이유

  • 도미노 현상과 국소적 정체
    특정 트랜잭션 사이에서 자원 점유가 엇갈리며 발생하는 데드락은 시스템 일부를 마비시키는 시발점이 된다.

  • 커넥션 풀 고갈과 자원 마비
    대규모 트래픽 환경에서는 효율성을 위해 제한된 수의 DB 커넥션 풀을 공유한다. 데드락에 걸린 요청들이 커넥션을 반납하지 않고 점유함에 따라 풀이 가득 차게 되며 결국 정상적인 다른 기능들까지 DB 연결 실패로 인해 작동을 멈춘다.

  • 마이크로서비스 환경에서의 장애 전이
    특정 서비스 내부의 정체가 해당 서비스를 호출하는 연관 서비스들의 스레드 점유로 이어진다. 이는 결제 주문 장바구니 서비스 등 플랫폼 전체로 장애가 확산되는 연쇄적 실패의 원인이 된다.

  • 비정상적 인프라 비용 발생
    대기 상태의 스레드 증가로 인해 메모리와 CPU 사용량이 급증한다. 이때 자동 확장 시스템이 성능 저하를 해결하기 위해 서버 대수를 늘리게 되면 실질적인 작업은 처리하지 못하면서 인프라 비용만 기하급수적으로 증가하는 모순적 상황이 초래된다.

  • 강제 종료에 따른 데이터 정합성 위기
    시스템 정상화를 위해 강제 종료를 선택할 경우 데이터베이스는 복구를 시도한다. 복잡하게 얽힌 데드락 상황에서의 복구 과정은 방대한 언두 로그 분석이 필요하여 막대한 시간이 소요되며 이 과정에서 데이터 오염이나 인덱스 손상이 발생해 서비스 신뢰도를 심각하게 훼손한다.


3) 데드락 성립의 필수 4대 조건

데드락은 네 가지 조건이 동시에 충족되어야만 발생하며 이 중 하나라도 배제하면 교착 상태를 방지할 수 있다.

  • 상호 배제 : 자원은 한 번에 하나의 프로세스만 사용할 수 있는 독점적 특성을 가진다.
  • 점유와 대기 : 자원을 점유한 상태에서 다른 프로세스에 할당된 자원을 추가로 확보하기 위해 대기하는 프로세스가 존재한다.
  • 비선점 : 이미 할당된 자원을 강제로 빼앗을 수 없으며 점유 중인 프로세스가 스스로 반납할 때까지 기다려야 한다.
  • 환형 대기 : 각 프로세스가 순환 형태로 다음 프로세스가 점유한 자원을 대기하는 고리가 형성된다.

(1) 무엇을 깨는 것이 가장 최선인가?

  • 상호 배제 파괴 : 공유 자원의 독점을 허용하면 서비스 전체의 데이터 일관성이 무너진다.

  • 점유와 대기 파괴 : 모든 자원을 한꺼번에 할당받아야 하므로 특정 프로세스가 자원을 영영 얻지 못하는 기아 상태가 발생할 수 있다.

  • 비선점 파괴

    • 작업 중인 프로세스의 자원 권한을 강제로 박탈하면 결제 처리 도중 데이터가 유실되는 등 심각한 사고로 이어진다.
  • 환형 대기 파괴 : 상호 배제나 비선점 조건을 강제로 깨는 것은 시스템의 데이터 정합성을 파괴하거나 치명적인 오류를 발생시킬 위험이 크다.

    • 반면 환형 대기는 자원 요청 순서를 정하는 규칙만으로 제어가 가능하여 비용 대비 안전성이 매우 높다.

(2) 나쁜 예시 : 데드락 발생하는 위험한 코드

// Thread A: DB락(1) 잡고 파일락(2) 요청
new Thread(() -> {
    synchronized (dbLock) { 
        System.out.println("Thread A: DB 락 획득");
        synchronized (fileLock) { 
            System.out.println("Thread A: 파일 락 획득");
        }
    }
}).start();

// Thread B: 파일락(2) 잡고 DB락(1) 요청 (순서가 반대이다.)
new Thread(() -> {
    synchronized (fileLock) { 
        System.out.println("Thread B: 파일 락 획득");
        synchronized (dbLock) { 
            System.out.println("Thread B: DB 락 획득");
        }
    }
}).start();

(3) 좋은 예시 : 환형 대기를 깨뜨린 안전한 코드

public class DeadlockPrevention {
    private static final Object dbLock = new Object();   // 자원 1 (낮은 번호)
    private static final Object fileLock = new Object(); // 자원 2 (높은 번호)

    public static void main(String[] args) {
        // Thread A: 규칙 준수 (1 -> 2 순서)
        Thread threadA = new Thread(() -> {
            synchronized (dbLock) { 
                System.out.println("Thread A: 1번(DB) 락 획득 성공");
                
                try { Thread.sleep(100); } catch (InterruptedException e) {}

                synchronized (fileLock) { 
                    System.out.println("Thread A: 2번(파일) 락까지 획득 성공, 작업 시작");
                }
            }
        });

        // Thread B: 규칙 준수 (2번이 먼저 필요해도 1번부터 잡아야 한다.)
        Thread threadB = new Thread(() -> {
            // 자원 2가 먼저 필요하더라도 규칙상 1번부터 요청합니다.
            synchronized (dbLock) { 
                System.out.println("Thread B: 1번(DB) 락 획득 성공");
                synchronized (fileLock) { 
                    System.out.println("Thread B: 2번(파일) 락까지 획득 성공, 작업 시작");
                }
            }
        });

        threadA.start();
        threadB.start();
    }
}

4) 배고픈 철학자 문제

  • 정의 및 배경
    1965년 에츠허르 다익스트라가 운영체제의 교착 상태(Deadlock)를 설명하기 위해 고안한 고전적인 모델이다. 한정된 자원을 여러 프로세스가 공유할 때 발생하는 동시성 문제를 직관적으로 보여준다.

  • 상황 설정

    1. 원형 테이블에 5명의 철학자가 앉아 있고, 각자 앞에는 스파게티 접시가 놓여 있다.
    2. 철학자들 사이에는 포크가 1개씩, 총 5개가 놓여 있다.
    3. 철학자는 생각하기식사하기 두 가지 행동만 반복한다.
    4. 식사를 하기 위해서는 반드시 자신의 왼쪽과 오른쪽에 있는 포크 2개를 모두 집어야 한다.
  • 교착 상태(Deadlock) 발생 시나리오
    모든 철학자가 동시에 배가 고파져서 다음과 같이 행동할 때 시스템은 영구적으로 멈춘다.

    • 1단계 : 모든 철학자가 동시에 자신의 왼쪽 포크를 집어 든다.
    • 2단계 : 이제 오른쪽 포크를 집으려 하지만, 이미 오른쪽 철학자가 그 포크를 집은 상태다.
    • 3단계 : 모든 철학자가 "오른쪽 포크가 나타날 때까지 내가 든 왼쪽 포크는 절대 놓지 않겠다"며 무한히 대기한다.
    • 결과 : 아무도 식사를 하지 못하고 굶어 죽는 교착 상태에 빠진다.
  • 데드락 발생의 4가지 조건 확인

    • 상호 배제 : 포크는 한 번에 한 명만 쓸 수 있다.
    • 점유와 대기 : 왼쪽 포크를 잡은 채로 오른쪽 포크를 기다린다.
    • 비선점 : 옆 사람의 포크를 강제로 뺏을 수 없다.
    • 환형 대기 : 모든 철학자가 원형으로 서로의 자원을 기다린다.
  • 대표적인 해결 방법

    • 인원 제한 : 테이블에 동시에 앉을 수 있는 인원을 4명으로 제한하여 최소 한 명은 두 포크를 모두 잡을 수 있게 한다.
    • 비대칭 해결 : 홀수 번호 철학자는 왼쪽부터, 짝수 번호 철학자는 오른쪽부터 포크를 집게 하여 환형 대기 고리를 끊는다.
    • 상태 확인 : 양쪽 포크가 모두 사용 가능할 때만 포크를 들 수 있게 허용한다 (세마포어 또는 뮤텍스 활용).

2. 데드락 해결 전략

1) 예방, 회피, 탐지, 복구

  • 예방 방법 (Prevention)
    교착 상태가 발생하기 위한 4가지 필수 조건(상호 배제, 점유 및 대기, 비선점, 순환 대기) 중 하나를 아예 못 일어나게 규칙을 정하는 것이다.

  • 회피 방법 (Avoidance)
    예방은 규칙이 너무 까다로워 시스템 효율을 떨어뜨릴 수 있다. 회피는 좀 더 유연하게, 자원을 줄 때마다 "이걸 줬을 때 나중에 문제가 생길까?"를 시뮬레이션한다.

  • 탐지 방법 (Detection)
    예방이나 회피는 비용이 많이 들기 때문에, 평소에는 자유롭게 두다가 주기적으로 데드락이 발생했는지 검사하는 전략이다.

  • 복구 방법 (Recovery)
    탐지 단계에서 데드락을 찾아냈다면, 이제 시스템을 다시 정상화해야 한다.


(1) 자원 순서화 (Resource Ordering)

자원 순서화란 시스템 내에 존재하는 모든 자원에 고유한 우선순위 번호를 부여하고 정해진 오름차순으로만 자원을 점유하도록 강제하는 기법이다.

자원 순서화 기법은 시스템 내 존재하는 모든 자원에 고유한 우선순위 번호를 부여하고 정해진 오름차순으로만 점유를 허용하여 교착 상태의 필수 요건인 순환 대기 조건을 원천 차단하는 예방 기술로서, 프로세스가 보유 자원보다 높은 순위만 요청하도록 강제해 사이클 형성을 물리적으로 불가능하게 만들고 낮은 순위 자원 필요 시 기존 자원을 모두 해제한 뒤 재요청을 유도하며, 별도 감지 로직 없이 설계 규칙만으로 데드락을 확실히 방지하는 효율성을 갖추었으나 할당 순서에 따라 자원 이용률이 저하될 수 있는 기술적 한계가 존재한다.


(2) 자원 할당의 일괄 처리 (Hold and Wait 방지)

프로세스가 실행에 필요한 모든 자원을 작업 시작 전에 한꺼번에 요청하여 할당받는 방식이다.

점유 및 대기 조건의 원천 차단 기법은 프로세스가 특정 자원을 점유한 채 다른 자원을 확보할 때까지 대기하는 상황을 방지하여 교착 상태를 예방하는 기술로서, 운영체제가 요청된 모든 자원이 가용할 때만 일괄 할당을 허용하고 추가 자원 필요 시 기존 자원을 모두 해제한 뒤 다시 전체를 요청하도록 강제함으로써 순환 고리를 사전에 제거하나, 실제 사용 시점보다 앞선 점유로 인한 자원 효율성 저하와 특정 프로세스가 무한히 할당받지 못하는 기아 현상이 발생할 수 있는 시스템적 한계가 명확히 존재한다.


(3) 은행원 알고리즘 (Banker's Algorithm)

은행원 알고리즘은 은행이 대출 한도를 보장하듯 모든 프로세스가 정상 종료 가능한 안전 순서열의 존재를 판별하여 자원 할당을 결정하는 논리적 모델로서, 가용 자원과 최대 요구량을 실시간 추적하며 요청 시 가상 할당 시뮬레이션을 수행하여 시스템이 불안전 상태에 빠질 위험이 있다면 승인을 거부하고 대기시킨다.

다만 프로세스 수의 고정과 최대 요구량 사전 파악이 필수적이며 매 요청마다 발생하는 연산 오버헤드로 인해 시스템 자원 활용률이 낮아지는 기술적 한계가 존재한다.


(4) 자원 할당 그래프 알고리즘 (Resource Allocation Graph, RAG)

자원 할당 그래프 확장 기법은 자원 유형당 인스턴스가 하나인 시스템 환경에서 미래의 자원 요청 가능성을 점선 형태의 예약 간선으로 도식화하여 교착 상태를 사전에 방지하는 회피 기술이다.

프로세스의 자원 요청 시 예약 간선을 할당 간선으로 가상 전환한 뒤 전체 그래프 내 사이클 형성 여부를 엄격히 검사하며, 사이클이 없는 안전 상태가 보장될 때만 실제 할당을 수행함으로써 시스템 안정성을 동적으로 유지하고 매 요청마다 미래의 잠재적 위험을 분석하여 시스템을 항상 안전한 궤도 내에 머물게 하는 핵심적인 논리적 토대를 제공한다.


(5) 대기 그래프 (Wait-for Graph)

대기 그래프는 시스템 내 프로세스 간의 대기 관계를 방향성이 있는 그래프로 도식화하여 교착 상태 발생 여부를 정밀하게 판별하는 진단 방법이다. 노드는 실행 중인 프로세스를 의미하고 화살표는 자원 점유에 따른 의존 관계를 나타내며 자원 노드를 생략해 단일 자원 유형 환경에서 탐지 효율을 극대화한 것이 특징이다.

그래프 내에서 시작과 끝이 연결된 사이클이 발견될 경우 이를 교착 상태로 확진하며 운영체제는 주기적으로 그래프를 갱신 및 검사하여 사이클 확인 시 특정 프로세스 강제 종료나 자원 선점 방식을 통해 상태를 즉각 해소한다.


(6) 자원 할당 상태 모니터링

자원 할당 상태 모니터링은 RDBMS가 트랜잭션 간 잠금 대기 관계를 그래프로 그려 순환 고리를 탐색하고 특정 트랜잭션을 강제 종료시켜 시스템 마비를 해소하는 자동 관리 기능이다. 실시간으로 자원 점유 및 요청 정보를 기록하며 자원 할당 그래프로 점유 흐름을 논리적으로 추적하고, 사이클 형성 여부를 분석하여 데드락 발생의 증거로 삼는다.

시스템 오버헤드를 방지하려 주기적으로 탐지 알고리즘을 가동하며 교착 상태 확인 시 즉각 복구 절차와 연계하여 프로세스 종료 및 자원 해제를 수행함으로써 시스템 가용성을 안정적으로 유지한다.


(7) 프로세스 강제 종료 (Termination)

프로세스 강제 종료는 교착 상태 감지 시 하나 이상의 프로세스를 중단시켜 점유된 자원을 회수하는 사후 복구 기법이다. 연루된 모든 대상을 한꺼번에 중단하는 전체 종료와 해제 시까지 순차적으로 제거하는 부분 종료로 구분되며, 우선순위가 낮거나 수행 시간이 짧은 작업을 우선 선별하여 매몰 비용을 최소화하고 자원 회수 효율성을 극대화한다.

별도 알고리즘 없이 신속한 해결이 가능하나 이미 진행된 작업의 데이터 소실이나 일관성 훼손 위험이 있으며 특정 프로세스가 반복적으로 종료 대상으로 선정되는 기아 현상이 수반될 수 있는 트레이드오프가 존재한다. 하드웨어 자원의 특성과 비즈니스 중요도를 고려하여 최적의 대상을 선별하는 정교한 정책이 요구된다.


(8) 자원 선점 및 롤백 (Preemption & Rollback)

자원 선점 및 롤백은 교착 상태 발생 시 특정 프로세스로부터 자원을 강제로 회수하여 다른 프로세스에게 할당함으로써 시스템 마비를 능동적으로 해제하는 복구 기법이다. 최소 비용 원칙에 따라 선정된 희생자의 자원을 선점하여 대기 작업에 부여하고, 자원을 잃은 프로세스는 안전한 체크포인트 지점으로 되돌려 재실행하는 과정을 거친다.

시스템 전체 중단 없이 가용성을 높일 수 있으나, 특정 프로세스가 반복 희생되는 기아 현상과 상태 보존을 위한 체크포인트 저장 비용이 시스템 부하를 가중시키는 기술적 트레이드오프가 존재한다.


(9) 우선순위 기반 복구

우선순위 기반 복구는 데드락 발생 시 시스템 영향도가 적은 대상을 객관적 우선순위에 따라 희생물로 선정하여 자원을 회수하거나 강제 종료함으로써 순환 대기 고리를 해제하는 전략으로서, 프로세스 속성을 종합 평가해 낮은 순위의 작업을 중단하거나 자원을 선점해 배분함으로써 핵심 서비스 중단을 최소화하고 가용성을 신속히 회복하는 동시에,

낮은 순위 작업의 기아 현상과 상태 복구를 위한 추가적인 시스템 부하라는 기술적 트레이드오프가 존재함을 인지하고 운영 환경에 최적화된 정책을 수립해야 한다.

(10) RDBMS 데드락 탐지 및 복구 방법

MySQL
  • 탐지
    • InnoDB는 wait-for graph라는 내부 자료구조를 유지한다.
    • 트랜잭션이 자원을 기다릴 때마다 그래프에 화살표를 그린다. 만약 화살표가 순환을 그리게 되면 데드락 발생이라 판단한다.
    • innodb_deadlock_dect
      • 설정값을 통해 이 탐지 기능을 켜고 끌 수 있다. 기본적으로는 활성화 되어 있다.
    • 자동 탐지는 시스템이 멈추는 것을 방지하고 자동 복구가 가능하다는 장점이 있지만, 초당 수천 건의 트랜잭션이 발생하는 고부하 환경에서는 탐지 자체가 많은 CPU 비용을 소모할 수 있기 때문에, 시스템 규모에 따라 자동 탐지 기능을 끌지 사용할지 판단해야 한다.
  • 복구
    • Victim 선정
      • InnoDB는 데드락에 연루된 트랜잭션 중 Undo 로그 양이 가장 적은 트랜잭션(즉, 시스템 복구 비용이 가장 낮은 것)을 희생자(Victim)로 선정한다.
    • 롤백(Rollback)
      • 선정된 트랜잭션을 강제로 롤백 시켜 점유하던 락을 해제한다. 그러면 대기 중이던 다른 트랜잭션이 작업을 재개할 수 있게 된다.
    • 강제 롤백은 데이터의 일관성을 유지하며 잠금을 해제할 수 있지만, 애플리케이션 레벨에서 재시도 로직을 반드시 구현해야 한다는 것을 명심해야 한다.

3. 실무 및 현대적 시스템에서의 데드락

1) 심화

(1) 타조 알고리즘 (Ostrich Algorithm)

타조 알고리즘은 데드락 발생 확률이 극히 낮거나 해결 비용이 과도할 때 문제를 의도적으로 무시하는 전략으로, 위험 시 모래에 머리를 묻는 타조의 행동에서 유래하였다. 완벽한 방지보다 시스템 재부팅이 경제적이라는 실용적 관점을 중시하며, 현대 운영체제에서 모든 교착 상태를 차단할 경우 발생하는 막대한 성능 저하를 방지하기 위해 채택된다.

유닉스와 윈도우 등 대부분의 범용 운영체제가 이 방식을 활용하며, 드문 시스템 멈춤 발생 시 사용자가 직접 재시작이나 강제 종료를 수행하도록 유도하여 전체적인 퍼포먼스를 유지하는 효율적인 공학적 대안으로 평가받는다.

(2) Lock-Free 및 Wait-Free 알고리즘

데드락이란 결국 락을 사용하기 때문에 발생하는 문제이다. 락을 아예 사용하지 않고 동시성을 제어하는 방식인 낙관적 락 방식을 채용할 수 있다.

뮤텍스나 세마포어 같은 블로킹 메커니즘 대신 CAS(Compare-And-Swap) 같은 원자적(Atomic) 명령어를 사용하여 데이터를 업데이트 한다. 어떤 스레드도 락을 사용하지 않으므로 데드락이 발생할 가능성은 완전히 없어진다.

Java의 java.util.concurrent.atomic 패키지나 고성능 메시지 큐인 LMAX Disrupotor 등이 이 방식을 사용한다.

(3) Gap Lock과 Next-Key Lock

MySQL(InnoDB) 사례를 언급하였지만 실무에서 발생하는 데드락의 상당수는 단순히 특정 행때문이 아니라 범위 때문에 발생한다.

  • Gap Lock : 레코드와 레코드 사이의 간격에 락을 거는 것.
  • Next-Key Lock : 레코드 락과 갭 락을 합친 것.

트랜잭션 A가 특정 범위의 갭 락을 잡고 있는 상태에서, 트랜잭션 B가 그 사이에 데이터를 삽입하려 할 때(Insert Intention Lock) 예상치 못한 데드락이 빈번하게 발생한다. 이는 행 단위 로그만 봐서는 이해하기 어렵기 때문에 매우 중요한 개념이다.

(4) 2단계 잠금 규약(Two-Phase Locking, 2PL)

데이터베이스 트랜잭션의 직렬성(Serializability)을 보장하기 위한 이론적 배경이다.

  • 확장 단계(Expanding Phase) : 트랜잭션이 락을 획득하기만 하고 해제하지 않는 단계.
  • 수축 단계(Shrinking Phase) : 트랜잭션이 락을 해제하기만 하고
    새로 획득하지 않는 단계.

2PL은 데이터 일관성을 보장하지만, 데드락을 방지하지는 못한다. 오히려 모든 락을 해제 전까지 쥐고 있게 만들어 데드락 발생 가능성을 높이기도 한다. 이를 보완한 것이 Strict 2PL이다.

(5) 분산 환경의 데드락 탐지기

  • 중앙 집중형 : 하나의 노드가 전체 시스템의 자원 할당 그래프를 관리한다. (성능 병목 위험)

  • 분산형 : 각 노드가 자신의 지역 그래프 정보를 인접 노드에 전달하여 사이클을 찾는다.

  • 위계형 : 노드들을 트리 구조로 묶어 상위 노드에서 하위 노드들 간의 데드락을 관리한다.

(6) 실무적인 디버깅 및 분석 도구

  • Thread Dump 분석

    • Java 환경에서 jstack 명령어를 통해 스레드 덤프를 추출하면, JVM이 자체적으로 Found 1 deadlock이라며 문제의 원인이 되는 스레드와 락주소를 짚어준다.
  • DB 엔진 상태 조회

    • MySQL에서 SHOW ENGINE INNODB STATUS; 명령어를 통해 가장 최근에 발생한 데드락의 쿼리와 트랜잭션 상황을 상세히 분석하는 방법.

(6) 자원 할당 거부 기법 : 점진적 할당

자원 순서화와 비슷하지만 계층 개념을 도입하는 기법이다.
예를 들어 데이터베이스 락을 잡은 상태에서만 네트워크 소켓 락을 잡을 수 있다는 식의 상위 계층 규칙을 정하는 것이다.


2) 데드락 종류와 혼동하기 쉬운 개념

(1) 자원 데드락 (Resource Deadlock)

자원 데드락은 시스템 내 한정된 자원을 점유한 프로세스들이 서로가 가진 자원의 해제를 요구하며 작업을 진행하지 못한 채 무한정 멈춰 있는 상태를 의미하며, 이는 상호 배제와 점유 및 대기, 비선점, 순환 대기라는 네 가지 필수 조건이 동시에 충족될 때 성립하여 시스템 전반의 생산성을 저해하는 요인이 된다. 이를 완전히 차단하는 설계는 무결성을 보장하나 자원 할당 규칙의 엄격화로 인해 자원 활용 효율과 전체 처리량이 감소하는 기술적 비용이 수반되므로 시스템 안정성과 운영 효율 사이의 정교한 균형을 유지하는 설계적 관점이 요구된다.


(2) 통신 데드락 (Communication Deadlock)

통신 데드락은 네트워크나 분산 시스템 환경에서 둘 이상의 프로세스가 서로 상대방으로부터 메시지가 전송되기를 무한히 기다리는 현상으로, 물리적 자원의 점유권을 두고 경쟁하는 자원 데드락과 달리 메시지 전달이라는 특정 이벤트의 발생을 기다리는 것에 초점을 맞춘다.

프로세스 간 대기 고리가 형성되거나 메시지가 소실될 경우 시스템이 정지하게 되며, 타임아웃을 통한 재전송이나 설계 단계의 프로토콜 검증으로 발생을 억제하고 예외를 해결하는 기술적 대응이 필수적으로 요구된다. 이를 통해 분산 환경에서의 통신 무결성과 시스템 가용성을 동시에 확보한다.


(3) 분산 데드락 (Distributed Deadlock)

분산 데드락은 여러 독립된 노드 환경에서 서로 다른 위치의 프로세스들이 네트워크를 통해 상대방 자원을 대기하며 시스템 전체가 멈추는 현상으로, 자원 정보가 여러 곳에 분산되어 단일 노드 정보만으로는 판별이 어렵고 전역 대기 그래프 유지가 매우 까다롭다는 점이 기술적 핵심이다.

특정 요청이 여러 노드를 거쳐 거대한 순환 고리를 형성하며 발생하며 중앙 집중형 관리나 노드 간 협력 통신을 통한 상태 추론 방식이 사용되나 통신 지연과 메시지 오버헤드로 인해 해결 과정이 일반 시스템보다 훨씬 복잡한 특징을 가지며 시스템 전반의 가용성을 저해한다.


(4) 재귀적 데드락 (Recursive Deadlock / Self-Deadlock)

재귀적 데드락은 특정 스레드가 이미 소유한 락을 해제하지 않고 동일 락을 다시 획득하려 할 때 발생하는 자기 차단 상태로서, 재진입이 불가능한 뮤텍스가 동일 스레드의 중복 요청을 식별하지 못해 스스로가 점유한 자원의 해제를 무한히 기다리는 논리적 모순에 빠지는 현상을 의미한다.

락을 보유한 함수가 내부에서 동일 락을 요구하는 함수나 재귀 호출을 수행할 때 주로 발생하며, 이를 방지하기 위해 중복 획득을 허용하고 카운트 관리를 통해 마지막 해제 시점에 자원을 방출하는 재진입 락을 도입하여 시스템의 실행 흐름을 보장한다.


(5) 데드락과 혼동하기 쉬운 개념 : 라이브락 (Livelock)

라이브락은 두 개 이상의 프로세스가 서로의 상태 변화에 반응하여 자신의 상태를 끊임없이 변경함에도 불구하고 실질적인 작업 진행은 전혀 이루어지지 않는 활성 대기 상태를 의미한다. 프로세스가 완전히 정지하는 데드락과 달리 실행 상태를 유지하며 CPU 자원을 지속적으로 소비하지만, 충돌을 피하기 위한 상호 양보와 우회 동작이 무한히 반복되어 유의미한 결과에 도달하지 못한다는 점에서 동적인 교착 상태로 간주된다.

이는 시스템의 멈춤이 아닌 무의미한 분주함으로 인해 전체 효율을 저해하는 현상이며 자원 점유와 대기가 고정된 데드락과는 구별되는 명확한 기술적 특징을 지닌다. 해당 상태를 해결하기 위해 무작위 지연 시간을 도입하거나 설계 단계에서 상호 반응 로직을 정교화하는 등의 실무적 대응이 필수적으로 요구된다.


(2) 기아 상태 (Starvation)

기아 상태는 특정 프로세스가 자원 할당 순위에서 계속 밀려나 필요한 자원을 확보하지 못한 채 무한정 대기하는 현상을 의미한다. 시스템은 정상 작동하나 알고리즘이 특정 조건을 우대하여 발생하는 불공정성이 본질이며, 모든 프로세스가 정지하는 데드락과 달리 타 작업들은 활발히 수행 중이라는 점에서 구별된다.

높은 순위 작업의 유입으로 낮은 순위가 영구 소외되는 것을 막기 위해, 대기 시간에 비례해 우선순위를 높이는 에이징 기법을 적용함으로써 모든 프로세스가 반드시 실행 기회를 보장받도록 설계한다.


(3) 우선순위 역전 (Priority Inversion)

우선순위 역전은 높은 우선순위 프로세스가 낮은 순위 프로세스에 의해 실행이 차단되어 우선순위가 논리적으로 뒤바뀌는 현상으로서 낮은 순위 작업이 공유 자원을 점유한 상태에서 높은 순위 작업이 대기할 때 자원을 쓰지 않는 중간 순위 작업이 CPU를 선점하며 발생하고,

시스템이 영구 정지하는 데드락과 달리 응답 시간이 급격히 지연되는 성능 결함에 해당하므로 낮은 순위 프로세스에 한시적으로 높은 우선순위를 부여하는 우선순위 상속 기법을 적용하여 작업을 빠르게 완료하도록 유도함으로써 시스템의 실시간성과 안정성을 확보한다.


3) 현업에서의 데드락 사례 및 시나리오

(1) 데이터베이스 트랜잭션의 상호 의존성 데드락

데이터베이스 트랜잭션의 상호 의존성 데드락은 둘 이상의 트랜잭션이 특정 데이터 잠금을 확보한 상태에서 상대방의 잠금 해제를 무한히 기다리는 상태를 의미한다. 데이터 무결성 보장을 위한 배타적 잠금 메커니즘이 본질적 원인이며, 서로 다른 자원을 점유한 채 교차 요청 시 순환 대기 고리가 형성된다.

주로 다중 테이블 갱신 시 접근 순서가 불일치할 때 발생하며, 관리 시스템은 이를 실시간 감지하여 특정 트랜잭션을 강제 종료하고 롤백함으로써 전체 시스템의 정지를 방지하는 자동 복구 기능을 수행한다.


(2) 분산 시스템 환경에서의 외부 API 호출 데드락

분산 시스템 환경에서의 외부 API 호출 데드락은 서로 다른 마이크로서비스 간 동기식 블로킹 호출 시 상대방의 응답을 무한히 기다리며 전체 처리가 중단되는 상태이다. 유한한 스레드 풀 환경에서 서비스 A와 B가 서로의 API를 교차 호출하며 응답을 기다릴 때 모든 가용 스레드가 고립되어 순환 구조가 완성된다.

이는 주로 설계상의 순환 의존성으로 인해 발생하며 타임아웃 미설정 시 위험이 극대화된다. 이를 예방하기 위해 의존 방향을 단방향으로 강제하거나 비동기 메시지 큐를 도입하여 직접적인 대기 구조를 제거함으로써 시스템의 안정성을 확보한다.


(3) 실무적 데드락 사례: 스레드 풀 고갈의 메커니즘

스레드 풀 고갈 데드락은 한정된 가용 스레드를 모두 점유한 상위 작업들이 동일한 풀 내 하위 작업의 완료를 동기적으로 기다릴 때 발생하는 논리적 교착 상태로서, 모든 스레드가 점유된 채 하위 작업이 큐에서 무한 대기하여 시스템이 응답 불능에 빠지는 메커니즘으로 작동한다.

이를 해결하기 위해 작업 간 의존성을 제거하는 비동기 논블로킹 방식을 채택하거나 상위와 하위 작업의 스레드 풀을 물리적으로 분리하여 자원 간섭을 차단함으로써 시스템의 안정성을 확보하고 실행 자원의 한정성을 극복한다.


참고 사항

  • 락 순서화(Lock Ordering)
    • 자원 계층 구조(Resource Hierarchy)라고도 부른다.

참고 문헌

0개의 댓글