모든 글
약 4분 분량 학습 프로젝트/분산 시스템

분산 시스템, 먼저 제대로 배우고 Kafka를 만든다: MIT 6.5840

목차

분산 시스템을 제대로 파보는 공부기. 이 글은 1편, 왜 6.5840부터 시작하나, 그리고 어떻게.

0. 들어가며

커널도, DB도, JVM도 밑바닥부터 만들어봤습니다. 그런데 전부 컴퓨터 한 대 안의 이야기더군요. 다음 축은 분명했습니다. 바로 여러 대가 협력하는 분산 시스템입니다.

그럼 어떻게 배우지? 제 방식대로면 “분산 시스템 하나를 밑바닥부터 만들어보자”가 자연스럽습니다 (그게 Kafka를 만들기로 한 이유입니다). 그런데 계획을 짜다 보니, 자작만으로는 분산을 “제대로” 배울 수 없는 이유가 걸렸습니다. 그래서 순서를 정했습니다. 분산 fundamentals를 먼저 제대로 배우고(MIT 6.5840), 그 위에 Kafka를 짓는다. 이 글은 그 이유와 계획입니다.

1. 왜 “그냥 만들면서 배우기”로는 부족한가

분산 시스템을 Kafka 하나 만들며 배우려 하면 두 가지가 걸립니다.

① 앞부분이 다 단일 노드

Kafka를 만들려면 먼저 와이어 프로토콜 → 로그 저장 → produce/fetch를 해야 합니다. 이건 전부 컴퓨터 한 대 안의 일입니다. 진짜 분산(복제·합의)은 로드맵 맨 끝에 있습니다. “분산 공부”가 목표인데 몇 주간 배관부터 깔고 나서야 분산에 도달합니다.

② 진짜 어려운 걸 스스로 테스트할 수 없다 (결정타)

분산 시스템이 어려운 진짜 이유는 실패를 다루는 겁니다. 네트워크 분단, 노드 크래시, 메시지 지연·재정렬 같은 것들입니다. 정상 경로는 쉽습니다. 복제? 그냥 로그 복사하면 됩니다. 어려운 건 “리더가 죽는 순간 메시지가 반쯤 갔을 때” 같은 지옥입니다.

그런데 이런 실패 시나리오를 스스로 테스트로 만들기가 거의 불가능합니다. 프로토콜은 내가 짠 시뮬레이터로 검증할 수 있어도, *“내 합의 알고리즘이 네트워크 분단에서 올바른가?”*는 스스로 검증하기 어렵습니다.

분산에서 가장 위험한 함정은 “돌아가는 것처럼 보이는데 사실 틀린” 코드입니다. 적대적 테스트가 없으면 그걸 맞다고 믿고 넘어갑니다. 그리고 그 버그는 프로덕션에서 새벽 3시에 터집니다.

2. 그래서 MIT 6.5840부터

이 구멍을 정확히 메워주는 게 있었습니다. 바로 MIT의 분산 시스템 대학원 과목 6.5840(구 6.824)입니다. 랩마다 적대적 테스트 스위트가 붙어 있습니다. 네트워크 분단·크래시·지연을 무작위로 주입하면서 내 구현이 여전히 올바른지 두들깁니다.

이게 자작으로는 재현하기 힘든 부분입니다. Raft 논문을 직접 구현하고 MIT이 만든 잔인한 테스트로 검증받는 것. 강의·랩·테스트가 전부 무료로 공개돼 있어서 집에서 그대로 할 수 있습니다.

만들면서 배우기 (Kafka)MIT 6.5840
분산 학습 밀도낮음 (앞이 단일 노드)높음 (Raft 정면돌파)
적대적 테스트스스로 못 짬분단·크래시 주입
성격실전 시스템 완성fundamentals 학습

3. 순서: 배우고 → 짓는다

Kafka는 여전히 만듭니다. 다만 순서를 “배우고 나서 짓는다”로 잡았습니다.

