learning raphael draft 2026-05-23

채널톡 면접 D-3 — OS 동시성 + DB 트랜잭션 깊이파기

TL;DR — 5/22 락/동시성 흐름 이어받아 OS 동시성 메커니즘DB 트랜잭션·격리수준·MVCC를 한 묶음으로. 채널톡 사전 인터뷰 출제 영역(낙관/비관 락·데드락·프로세스/스레드) 정면 대응. "왜 그렇게 동작하는가" + "실 운영에서 어떤 판단을 했는가" 두 축으로 답변 라인 정리.

---

학습 순서 (3시간 블록 가이드)

블록시간주제산출물
112:00–13:00OS 동시성 메커니즘뮤텍스/세마포어/데드락 답변 라인
213:00–14:00DB 트랜잭션 ACID + 격리수준4가지 격리수준 부정합 현상 매트릭스 암기
314:00–15:00MVCC + 낙관/비관 락 DB 구현5/22 미해결 답변 라인 보강
(휴식)
416:00–18:00모의 면접 Q&ARaphael 채널에서 6문제

---

1. OS 동시성 메커니즘

1.1 뮤텍스 vs 세마포어 — 면접관이 자주 헷갈리게 묻는 포인트

항목뮤텍스 (Mutex)세마포어 (Semaphore)
본질락 (소유 개념 O)카운터 (소유 개념 X)
자원 수1개N개
해제 권한**락을 획득한 스레드만**어떤 스레드든 가능
용도임계 구역 보호자원 풀 관리, 시그널링
Java 대응`synchronized`, `ReentrantLock``Semaphore` (자바 표준)

핵심 트랩: "Binary Semaphore (count=1)는 뮤텍스와 같은가?" → 다르다. 소유 개념이 없으므로 다른 스레드가 release 가능. 뮤텍스는 락 보유자만 해제.

1.2 데드락 4가지 조건 (Coffman conditions)

1. Mutual Exclusion (상호 배제) — 자원이 한 번에 한 스레드만 점유 가능

2. Hold and Wait (점유 대기) — 자원 보유한 채로 다른 자원 대기

3. No Preemption (비선점) — 강제로 자원 회수 불가

4. Circular Wait (순환 대기) — 대기 그래프에 사이클

예방 전략 (실무):

실 케이스 답변 라인 (사전 인터뷰 출제됨)

> "JPA에서 A 엔티티 → B 엔티티 순으로 락 거는 코드와, 다른 트랜잭션이 B → A 순으로 락 거는 코드가 같이 돌아가면 데드락이 발생합니다. 해결책은 두 가지였는데, 첫째는 락 획득 순서를 ID 오름차순으로 강제해서 순환 대기를 제거했고, 둘째는 락이 필요한 트랜잭션을 짧게 쪼개서 보유 시간을 줄였습니다. MySQL은 데드락 감지가 자동이라 한쪽이 자동 롤백되긴 하지만, 빈번하게 발생하면 모니터링 알람으로 잡고 코드 레벨에서 순서를 다시 점검했습니다."

1.3 프로세스 vs 스레드 — Spring/Tomcat 맥락

면접관이 "Java/Spring 7년차"라면 일반론보다 JVM 맥락으로 답해야 가산점:

> "Tomcat의 기본 스레드 풀(max-threads=200)이 요청당 스레드 모델이고, 스레드는 JVM 프로세스 내에서 힙을 공유하므로 객체 참조를 직접 넘길 수 있는 게 장점입니다. 대신 공유 변수 접근 시 synchronizedConcurrentHashMap 같은 동기화 장치가 필요했고, 이 부분이 늘 버그의 원천이었습니다. Java 21부터 Virtual Thread가 도입되면서 I/O 바운드 작업의 컨텍스트 스위칭 비용을 줄일 수 있게 됐는데, 저희는 아직 도입 전입니다."

1.4 Context Switching 비용 — 자주 놓치는 디테일

---

2. DB 트랜잭션 — ACID + 격리수준

2.1 격리수준 4가지 × 부정합 현상 매트릭스 (필수 암기)

격리수준Dirty ReadNon-Repeatable ReadPhantom Read
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ⭕ (MySQL InnoDB는 MVCC로 거의 방지)
SERIALIZABLE

2.2 부정합 현상 — 실 시나리오로 외우기

Dirty Read (커밋 안 된 데이터 읽음)

```

T1: UPDATE balance SET amount = 0 WHERE id = 1; -- 커밋 X

T2: SELECT amount FROM balance WHERE id = 1; -- 0 읽음

T1: ROLLBACK; -- T2는 존재하지 않은 값을 봤음

```

Non-Repeatable Read (같은 행, 다른 값)

```

T1: SELECT amount FROM balance WHERE id = 1; -- 100

T2: UPDATE balance SET amount = 50 WHERE id = 1; COMMIT;

T1: SELECT amount FROM balance WHERE id = 1; -- 50 (T1 입장에선 같은 트랜잭션 안인데 결과 다름)

```

Phantom Read (조건 일치 행 수 변화)

