Windows 서버에서 MariaDB를 운영하다 보면 어느 날 갑자기 응답이 느려지거나, 애플리케이션에서 Lock wait timeout exceeded, Deadlock found 같은 메시지가 터지면서 장애로 이어지는 경우가 있습니다. 이 글은 “지금 서비스가 돌아가는 중”이라는 전제에서, 영향 최소화(online) 관점으로 원인 진단 → 즉시 완화 → 백업/복구 → 재발 방지 점검 순서로 정리한 실전 절차입니다.

Database lock metaphor with padlock and tangled connections

핵심은 “잠금을 없애는 것”이 아니라, 어떤 트랜잭션이 어떤 잠금을 오래 쥐고 있는지를 빠르게 찾고, 안전한 범위에서 풀어주는 것입니다.

1) 증상 분류: 지금 겪는 게 lock인지부터 확인

락 이슈는 대체로 아래 형태로 나타납니다. 먼저 증상을 분류하면 불필요한 조치를 줄일 수 있습니다.

  • 특정 API/배치만 느림: 특정 테이블/쿼리에서 row lock 경합 가능성이 큽니다.
  • 전체가 느려짐: 커넥션이 대기 상태로 쌓이면서 “연쇄 대기”가 발생했을 수 있습니다.
  • 에러가 명확: 애플리케이션 로그에 lock wait timeout / deadlock 문구가 직접 찍힙니다.
  • CPU는 낮은데 처리량이 급감: 실행이 아니라 “대기”가 병목인 전형적인 패턴입니다.

온라인 환경에서는 원인 파악 전에 성급히 재시작부터 하면, 같은 트랜잭션 패턴이 다시 들어와 재발하거나 복구 시간이 더 길어질 수 있습니다.

2) 영향 최소화 진단: 대기 중인 트랜잭션과 ‘범인’ 세션 찾기

가장 먼저 보고 싶은 건 “누가 잡고 있고(holding), 누가 기다리는지(waiting)”입니다. Windows에서도 MariaDB 클라이언트(mysql)로 접속해 확인합니다.

1) 현재 프로세스/대기 확인

가능하면 전체를 보되, 운영 중에는 긴 쿼리/대기만 빠르게 훑는 게 좋습니다.

  • SHOW FULL PROCESSLIST로 Sleep이 아닌 쿼리, 오래 도는 쿼리, Locked/Waiting 관련 상태를 확인
  • 애플리케이션 커넥션 풀에서 같은 계정으로 수백 개가 대기 중이면, DB 원인 + 앱 재시도 폭주가 겹쳤을 가능성

2) InnoDB 잠금 내부 상태 확인

InnoDB의 잠금은 프로세스리스트만으로는 원인이 흐릿할 때가 있어, 내부 상태를 함께 봅니다.

  • SHOW ENGINE INNODB STATUS 결과에서 LATEST DETECTED DEADLOCK, TRANSACTIONS, LOCKS 섹션 확인
  • 특정 테이블/인덱스가 반복적으로 등장하면 해당 경로가 병목

Isometric tiles showing sessions waiting on database locks

3) “긴 트랜잭션”이 있는지 확인

잠금 문제의 80%는 결국 “오래 열린 트랜잭션”에서 시작합니다. 특히 Windows 환경에서 스케줄러 작업(배치)이나 서비스 프로세스가 트랜잭션을 열어둔 채 예외 처리로 빠져버리면 쉽게 재현됩니다.

  • 오래 지속되는 트랜잭션(분 단위 이상)이 있는지
  • 같은 세션이 계속 갱신/삭제를 붙잡고 있는지
  • 대량 작업이 커밋 없이 한 번에 진행되는지

3) 즉시 완화(online): 재시작보다 먼저 할 수 있는 안전한 조치

서비스 영향 최소화 관점에서, 아래 순서로 “작게” 개입하는 편이 안전합니다.

  • 1순위: 범인 세션만 정리
    • 대기열을 만든 원인이 명확한 경우, 해당 세션(커넥션)만 종료하는 것이 재시작보다 충격이 작습니다.
    • 종료 전, 그 세션이 어떤 앱/호스트에서 왔는지(Host, User) 확인해 재발 경로를 같이 잡습니다.
  • 2순위: 대량 작업을 “작게 쪼개기”로 전환
    • 배치/정리 작업이 원인이라면, LIMIT로 나누거나(예: 1,000~10,000 단위) 커밋 주기를 짧게 해서 잠금 보유 시간을 줄입니다.
    • 가능하면 운영 피크 시간대에는 쓰기 작업(UPDATE/DELETE/ALTER)을 피합니다.
  • 3순위: 애플리케이션 재시도(리트라이) 폭주 완화
    • DB에서 lock wait가 나면 앱이 즉시 재시도하며 더 큰 경합을 만드는 경우가 있습니다.
    • 일시적으로 재시도 간격(백오프)이나 동시 실행 수를 낮추면 DB가 회복할 시간을 벌 수 있습니다.

가능하면 “DB 재시작”은 마지막 카드로 남겨두세요. 재시작은 확실히 잠금을 끊어주지만, 원인이 쿼리/트랜잭션 설계에 있으면 동일 증상이 곧바로 재발합니다.

4) 백업/복구 절차: lock 이슈 직후 안전하게 상태 보존하고 복구하기