1단계 이론·멘탈모델 Kleppmann 8강(7h) + DDIA 5~9장 ← 지도 그리기
2단계 핵심 정면돌파 MIT 6.5840: MapReduce → Raft ← 적대적 테스트로 합의
3단계 실전에 적용 그 Raft를 kafka-hobby 트랙 E에 짓기 ← 배운 걸 내 손으로

6.5840에서 Raft를 제대로 배우고 나면, kafka-hobby의 합의(KRaft) 트랙이 막막한 TODO가 아니라 “아는 걸 짓는 일”이 됩니다. fundamentals(6.5840)와 실전(Kafka)이 서로를 강화합니다. 면접에서도 “6.5840 Raft를 구현했고 그걸 제가 만든 Kafka에 적용했습니다”는 이론과 실전을 동시에 증명하는 답입니다.

4. 왜 Go인가 (C/Java 하던 사람 입장에서)

6.5840은 Go 전용입니다. 테스트 하네스 자체가 Go로 짜여 있어서 선택지가 없습니다. 저는 커널·DB를 C로, Kafka를 Java로 만들었지 Go는 처음이었습니다. 근데 걱정보다 훨씬 쉬웠습니다.

  • Go ≈ C 문법 + Java식 GC + goroutine/channel + 훨씬 작은 문법. C·Java 배경이면 며칠이면 랩 돌릴 수준이 됩니다.
  • goroutine·channel이 분산 코드를 깔끔하게 만듭니다. “여러 노드가 동시에 메시지 주고받기”가 Java 스레드보다 자연스럽습니다. MIT이 Go를 고른 이유입니다.
  • Go 자체가 커리어 자산. Kubernetes·Docker·etcd가 다 Go입니다.

개념 매핑은 이렇게 잡았습니다.

C/JavaGo
Thread / pthreadgoroutine go f()
BlockingQueuechannel ch <- x
synchronized / mutexsync.Mutex
classstruct + 메서드
try/catchif err != nil (에러는 값)
finallydefer

5. 첫날: 셋업하고 손 풀기

말만 하면 안 되니까 바로 환경을 깔았습니다.

Terminal window
brew install go # Go 1.26
git clone git://g.csail.mit.edu/6.5840-golabs-2026 6.5840 # 랩 스타터 (git:// 프로토콜!)
cd 6.5840/src/main
go run mrsequential.go wc.so pg-*.txt # 순차 MapReduce 레퍼런스

셰익스피어 텍스트로 단어 수를 세는 순차 버전이 잘 돌아갔습니다.

the 29748
and 23612
to 16079

이제 할 일은 이 순차 버전을 “분산”으로 만드는 겁니다. mr/worker.gomr/coordinator.go를 채워서 여러 워커가 나눠 처리하고, 중간에 워커가 죽어도 코디네이터가 재할당하게 만듭니다. 테스트(make mr)는 실제로 워커를 크래시시키면서 검사합니다.

마무리

코드에 앞서 순서를 이렇게 잡았습니다.

  • 분산을 “제대로” 배우려면 실패 처리를 적대적 테스트로 검증해야 한다. 자작만으론 채우기 힘든 부분이다.
  • 그래서 MIT 6.5840로 fundamentals(특히 Raft)를 먼저 정면돌파하고, 그걸 kafka-hobby를 지으며 적용한다.
  • Go는 부담이 아니라 자산이다. C/Java 배경이면 며칠이면 된다.

다음 편은 MapReduce 랩을 실제로 구현하면서 “분산 작업 분배 + 죽은 워커 복구”를 Go로 짜보는 과정입니다. 그다음이 진짜 산인 Raft입니다.

Author
작성자 @범수

오늘의 노력이 내일의 전문성을 만든다고 믿습니다.

댓글

댓글 수정/삭제는 GitHub Discussions에서 가능합니다.