Debian에서 MySQL/MariaDB가 갑자기 느려지고 “락이 걸린 것 같다”는 제보가 들어오면, 당장 재시작으로 덮기보다 원인(누가/무엇을/얼마나 오래 잠그는지)를 먼저 좁히는 게 안전합니다. 이 글은 운영 중 영향 최소화를 전제로, phpMyAdmin을 보조로 쓰되 핵심은 서버에서 확인하는 방식으로 정리했습니다.

Chained padlock around database symbolizing lock contention

진단과 완화는 빠르게, 백업/복구는 더 보수적으로 진행합니다.

1) 먼저 안전장치: 변경 전 백업 + 복구 리허설 포인트

락 이슈를 만지다 보면 인덱스를 추가하거나 격리 수준을 바꾸는 등 “변경”이 뒤따르는 경우가 많습니다. 변경 전에 아래 3가지를 최소 안전장치로 잡아두면, 상황이 악화돼도 되돌아갈 수 있습니다.

  • 백업 종류를 2겹으로: (1) 논리 백업(mysqldump) + (2) 물리/스냅샷(가능하면 LVM/VM snapshot 등). 둘 중 하나만으로는 불안합니다.
  • 복구 리허설 1회: 별도 테스트 DB(또는 임시 인스턴스)에 dump를 실제로 import 해 “복구가 되는 백업”인지 확인합니다.
  • 작업 전 체크포인트: 현재 실행 쿼리/락 상태를 캡처(스크린샷이 아니라 텍스트로)해두면, 변경 후 비교가 쉬워집니다.

mysqldump 기준으로는 스토리지 엔진이 InnoDB일 때 보통 --single-transaction을 사용해 일관성을 확보합니다(DDL이 동시에 돌면 일관성이 깨질 수 있으니 변경 작업과 백업은 시간을 분리하는 게 안전합니다).

Vault protecting database backup and restore safety

2) 증상 구분: “락 대기”인지 “CPU/IO 병목”인지 먼저 갈라보기

락처럼 보이지만 실제로는 IO 병목이나 커넥션 폭증이 원인인 경우가 있습니다. 아래처럼 2~3분만 투자해 1차 분류를 하세요.

  • 락/대기 신호: 응답이 멈춘 듯하지만 CPU는 아주 높지 않고, 특정 테이블 작업에서만 지연이 몰립니다.
  • IO 병목 신호: 디스크 대기가 크고(서버 모니터링에서 iowait 상승), 대부분의 쿼리가 전반적으로 느려집니다.
  • 커넥션 문제 신호: “Too many connections” 또는 커넥션이 쌓이며 새로운 요청이 못 들어옵니다(락이 아니라 세션 관리 이슈).

락을 다루는 글이지만, 1차 분류를 건너뛰면 엉뚱한 처방(예: 무작정 인덱스 추가, 재시작 반복)으로 장애 시간이 늘어납니다.

3) phpMyAdmin으로 빠르게 보는 포인트(보조 도구로만)

phpMyAdmin은 “원인 추적의 시작점”으로는 좋지만, 화면에 보이는 정보가 제한적일 수 있습니다. 그래도 아래는 빠르게 훑기 좋습니다.

  • Processlist: 오래 도는 쿼리(특히 UPDATE/DELETE/ALTER)와 “Locked / Waiting” 류 상태를 찾습니다.
  • 동일 쿼리 반복: 같은 패턴의 쿼리가 다수 쌓이면 애플리케이션 쪽 재시도/타임아웃 설정도 의심합니다.
  • 특정 계정/호스트 집중: 한 사용자/호스트에서만 몰리면 배치 작업, 크론, 관리자 페이지 기능을 우선 확인합니다.

중요: phpMyAdmin에서 보이는 “kill”은 신중해야 합니다. 락 홀더(잠그는 쪽)를 끊으면 빠르게 풀릴 수 있지만, 애플리케이션 트랜잭션이 롤백되면서 더 큰 부하가 생길 수도 있습니다. 가능하면 서버에서 “대기/홀더 관계”를 먼저 확인하세요.

4) 서버에서 락 원인 좁히기: 대기(Waiting)와 홀더(Blocking) 매칭

락 이슈는 결국 누가(blocking) 무엇을 잡고 있고, 누가(waiting) 얼마나 기다리는지를 매칭하는 싸움입니다. MySQL/MariaDB 버전에 따라 사용 가능한 뷰가 조금씩 다른데, 일반적으로는 performance_schema / information_schema를 활용합니다.

  • 대기 시간 상위를 찾고(대기 이벤트/대기 트랜잭션),
  • 해당 대기가 어떤 쿼리와 연결되는지 확인한 뒤,
  • 그 쿼리를 막고 있는 홀더 트랜잭션을 찾습니다.

