경로를 계층별로 끊어 설명한다
요청이 브라우저에서 출발해 DB의 한 행에 닿았다가 돌아오는 경로를 계층별로 끊어 설명하고, 각 계층의 실패 모드를 안다.
LEVEL 2실무 백엔드 · 교재 안내서 · 공통 랩 + 전 11단계 공개
금융 서비스(모의 증권사 MiniTrade)를 이름·인증서·프록시·워커·브로커·배포·관측·보안이 있는 실제 운영 환경에 올리고, 일부러 깨뜨리고, 복구한 기록을 남기는 과정입니다. Level 1이 “요청 한 번이 DB에 무엇을 시키는가”를 숫자로 설명하게 했다면, Level 2는 DB 바깥의 계층을 같은 방식으로 채우고 둘을 하나의 서비스에서 잇습니다.
로드맵이 8년차 백엔드 팀장에게 기대하는 능력은 프레임워크 API 목록이 아니라 세 가지입니다. 이 교재의 모든 단계는 이 셋을 내 손으로 재현한 기록을 남기는 것으로 끝납니다.
요청이 브라우저에서 출발해 DB의 한 행에 닿았다가 돌아오는 경로를 계층별로 끊어 설명하고, 각 계층의 실패 모드를 안다.
무엇이 구버전·신버전과 동시에 살아 있어도 되는지 구분해 무중단 배포 절차를 설계한다.
장애 상황에서 원인 가설을 좁히는 순서가 있고, 그 순서가 로그·메트릭·트레이스로 뒷받침된다.
Level 1의 “실측만”에 더하는 것
정상 동작만 확인한 것은 통과가 아니다. 단계마다 사고_재현.md에 최소 세 건 — 재현 → 사용자가 보는 증상 → 진단 명령 → 완화·복구 → 재발 방지.
기본값을 썼더라도 그 값이 왜 안전한지 설계_기록.md에 적는다. 예: proxy_read_timeout이 왜 gunicorn timeout보다 길어야 하는가.
저장소 · 실행 가능한 구성(compose) · 한 장짜리 설계 기록으로 남긴다. 화면 캡처나 기억은 산출물이 아니다.
원전 로드맵의 표 — 이 교재가 겨냥하는 차이
| 질문 | 프레임워크 수준 | 실무 수준 |
|---|---|---|
| 배포는 어떻게? | git push하면 플랫폼이 빌드해서 올려 준다 | 이미지 태그를 커밋 SHA로 고정하고, 스키마 마이그레이션을 배포와 분리된 선행 단계로 돌리며, readiness를 통과한 인스턴스만 로드밸런서에 편입하고, 실패 시 이전 태그로 되돌린다 |
| CORS 에러가 난다 | CORS_ALLOW_ALL_ORIGINS = True | credentials 요청에선 *를 못 쓰니 허용 목록에 있는 오리진만 그대로 반사하고, Vary: Origin으로 CDN이 다른 오리진의 응답을 재사용하지 않게 한다 |
| 왜 도메인을 사나 | 주소가 보기 좋으니까 | 인스턴스 교체·스케일아웃마다 IP가 바뀌고, TLS 인증서는 이름에 발급되며, 쿠키 스코프·CORS 오리진·OAuth 리디렉트 URI가 전부 호스트명 기준으로 판정된다 |
| 응답이 느리다 | 캐시를 붙인다 | 평균이 아니라 p99를 보고, 지연 구간이 DB인지 외부 API인지 이벤트 루프 대기인지 트레이스로 가른 뒤, 쿼리라면 실행계획으로 인덱스 선택과 스캔 행 수를 확인한다 |
| 서버가 죽었다 | 재시작한다 | OOM인지 헬스체크 실패인지 배포 직후인지 먼저 가르고, 완화(롤백·트래픽 차단·스케일)를 복구보다 먼저 집행한 뒤 원인 분석은 정상화된 다음에 한다 |
Level 2의 모든 실습은 오른쪽 답을 내 손으로 재현한 기록을 남기는 것으로 끝납니다.
Level 1은 세 능력의 “DB 쪽 절반”을 측정으로 익혔습니다. Level 2는 DB 바깥의 계층 — 이름·TLS·HTTP·브라우저·앱 서버·브로커·배포·관측·규제 — 을 같은 방식으로 채우고, 둘을 하나의 서비스에서 잇습니다.
*.test·Pebble·Nginx 캐시·시뮬레이터) + 실제 도메인으로 하는 실전 트랙칩을 누르면 Level 1 안내서의 해당 퀘스트로
| 단계 | Level 1에서 이미 한 것 | Level 2에서 새로 하는 것 |
|---|---|---|
| 1. 도메인·DNS·TLS | Q12 자체 서명 인증서와 --cacert | 이름 해석 경로·TTL·부정 캐싱, ACME 발급·갱신·체인, 프록시 뒤 TLS 종료, mTLS |
| 2. HTTP·쿠키·CORS·인증 | Q06 JWT·리프레시 회전·재사용 탐지, Q11 상태코드·에러 봉투, D4 세션, D6 CSRF | 오리진·프리플라이트·Vary: Origin, 쿠키 속성과 eTLD+1, CSRF 공격 재현, 조건부 요청, CDN 캐시 사고 |
| 3. 앱 서버·동시성 | Q05 풀, Q09 이벤트 루프 vs 스레드, Q13 graceful·liveness/readiness, Q14 GIL 포화 | gunicorn 워커 종류·수의 역산, 타임아웃 사다리, 부하 중 무중단 재기동, 워커 RSS |
| 4. 데이터 계층 | Q01~Q04 실행계획·N+1, F1 금액·원장, F2 데드락, F3 멱등, O1 expand–contract, H2 경합 | PostgreSQL로 다시: MVCC·VACUUM, 격리 수준과 재시도, 이중 시간축, 1,000만 행 튜닝, 파티셔닝, pgbouncer |
| 5. 실시간·웹소켓 새 영역 | (없음 — 완전히 새 영역) | 시세 게이트웨이, 스냅샷+증분 시퀀스, heartbeat, 컨플레이션, 재연결 폭주, 1만 연결 |
| 6. 비동기·멱등성 | Q10 DB 잡 큐·SKIP LOCKED, D3 큐, F3 멱등 키, H3 아웃박스·멱등 소비자 | 브로커 선택(Redis·RabbitMQ·Kafka), DLQ 운영, 사가와 홀드 만료, 재실행 가능한 마감 배치, 분산 락 |
| 7. 배포·CI/CD | Q13 Dockerfile·compose·CI 게이트, O1 마이그레이션, O3 경계 검사 | SHA 태그·이미지 승격, 블루그린·카나리, 롤백 1분, 마이그레이션 분리, 기능 플래그, IaC |
| 8. 관측성·장애대응 | Q07 구조화 로그·trace↔SQL_ID, O2 traceparent·RED, H1 대기 분해, F5 Server-Timing | SLO와 에러 버짓, 증상 기반 알림, 장애 지휘 절차, 포스트모템, 외부 기관 대사 |
| 9. 보안·금융 규제 | Q12 SQLi·IDOR·레이트리밋, D6 보안 헤더, F1 append-only 권한, F4 해시 체인 | 위협 모델, SSRF, 컬럼 암호화 + 블라인드 인덱스, 조회 감사, 공급망 스캔, 망분리 제약 |
| 10. 아키텍처·팀 리드 | O3 모듈 경계·포트/어댑터, 졸업 리포트 | 분리 기준과 비용, 계약 테스트, 용량·원가 산정, ADR, 리뷰 체크리스트, 온보딩 측정 |
모든 단계는 같은 네 부분 — 알아야 할 것, 사고가 나는 지점, 실습 과제, 통과 기준 — 을 갖습니다. 7단계 이후는 앞에서 만든 서비스가 실제로 배포되어 있어야 의미가 생깁니다.
카드를 누르면 펼쳐집니다 · L1 칩은 Level 1 안내서로 · 상태: 설계 / 집필 중 / 공개
Level 1의 문서 5종 + app/에 해당하는 Level 2의 구성
| 파일 | 내용 |
|---|---|
가이드.md | 알아야 할 것(개념) · Level 1 연결 · Oracle 대조 박스 · 사고가 나는 지점 · 통과 기준 |
실습.md | 실습 과제별 명령과 실제 출력(실측) |
사고_재현.md | 사고마다: 재현 → 증상 → 진단 명령 → 완화·복구 → 재발 방지 |
측정_기록.md | 전/후 표, 환경·버전·이미지 다이제스트 |
설계_기록.md | 이 단계에서 고른 설정값과 근거(기본값이 왜 안전한가) — 한 장짜리 ADR 형식 |
실전_트랙.md | 실제 도메인·VM·클라우드에서 할 일과 기록 양식 |
자가점검.md | 플립러닝 질문(①설명 ②근거 ③판단) + 우리의 답변 + 면접 “얕은 답 / 깊은 답” |
lab/ | 그 단계 시점의 실행 가능한 스냅샷(compose · 앱 코드 · 스크립트) — Level 1의 app/과 같은 방식 |
Level 1이 주문 백엔드 하나를 세 번 관통했듯, Level 2는 모의 증권사 백엔드 하나를 10단계 내내 키웁니다. 종합 산출물 3종이 이 서비스의 세 얼굴입니다.
모든 자금 이동은 이중부기(차변·대변 쌍, 합 0). 잔고는 원장에서 파생한다.
주문은 멱등하게(거래 고유번호 UNIQUE), 체결은 외부 거래소가 통보, 포지션은 체결에서 파생.
공개 거래소 웹소켓(실연결) + 시퀀스·구멍·속도를 조절할 수 있는 로컬 시세 시뮬레이터.
시각과 별개의 값으로 저장. 마감 배치와 대사는 거래일을 인자로 받는다.
거래소(주문 접수·체결 통보·지연·장애 주입), 은행/PG(입출금, mTLS 연계). 대사의 상대편.
실시간 시세·포트폴리오 서비스, 주문·정산 백오피스, 운영 증거 저장소.
흐름: 브라우저 —HTTPS→ Nginx → Django / 게이트웨이 · Django → pgbouncer → PostgreSQL · Django → RabbitMQ → 워커 → PostgreSQL · 워커 —mTLS→ 외부 기관 · 공개 거래소 WS → 게이트웨이 → Redis pub/sub
도메인은 RFC 6761이 예약한 *.test — 랩 DNS가 답한다
| 호스트 | 용도 |
|---|---|
minitrade.test | apex — CNAME 불가 실습, CAA·MX |
app.minitrade.test | SPA(정적) |
api.minitrade.test | Django API |
admin.minitrade.test | 백오피스(세션 분리·권한·감사) |
ws.minitrade.test | 시세 게이트웨이 |
cdn.minitrade.test | CDN 역할 Nginx(proxy_cache) — 캐시 오염·개인화 응답 사고 |
partner.test | 대외기관(거래소·은행 시뮬레이터) — mTLS |
evil.test | 공격자 사이트 — CSRF·CSWSH 재현 |
모든 실습은 Docker로 재현하고 수치까지 직접 잽니다. 실제 인터넷이 있어야만 하는 부분은 절차로 남겨 학생이 자기 도메인으로 하고, 그 수치는 교재가 대신 재 주지 않습니다.
*.test, 이름 해석은 랩 DNS(권한 서버 + 재귀 리졸버)proxy_cache, 외부 기관은 시뮬레이터, 장애는 주입 프록시로lab-shell 컨테이너 — 호스트 설정·인증서 저장소는 건드리지 않는다실전_트랙.md — 결과를 로컬 실측과 나란히 적는다2026-10-06 · 설계서 §4.1
| 항목 | 결과 |
|---|---|
| Docker | Docker Desktop 29.8.1(linux/amd64), CPU 32 · 메모리 약 15.4GiB |
| 리눅스 셸 | WSL 배포판 없음 → 실습용 리눅스 셸은 컨테이너(lab-shell: dig·ss·lsof·openssl·psql·redis-cli·curl·jq)로 제공 |
| 이미지 가용성 | postgres:18(19 없음) · redis:8 · nginx:1.29 · ghcr.io/letsencrypt/pebble · certbot/certbot · coredns/coredns · klutchell/unbound · grafana/k6 · grafana/otel-lgtm · rabbitmq:4-management · redpandadata/redpanda · python:3.13-slim/3.14-slim · edoburu/pgbouncer · zricethezav/gitleaks · aquasec/trivy · hashicorp/terraform · registry:2 · ubuntu:24.04 모두 확인 |
| 로컬 ACME 발급 | CoreDNS(minitrade.test 권한 존) + Nginx(webroot) + Pebble + certbot으로 HTTP-01 발급 성공. fullchain = 인증서 2장(리프+중간), 주체(Subject)는 비어 있고 이름은 SAN에만, 유효기간 6일(Pebble 기본 프로필), 리프에 AIA 필드 없음 |
| 함정(실측) | Pebble 기본 HTTP-01 포트는 5002 → 설정에서 80으로. Pebble은 상태를 메모리에 두므로 재시작하면 certbot에 저장된 계정이 “not found” |
| 공개 시세 웹소켓 | Upbit(trade, KRW-BTC·ETH) 5초에 67건(연결 63ms), Binance(btcusdt@trade) 5초에 355건(연결 114ms) — 실연결 실습 가능 |
결론: 1~10단계의 로컬 실습은 모두 Docker 위에서 성립한다. 단, “중간 인증서 누락을 브라우저가 AIA로 보완” 실습은 Pebble 인증서에 AIA가 없으므로 openssl로 만든 자체 CA(AIA 포함)로 따로 구성한다.
| 주제 | Oracle(Level 1) | PostgreSQL(Level 2) |
|---|---|---|
| 실행 통계 | DISPLAY_CURSOR(ALLSTATS LAST), Buffers | EXPLAIN (ANALYZE, BUFFERS), shared hit/read |
| SQL 누적 지표 | v$sql, SQL_ID | pg_stat_statements, queryid |
| MVCC | undo로 과거 버전 재구성 | 힙에 행 버전이 쌓임 → VACUUM·bloat |
| 격리 수준 | SERIALIZABLE = 스냅샷 | REPEATABLE READ = 스냅샷, SERIALIZABLE = SSI(직렬화 실패 → 재시도) |
| 데드락 | ORA-00060, 문장 하나 롤백 | deadlock_timeout(1s) 뒤 탐지, 트랜잭션 하나 중단 |
| 온라인 인덱스 | CREATE INDEX … ONLINE | CREATE INDEX CONCURRENTLY(실패하면 INVALID 인덱스가 남는다) |
| DDL 대기 | DDL_LOCK_TIMEOUT | lock_timeout + 잠금 대기열(뒤의 모든 쿼리가 줄을 선다) |
| NOT NULL 무중단 | ENABLE NOVALIDATE → VALIDATE | CHECK … NOT VALID → VALIDATE CONSTRAINT |
| 빈 문자열 | NULL로 저장 | 빈 문자열 그대로 |
| 금액 타입 | NUMBER(p,s) | NUMERIC(p,s) |
| 커넥션 | 세션 = 서버 프로세스, DRCP | 연결 = 백엔드 프로세스, pgbouncer |
| 행 수준 접근통제 | VPD | Row Level Security |
| 감사 | Unified Auditing | pgaudit / 앱 감사 테이블 |
| 항목 | 기본안 | 바꿀 조건 |
|---|---|---|
| 실시간 게이트웨이 | FastAPI + websockets | Django Channels 비교 실습을 추가할지 |
| 작업 큐 | Celery + RabbitMQ | 단순성을 우선하면 Arq + Redis |
| 키 관리(KMS 대체) | OpenBao(오픈소스 Vault 포크)의 transit 엔진 | 원조 Vault를 쓰고 싶다면 hashicorp/vault(BUSL 라이선스) |
| GitHub Actions | 워크플로 파일 + 실전 트랙에서 실제 실행 | 저장소를 GitHub에 올리면 교재가 직접 실행 결과를 싣는다 |
| 장애 주입 | Toxiproxy — 지연·끊김·대역 제한을 API로 주입 | — |
| 권한 DNS | BIND 9.20 — 위임·TSIG 동적 갱신(DNS-01) | 단순 존만 필요하면 CoreDNS |
| 로컬 TLS 등급 | testssl.sh(SSL Labs 대체) | — |
| 컨테이너 안 브라우저 | chromedp/headless-shell 또는 zenika/alpine-chrome — 랩 루트 CA를 컨테이너 안에서만 신뢰 | — |
기술 목록은 검증되지 않지만, 운영해 본 시스템 하나는 검증됩니다. 세 산출물이 각각 다른 종류의 능력을 증명합니다.
공개 거래소 웹소켓을 정규화해 저장과 동시에 재배포하고, 보유 종목의 실시간 평가액과 목표가 알림을 준다.
완성 기준(측정치로)연속 운영 기록, 강제 단절 후 복구 시간, 동시 연결 1,000 이상에서 p99, 시퀀스 검사로 유실 0
주문을 멱등하게 받고, 체결을 반영하고, 이중부기 원장으로 기록하고, 마감 배치로 정산하고, 대사 리포트를 낸다. 관리자 화면엔 권한 분리와 감사 로그.
완성 기준(측정치로)중복 요청 1,000건 주입 후 원장 합계 일치, 마감 배치 3회 재실행 동일, 의도적 누락이 대사에서 자동 탐지
두 서비스를 돌리는 인프라와 절차 — IaC, CI/CD, 대시보드, 런북, 포스트모템, ADR.
완성 기준(측정치로)롤백 1분 이내 측정 기록, 장애 훈련 포스트모템, ADR 5건, SLO·에러 버짓 대시보드
로드맵의 “24시간 연속 운영”은 로컬 랩에서 실제로 24시간 돌려 기록합니다. 기간을 줄여야 하면 줄인 값과 이유를 함께 적습니다.
주 10~15시간 기준 · 단계를 넘기는 기준은 기간이 아니라 통과 기준
| 월차 | 단계 | 끝날 때 남아 있어야 하는 것 |
|---|---|---|
| 1 | 1단계 | 도메인 + HTTPS로 동작하는 서버 1대, TTL 전환 측정 기록 |
| 2 | 2단계 | 별도 오리진 SPA + 쿠키 인증 API, CSRF 공격·방어 재현 기록 |
| 3 | 3단계 | 워커 설정별 p99 비교표, 배포 중 요청 유실 0 검증 |
| 4–5 | 4단계 | 주문·체결·원장 스키마, 1,000만 행 조회 튜닝 기록, 무중단 마이그레이션 리허설 |
| 6–7 | 5단계 | 산출물 1(실시간 시세 서비스) 동작, 복구 시간과 부하 측정치 |
| 8 | 6단계 | 멱등 파이프라인, DLQ 운영 절차, 재실행 가능한 마감 배치 |
| 9 | 7단계 | CI/CD 파이프라인과 롤백 1분 측정 기록 |
| 10 | 8단계 | 트레이싱 적용, SLO 대시보드, 장애 훈련 1회와 포스트모템 |
| 11 | 9단계 | 위협 모델 1장, 감사 로그, 산출물 2(주문·정산) 완성 |
| 12 | 10단계 | ADR 5건, 용량·비용 산정서, 산출물 3(운영 증거), 글 3편 |
로드맵의 기준 배분(합 11시간)
기록을 빼면 12개월 뒤에 말할 것이 남지 않습니다. 깨뜨리는 시간을 빼면 지식은 늘지만 경험은 늘지 않습니다.
설계 → 집필 중(실측·사고 재현·학생 따라하기 검증) → 공개
로드맵에 들어 있는 날짜·수치 주장은 그대로 옮기지 않습니다. 설계 단계(2026-10-06)에 먼저 확인한 것과 집필 때 확인할 것입니다.
| 주장 | 판정 | 확인 결과 | 출처 |
|---|---|---|---|
| 공개 TLS 인증서 유효기간 단계 축소(398 → 47일) | 맞음 | Ballot SC081v3 채택(인증서 발급자 25표·브라우저 4표 찬성), 2026-03 시작 → 2029-03 종료, SAN 검증 재사용 398 → 10일. 단계별 날짜(200일 2026-03-15 · 100일 2027-03-15 · 47일 2029-03-15, 기준은 발급일)는 1단계 집필 때 BR 본문 2.3.1판으로 대조 완료 | CA/B Forum |
| Let’s Encrypt 90 → 45일 | 맞음, 더 구체적 | 2026-05-13 tlsserver 프로필 45일(선택), 2027-02-10 classic 64일·인가 재사용 10일, 2028-02-16 classic 45일·인가 재사용 7시간. ARI 사용과 유효기간의 약 2/3 지점 갱신 권고, DNS-PERSIST-01 예고 | Let’s Encrypt |
| PEP 779 | 맞음 | Python 3.14에서 free-threaded가 Phase II(공식 지원·선택 빌드), 기본 빌드는 여전히 GIL | PEP 779 |
| 전자금융감독규정 시행세칙 개정(업무용 SaaS) | 맞음, 출처 보정 | 로드맵이 단 금융위 링크는 2026-01-19 변경 예고 보도자료(조건: 침해사고 대응기관 평가, 단말 보호·안전한 인증·최소 권한·구간 암호화, 중요정보 모니터링, 반기 1회 이행 평가, 개인(신용)정보 처리 SaaS 제외). 2026-04-20 시행은 언론 보도로 확인 — 9단계에 두 날짜를 구분해 싣는다 | 금융위 · ZDNet |
| Pebble이 CAA를 검사하는가 | 검사 안 함 | Pebble은 caaIdentities를 디렉터리 메타에 광고만 하고 발급 검증(VA)에서 CAA를 조회하지 않는다 → CAA 거부 실습은 실전 트랙(Let’s Encrypt staging)으로 | Pebble 소스 |
| 6일 단기 인증서 | 맞음 | Let’s Encrypt shortlived 프로필(160시간) 2026-01-15 정식 제공, IP 주소 인증서는 이 프로필로만. 로컬 Pebble 발급에서 6일 유효기간 실측 | Let’s Encrypt |
| PostgreSQL 11+ 기본값 있는 컬럼 추가의 재작성 없음 | 집필 때 | 4단계 집필 때 PG 18 문서와 실측으로 확인 | — |