분산 시스템 직접 만들어보기

sudosubin
5 min readDec 25, 2023

--

Fly.io는 쉽고 빠르게 컨테이너를 배포할 수 있는 서비스이다. 무료 플랜이 꽤 여유 있게 제공되고 Grafana 대시보드까지 자동으로 구성해주다 보니, 개인적인 프로젝트를 배포할 때 자주 사용하는 PaaS 이다.

어느 날 우연히 Fly.io에서 만든 챌린지를 알게 되었고, 직접 해보니 정말 재미있어서 공유해보고자 한다. 챌린지는 직접 풀어보아야 의미가 있기 때문에, 이 글에서는 스포일러가 최대한 되지 않는 선에서 소개하고자 한다.

분산 시스템 챌린지

https://fly.io/dist-sys/

Fly.io의 분산 시스템 챌린지(Distributed Systems Challenge)는 https://fly.io/dist-sys/ 에서 찾을 수 있다. 타이틀은 Gossip Glomers인데, 영어권 사용자가 아니다보니 정확하진 않지만 수다 중인 Glomer(It’s Punky Brewster의 캐릭터) 친구들이라는 의미인 것 같다.

이 분산 시스템 챌린지의 가장 큰 특징은, 순차적으로 분산 시스템에 대해 학습하면서 보완해나가게 된다는 점이다. 챌린지는 총 6개의 단계로 구성되어 있고, 난이도는 조금씩 상승한다. 가장 마지막 단계는 정말 어려운 편이다.

각 단계는 경우에 따라 처음에는 Single Node 환경에서 개발한 후, 바로 이어서 분산 환경에서도 동작하도록 재구현 하기도 한다. 이렇게 하나의 챌린지는 6개의 단계로, 각 단계는 더 작은 과정들로 나뉘어 차근차근 진행하게 된다. 하나씩 해결해나가는 재미와 성취감도 있는 편이다.

이 챌린지는 원하는 어떤 언어를 사용해도 무방하지만, Go를 기준으로 하고 있다. Go를 사용한다면 GitHub의 Demo 패키지를 바로 내려받아 사용할 수 있지만, 다른 언어들은 유틸리티들을 직접 구현하거나 Gist 등의 어디에선가 잘 찾아 사용해야 한다.

Maelstrom 플랫폼

이 챌린지는 Maelstrom이라는 플랫폼을 사용한다. 노드의 모든 통신은 STDINSTDOUT 을 이용하는데, 인터페이스가 아주 단순해서 다른 프로그래밍 언어로도 충분히 구현해 사용이 가능하다.

{
"src": "c1",
"dest": "n1",
"body": {
"type": "echo",
"msg_id": 1,
"echo": "Please echo 35"
}
}

규격에 따라 노드만 구현하면, Maelstrom은 노드 간의 통신을 처리하고, 다양한 종류의 KV 스토리지를 제공해주고, 적절한 테스트도 실행한다. 테스트 도중에는 자동으로 네트워크 실패(분할)도 주입해준다.

Maelstrom과 Jepsen이 원래 있었던 프로젝트인지, 아니면 Fly.io에서 새로 만들었는지는 잘 모르겠지만 덕분에 쉽게 테스트를 할 수 있었다.

가끔만 실패하는 케이스

https://fly.io/dist-sys/4/

⚠️ ️스포일러: Challenge #4: Grow-Only Counter 내용을 포함하고 있습니다.

테스트를 돌렸는데, 가끔만 실패하는 경우가 있었다. 분명히 잘 짠 것 같은데 테스트에 문제가 있나? 하지만 Maelstrom은 그 전까지는 내 기대를 배신한 적이 없었다.

문제는 4번째 단계인 Grow-Only Counter에서 나타났다. 여기에서는 Maelstrom이 제공하는 seq-kv를 사용해, 여러 개의 노드가 하나의 글로벌 카운터 값을 증가시키고 가장 마지막에는 모든 노드가 동일한 값을 반환해야 한다.

문제의 상황은 3개의 노드에서 테스트를 실행했을 때, 1~2개의 노드에서만 약간 적은 값을 반환하고 있었다. 가끔만 실패하다보니 많이 헤맸는데, 노드 개수를 5개, 10개로 늘려보니 거의 항상 실패하면서 감을 잡을 수 있었다.

seq-kv는 순차적으로 일관된 KV 저장소로, Sequential Consistency의 특성을 갖는다. 네트워크 분할(Network Partition)이 발생하면 seq-kv의 일부분이 더 진행되지 않을 수 있고, 어떤 프로세스는 최신 값을 읽는 반면, 다른 프로세스는 아직 덜 진행된 오래된 값을 읽을 수 있다. 마침 Maelstrom의 실행 로그에서 Partition과 관련한 로그를 확인할 수도 있었다.

이런 부분을 감안해서 seq-kv만을 사용하는 대신 약간의 로직을 덧대어 수정했다. 문제를 찾고 해결하면서 작은 깨달음을 얻었고, 너무 속이 시원해서 아직도 기억에 남는 단계이다.

Fly.io의 분산 시스템 챌린지는 https://fly.io/dist-sys/ 에서 진행할 수 있다.

챌린지를 진행하면서 어려운 부분에서는 도움을 구할 수 있다. Fly.io의 Discourse에도 질문과 답변이 올라와있고, GitHub에서 코드 검색을 통해 다른 사람들의 풀이를 참고해 실마리를 잡을 수 있다. (하지만 가능하면 혼자서 최대한 풀어보는 것을 추천한다.)

나는 개인적으로 알고리즘이나 Problem Solving에는 관심을 갖지 못했는데, 이 챌린지는 재미있게 풀었다. 실제로 업무에서 사용해온 다양한 분산 시스템들의 원리를 상상해보며, 나만의 작은 분산 시스템을 만드는 것이 꽤 재미있었다.

이 글을 읽은 다른 분들도 꼭 한 번씩 해보면 좋을 것 같다.

--

--