이 단계에서 흔히 나오는 패턴은 아래와 같습니다.

  • 긴 트랜잭션(autocommit 꺼짐): 웹 요청 하나가 트랜잭션을 열어둔 채로 오래 유지되어 다른 변경을 막습니다.
  • 인덱스 부족으로 큰 범위 잠금: 조건이 비효율적이면 의도보다 훨씬 많은 레코드를 건드려 락 범위가 커집니다.
  • 배치/정리 작업 충돌: 야간 배치 UPDATE/DELETE가 평소보다 늦게 시작해 주간 트래픽과 겹칩니다.
  • DDL(ALTER) 영향: online DDL이라도 메타데이터 락 등으로 짧게/길게 영향을 줄 수 있습니다.

Interlocked database rings representing blocking and waiting locks

5) 운영 중 완화(응급처치) → 근본 개선(재발 방지) 순서

락이 이미 심하면 “완화”와 “개선”을 분리하는 게 좋습니다. 응급처치를 하면서 동시에 큰 변경(스키마 개편)을 하면 변수만 늘어납니다.

  • 응급처치(완화)
    • 문제 쿼리/트랜잭션이 명확하고 영향이 큰 경우에만, 홀더 세션을 종료하는 것을 검토합니다(종료 시 롤백 비용 고려).
    • 배치/관리자 작업이라면 즉시 중지하고, 재실행은 부하가 낮을 때로 미룹니다.
    • 애플리케이션에서 재시도 폭탄이 발생 중이면 재시도 간격(backoff)과 타임아웃을 임시로 완화해 “동시 대기”를 줄입니다.
  • 근본 개선(재발 방지)
    • 문제 쿼리의 WHERE/조인 조건에 맞는 인덱스 검토(특히 범위 조건 + 정렬/그룹핑).
    • 트랜잭션 범위 축소: 사용자 입력/외부 API 호출을 트랜잭션 안에서 하지 않도록 코드 경계를 조정.
    • 대량 UPDATE/DELETE는 청크 단위(예: id 범위로 나눠 짧게 커밋)로 변경.
    • 격리 수준/락 옵션은 최후 수단: “왜 필요한지”가 명확할 때만 조정하고, 변경 전후를 측정합니다.

특히 인덱스 추가는 효과가 큰 편이지만, 테이블 크기/버전에 따라 작업 시간이 길고 락 영향이 생길 수 있습니다. 그래서 아래 ‘점검 리스트’를 먼저 통과시키고 진행하는 편이 안전합니다.

6) 백업/복구 절차 + 점검 리스트(작업 전/중/후)

락 개선 작업(인덱스/쿼리 수정/배치 변경)은 “고치다가 더 큰 락”을 만들 수 있습니다. 아래 체크리스트대로 진행하면, 사고가 나도 복구가 가능한 상태를 유지할 수 있습니다.

  • 작업 전(필수)
    • 최근 백업이 실제로 복구되는지: 테스트 환경에 import 확인
    • 변경 대상 테이블 용량/행 수 파악(작업 시간 추정)
    • 현재 대기/락 상태 캡처(비교 기준 확보)
    • 롤백 계획 문장으로 적기: “무엇을 되돌릴지, 어디서 백업을 가져올지”
  • 작업 중
    • 변경은 1개씩: 인덱스 3개를 한 번에 넣지 말고 효과를 확인하며 단계적으로
    • 모니터링: 대기/락 지표, 응답시간, 오류율을 동시에 확인
    • 작업이 길어지면: 트래픽 낮은 시간으로 연기(중단/재개 전략)
  • 작업 후
    • 재현 쿼리로 검증: 개선 전/후 실행시간 비교(최소 3회)
    • 락 대기 재발 여부 확인: 피크 타임에 다시 지표 확인
    • 백업 정책 점검: 락 이슈를 만든 배치/테이블이 백업/복구 범위에서 빠져있지 않은지 확인

마무리

Debian에서 MySQL/MariaDB 락 문제는 “락을 풀었다”로 끝나지 않고, 왜 그 락이 생겼는지(긴 트랜잭션, 인덱스 부족, 배치 충돌)를 줄여야 재발이 멈춥니다.

진단은 빠르게 하되, 변경은 백업/복구 안전장치를 먼저 걸어두고 한 단계씩 진행하면 운영 리스크를 크게 낮출 수 있습니다.