
둘 이상의 프로세스, 스레드, 또는 작업이 한정된 동일 자원을 동시에 사용하려고 다투는 상태
공유 자원(Shared Resource)이란 동시에 실행되는 프로세스들이 공동으로 접근하여 사용하는 자원을 의미한다. 전역 변수(예: '잔액', '총합')와 같은 데이터뿐만 아니라 파일, 입출력장치, 보조기억장치 등의 하드웨어 및 시스템 자원까지 포함한다.
여러 프로세스가 이러한 공유 자원에 동시에 접근해 읽고 쓸 때 접근 순서에 따라 결과가 달라지는 동시성 문제가 발생할 수 있다. 따라서 공유 자원에 접근하는 코드 영역 중 동시에 실행해서는 안 되는 영역을 임계 구역(Critical Section)으로 설정하고, 상호 배제(Mutual Exclusion)를 통해 보호해야 한다.
| Lock 종류 | 작동 방식 | 주요 특징 및 적합한 상황 |
|---|---|---|
| Mutex | 단일 스레드 전용 점유 | 소유권 개념이 존재하며, 락을 획득한 스레드만 해제 가능하다. |
| Semaphore | 카운터 기반 N개 접근 허용 | 설정한 수만큼 동시 접근을 허용한다. Mutex는 Binary Semaphore의 특수한 형태다. |
| Spinlock | 대기 중 지속적 CPU 점유 (Busy-wait) | Context Switching 비용보다 대기 시간이 짧을 때 유리하다. 대기가 길어지면 CPU 낭비가 극대화된다. |
| Read-Write Lock | 읽기 공유 / 쓰기 단독 배타 접근 | 읽기 작업이 많고 쓰기 작업이 적은 워크로드에서 경합을 줄이는 데 효과적이다. |
⚠️ 락 경합이 심화될 때 나타나는 시스템 병목 현상
| 구분 | 보호 범위 | 장점 | 단점 |
|---|---|---|---|
| Coarse-grained Lock | 넓은 범위 (예: 테이블 전체) | 구현이 단순하다. | 동시성이 떨어지고 경합 가능성이 높다. |
| Fine-grained Lock | 좁은 범위 (예: Row, Page) | 경합이 줄어들고 동시성이 향상된다. | 락 관리 오버헤드와 구현 복잡도가 증가한다. |
락을 얼마나 잘게 쪼개느냐가 동시성(Concurrency)과 오버헤드 사이의 트레이드오프를 결정하는 핵심 설계 지점이다.
시스템이 가진 메모리, CPU, 디스크 공간, 네트워크 대역폭 등의 제한된 자원이 과도하게 소모되거나 반환되지 않아 더 이상 정상적인 작업을 수행할 수 없는 상태다.
| 구분 | 주요 현상 | 원인 및 메커니즘 |
|---|---|---|
| 메모리 고갈 (OOM) | Heap 공간 부족으로 프로그램이 강제 종료된다. | 자원 누수(Resource Leak), 무한 루프 또는 과도한 재귀 호출로 인해 메모리가 계속 점유된다. |
| File Descriptor 고갈 | OS의 최대 파일 오픈 개수를 초과하여 새 파일이나 소켓을 열지 못한다. | 사용이 끝난 파일 핸들이나 소켓을 시스템에 정상적으로 반환하지 않는 코드 결함이 원인이다. |
| Port 고갈 | 네트워크 연결에 필요한 Ephemeral Port가 모자라 통신 불능 상태가 된다. | 대량의 연결 요청이 몰리거나(DoS/DDoS), Connection Pool 미사용 및 CLOSE_WAIT/TIME_WAIT 상태 적체로 발생한다. |
상호 연결된 분산 시스템이나 구조에서 하나의 구성 요소가 고장 났을 때, 그 여파가 인접 서비스로 파급되어 전체 시스템이 차례대로 마비되는 현상이다.
지연 증가 ──> 점유시간 증가 ──> Thread Pool 고갈 ──> 대기 적체 ──> 타임아웃/재시도 ──> 부하 증폭 ──> 상위 서비스 전파
작은 지연이 자원 점유 시간을 늘리고, 이는 Thread Pool 고갈과 대기 적체로 이어진다. 결과적으로 타임아웃에 따른 재시도 폭주(Retry Storm) 현상이 발생하여 부하가 증폭되고 상위 서비스로 장애가 전파된다.
여러 독립적인 작업이 하나의 공유 자원이나 상태를 사용하고 있습니다. 특정 작업 하나에서 부하가 발생하자 관계없는 다른 작업들까지 함께 느려졌습니다. 왜 이런 현상이 발생할 수 있고, 영향 범위를 줄이기 위해 어떻게 설계하시겠습니까? 각자의 도메인에 맞춰 설명해주세요.
특정 작업의 부하가 공유 자원을 둘러싼 자원 경합과 자원 고갈을 유발하고, 이것이 대기열을 타고 전파되면서 시스템 전체의 연쇄 장애로 이어집니다.
// 저는 요즘 DB 유지보수에 관심이 있고, 그중에서도 엔진 레벨에서 자원과 락을 직접 제어할 수 있는 MS SQL Server 기반 환경에 마음이 갑니다.
MS SQL Server 환경에서 대량의 데이터를 일괄 처리할 때 행 단위 잠금이 테이블 잠금으로 자동 승격되면, 작업과 무관한 트랜잭션까지 대기 상태에 빠지며 선두 차단 현상이 발생합니다.
선두 차단 현상은 앞선 요청이 잠금으로 인해 처리되지 못하면서, 그 뒤의 요청들까지 연쇄적으로 진행하지 못하고 대기하게 되는 현상입니다.
이 현상이 장기화되면 데이터베이스 연결 자원이 고갈되고 스레드 풀 고갈과 재시도 폭주로 이어져 결국 상위 서비스 전체에 연쇄 장애를 일으키게 됩니다.이를 해결하기 위해 리소스 관리자로 배치 작업의 CPU와 메모리 사용량을 제한하여 시스템 영향을 최소화하고, 읽기 커밋된 스냅숏 격리(RCSI)를 적용해 읽기 작업이 잠금 대기 없이 tempdb에 저장된 행 버전 정보를 읽도록 하겠습니다.
DB를 잘 치는 것은 아니지만, 도메인 및 답변 중복을 간만에 없애기 위해 DBA 관점의 답변을 준비하였다.
대량의 데이터를 일괄 처리할 때 행 단위 잠금을 많이 잡으면 SQL 서버가 이를 테이블 잠금으로 자동 승격시킬 수 있습니다. 많은 행에 각각 잠금을 유지하는 것보다 하나의 넓은 범위로 관리하는 것이 잠금 관리 비용을 줄일 수 있기 때문입니다. 하지만 이 경우 개별 행이 아닌 테이블 전체에 가까운 범위가 잠기면서, 배치 작업과 관계없는 다른 트랜잭션(작업범위)까지 잠금을 기다리게 됩니다.