잠금으로 장애가 난 직후에는 “우선 풀고 끝”이 아니라, 원인 분석을 위한 상태 보존과 데이터 안전을 같이 챙기는 게 중요합니다. 아래는 운영 중 영향 최소화를 우선한 흐름입니다.

A. 장애 직후(온라인) 상태 보존

  • DB 상태 캡처: SHOW FULL PROCESSLIST, SHOW ENGINE INNODB STATUS 결과를 파일로 저장(시간 포함)
  • 에러 로그 보존: MariaDB error log와 애플리케이션 로그의 동일 시간대 구간을 함께 보관
  • 대상 테이블/쿼리 식별: 반복 등장하는 테이블과 쿼리 패턴을 기록

B. 온라인 백업(가능하면)으로 ‘사후 복구 옵션’ 확보

  • 서비스가 간신히라도 동작 중이면, 논리 백업(mysqldump)은 락/부하를 유발할 수 있어 신중합니다.
  • 가능한 선택지는 “부하가 낮은 시간대에” 백업을 돌리거나, 백업 범위를 문제 테이블 중심으로 최소화하는 것입니다.
  • 백업 도중 대기/락이 다시 악화되면 즉시 중단하고, 먼저 원인을 완화한 뒤 재시도합니다.

C. 복구(재시작/롤백/재처리) 판단 기준

  • 단일 세션 종료로 회복: 가장 선호. 앱 오류 영향도도 상대적으로 작습니다.
  • 트랜잭션 꼬임/대량 대기 고착: 세션 정리로도 회복이 안 되면, 계획된 재시작을 고려하되 재발 방지 조치를 함께 진행
  • 데이터 정합성 우려: 장애 시점에 비정상 종료가 있었다면, 재기동 후 테이블 체크/애플리케이션 재처리(리컨실리에이션) 계획 필요

중요한 건 복구 자체보다, 복구 후에 동일한 락 경합이 다시 올라오지 않도록 쿼리/인덱스/트랜잭션 경계를 손보는 것입니다.

5) 재발 방지 튜닝 포인트: “잠금 보유 시간”을 줄이는 쪽으로

온라인 영향 최소화 관점에서 가장 효과가 큰 건 “한 번에 처리량을 늘리기”보다 잠금을 쥐는 시간을 짧게 만드는 것입니다.

  • 트랜잭션 범위 최소화: 여러 작업을 한 트랜잭션에 묶지 말고, 실패 가능성이 있는 외부 호출/파일 I/O를 트랜잭션 밖으로 분리
  • 배치 작업 분할: UPDATE/DELETE를 작은 단위로 반복 처리(커밋 주기 짧게)
  • 인덱스 점검: 조건절에 맞는 인덱스가 없으면 불필요한 범위 스캔이 늘어나 잠금 범위도 커질 수 있음
  • 일관된 접근 순서: 같은 여러 테이블을 갱신한다면, 모든 코드 경로에서 테이블 접근 순서를 통일해 deadlock 가능성을 낮춤
  • 격리 수준/락 대기 정책: 기본값을 무작정 바꾸기보다, 특정 작업의 락 대기 시간이 과도한지부터 확인

Batching and checkpoints reducing lock time in database

deadlock은 “나쁜 것”이라기보다 동시성 시스템에서 자연스럽게 생길 수 있는 현상입니다. 다만 deadlock이 잦아졌다면 대개 트랜잭션이 길거나, 같은 자원을 서로 다른 순서로 잡고 있거나, 인덱스가 부실한 쪽을 먼저 의심하는 게 맞습니다.

6) 운영 점검 리스트(현장용): 지금 바로 확인할 것들

  • 증상 확인
    • 에러 로그/앱 로그에 lock wait timeout 또는 deadlock이 있는가
    • 특정 테이블/기능에만 집중되는가
  • 원인 세션/쿼리
    • SHOW FULL PROCESSLIST에서 오래 실행/대기 중인 세션이 무엇인가
    • SHOW ENGINE INNODB STATUS에 반복 등장하는 테이블/인덱스가 있는가
    • 긴 트랜잭션(커밋이 늦는 흐름)이 있는가
  • 즉시 완화
    • 범인 세션만 종료할 수 있는가(재시작 대신)
    • 배치/정리 작업의 동시 실행 수, 작업 단위를 줄일 수 있는가
    • 앱 재시도 폭주를 일시 완화(백오프/동시성 제한)할 수 있는가
  • 백업/복구
    • 장애 시점의 프로세스/innodb status/로그를 저장했는가
    • 온라인 백업을 돌릴 때 부하/락을 더 악화시키지 않는 계획이 있는가
    • 재시작이 필요하다면, 재발 조건(배치 재가동/트래픽 유입)을 통제할 수 있는가
  • 재발 방지
    • 문제 쿼리에 맞는 인덱스가 있는가(특히 WHERE/JOIN 조건)
    • 트랜잭션 범위가 과도하게 넓지 않은가
    • 여러 테이블 업데이트 시 접근 순서가 일관적인가

마무리

Windows에서 MariaDB 잠금 이슈가 생겼을 때는 “재시작으로 일단 살린다”보다, 대기/보유 트랜잭션을 빠르게 특정하고 작은 조치로 풀어주는 것이 운영 중 영향 최소화에 더 유리합니다.

한 번이라도 lock wait timeout이나 deadlock이 장애로 번졌다면, 그 순간의 상태(SHOW ENGINE INNODB STATUS/로그/프로세스)를 남겨두는 것만으로도 다음 대응 속도가 크게 빨라집니다.