```

T1: SELECT COUNT(*) FROM orders WHERE user_id = 1; -- 3

T2: INSERT INTO orders (user_id, ...) VALUES (1, ...); COMMIT;

T1: SELECT COUNT(*) FROM orders WHERE user_id = 1; -- 4 (없던 행이 유령처럼)

```

2.3 실무 디폴트 — Spring/MySQL

면접 트랩: "왜 SERIALIZABLE 안 쓰나?" → 모든 읽기/쓰기에 락 → 동시성 처참. 차라리 비즈니스 로직 레벨에서 낙관/비관 락 직접 제어.

---

3. MVCC + 낙관/비관 락 DB 구현

3.1 MVCC (Multi-Version Concurrency Control)

핵심 아이디어: 읽기/쓰기 충돌을 락 대신 버전 관리로 해결.

```

T1 시작 (snapshot 시점 = SCN 100)

T2: UPDATE row → 새 버전 생성, Undo Log에 SCN 99 버전 보관

T1: SELECT row → SCN 100 시점 스냅샷 (=SCN 99 버전 봄, T2 변경 안 봄)

```

InnoDB의 REPEATABLE READ가 MVCC로 구현:

3.2 낙관적 락 — DB 구현 디테일

```java

@Entity

public class Order {

@Id Long id;

@Version Long version; // JPA가 자동으로 UPDATE 시 WHERE 조건에 추가

BigDecimal amount;

}

```

5/22 미해결 답변 보강: "낙관적 락 실패 시 처리"는 다음 3가지로 갈림:

1. 즉시 사용자 에러 (충돌 빈도 낮을 때) — "다시 시도해주세요"

2. 자동 retry with backoff (재시도로 해결 가능한 멱등 작업)

3. 비관적 락으로 fallback (충돌 빈도가 임계치 넘으면 코드 경로 전환)

3.3 비관적 락 — DB 구현 디테일

```java

@Lock(LockModeType.PESSIMISTIC_WRITE)

@Query("SELECT o FROM Order o WHERE o.id = :id")

Order findByIdForUpdate(@Param("id") Long id);

```

3.4 언제 무엇을 쓰나 — 판단 기준

조건권장
충돌 빈도 < 5%낙관적 락 (성능 ↑)
충돌 빈도 > 20%비관적 락 (retry 비용 ↑)
결제·재고 차감비관적 락 또는 idempotency key
분산 환경 (여러 서비스)별도 코디네이션 (Redis lock, DB transaction outbox)
단일 DB 내DB 락이 가장 깔끔

5/22 후속: Redis lock은 분산 코디네이션 용도지, 단일 DB 내 동시성 제어용이 아니다. 자세한 시나리오는 [Redis 분산락 + DB 트랜잭션 분리 시 정합성 문제](2026-05-22-redis-lock-db-commit-mismatch.html) 참조.

---

4. 내일 (5/23) 모의 면접 예상 질문 6개

Raphael 채널에서 순서대로 진행. 각 질문 후 답변 → 드릴다운.

Q1. 뮤텍스와 세마포어의 차이를 면접관이 처음 듣는 사람처럼 설명해보세요.

답변 라인: 소유 개념 차이 → 해제 권한 차이 → 용도 차이 (자원 보호 vs 시그널링).

Q2. 운영 중인 서비스에서 데드락이 발생했다는 알람이 왔다. 어떻게 진단하고 해결하시겠습니까?

답변 라인: 1) DB 로그에서 데드락 victim 트랜잭션 확인 → 2) 락 획득 순서 분석 → 3) 코드 레벨에서 ID 오름차순 락 또는 tryLock 도입 → 4) 모니터링 알람 임계치 설정.

Q3. REPEATABLE READ에서 Phantom Read가 발생하는 시나리오를 코드로 설명하시겠습니까?

답변 라인: 표준 SQL 정의로는 발생 가능. 단, MySQL InnoDB는 MVCC + Gap Lock으로 거의 방지. 표준과 실제 구현 차이 짚어야 가산점.

Q4. 낙관적 락을 쓰다가 충돌이 빈번해졌다. 비관적 락으로 바로 갈아탈 것인가?

답변 라인: 우선 충돌률 측정 → 임계치(예: 20%) 넘으면 전환 검토 → 단, 단순 전환 대신 로직 분리(낙관 우선 + N회 retry 후 비관 fallback) 또는 트랜잭션 범위 축소도 옵션.

Q5. MVCC에서 트랜잭션이 길게 열려있으면 어떤 문제가 발생하나요?

답변 라인: Undo Log 누적 → 디스크 부하 ↑ + 다른 트랜잭션의 read view 길어짐 → 장기 트랜잭션 회피, 읽기 전용 분리, 배치 작업 청크 단위.

Q6. Redis 분산락 vs DB 비관적 락 — 단일 DB 환경에서 어느 쪽을 추천하시겠습니까?

답변 라인: 단일 DB면 DB 비관적 락 (트랜잭션 경계 자동 일치). Redis는 분산 환경에서만 필요. 5/22 미해결 시나리오 답변 라인 그대로 인용 가능.

---

복습 일정

단계날짜완료
Day 0 (초학습)2026-05-23
Day 72026-05-30
Day 372026-06-29
Day 1272026-09-27

참고