어릴적 이야기. 그리고 결함 감내 시스템 (Fault-Tolerant System) 은 왜 중요한가. 그 이유와 몇가지 테크닉에 관한 글.

잠시 어릴적 이야기…

난 처음 프로그래밍에 정식적으로 입문하기 시작한 때가 고등학교 1학년때 부터 였던것 같다. 그전에도 한 10살때 였던가… 어렸을때 아버지가 어디서 가져오신 하드드라이브가 없고 대신 ​5 1⁄4 인치 플로피 디스크 2개 들어가는 XT 시스템 컴퓨터를 받은후 버블버블, 금광을 찾아라 같은 흑백으로 되어있는 게임을 하며 (이것도 누군가에게 얻어왔던것 같다) 컴퓨터에 관심을 가졌으며 아버지는 그런 나를 보고 안타깝게 여겼던지 얼마뒤 첫 펜티엄 컴퓨터를 사주셨다 (그때는 진돗개 컴퓨터로 유명한 세진컴퓨터 ). 그 컴퓨터로 DOS 도 써보고 전화모뎀으로 연결하는 인터넷도 혼자 배우며 사용해봤었다.

고등학교 일학년때 Best Buy 에서 사는 게임만들기 페키지를 박스체로 사서 C++ 에 관심을 가져보고 고등학교 2학년때는 HTML 을 혼자 우연히 책으로 배우고 Javascript, Perl/CGI, MySQL, CSS 에 입문. 고등학교 3학년때는 AP Computer Science 를 들으며 University Interscholastic League (UIL) 라는 코딩 대회에 참여하며 그렇게 프로그래밍에 접했었다. 하지만 그때 당시에는 컴퓨터가 전자파를 많이 보내서 그런지 내가 게임을 많이 해서 그러지 피곤해지고 중독되는 나 자신이 두려워서 컴퓨터 전공을 하기는 싫었고 때마침 고등학교 3학년때 미분적분과 물리학을 들으면서 ‘난 평생 공부만 하고 우주와 입자에 관해서 연구하고 싶다’ 는 미련한 꿈을 꾸며 우주공학을 선택해서 대학교에 들어갔다. 그때 당시에는 생각했던게 뒤늦게 수학을 좋아해서 기본실력부터 늘려야겠다. 그러면서 빡세게 물리학 수학을 배우고 싶다 그럴려면 로켓사이언스라는 우주항공공학이 좋아 보였고 학부때는 우주항공공학 그러다가 NASA 에서 한번 인턴하고 박사로 양양영학 (Quantum Physics) 포닥으로 천체물리학 (Astrophysics) 그리고 후에는 Fermi Lab 같은곳에서 일하는 상상을 했었다.

하지만 대학교를 들어가면서 그 자신만만한 태도는 곧 무너졌고 나보다 똑똑한 사람들이 정말 많구나 하는 큰 벽을 처음 느끼게 되었다. 고등학교 때도 천재같은 친구들은 몇명 보았었다. 다만 그때는 나와 시작이 다르구나 언젠간 노력과 열정으로 따라잡을수 있겠지라고 생각했었는데 대학교 들어가면서 그런 인식이 께지게 되었다. 그들의 머리는 정말 달랐다. 선택한 우주항공은 재미는 있었지만 내가 상상한것과는 많이 달랐다. 미국이 냉전 이후 더 이상 우주탐험에 관심이 없어서 그런지 우주탐사는 아주 먼 꿈처럼 보였으며 대부분 우주항공/비행항공을 공부하는 학생들은 Raytheon, Lockeed Martin 같은 곳에 들어가서 무기를 만들거나 Boeing 이나 NASA 에 들어가서 아주 세부적인 부분을 일하는 것 둘 중 하나였다. 아… 아니면 또 공부를 계속해서 교수님이 되거나. 그 어떤 방향도 관심이 없었다. 또 그 당시에는 난 시민권이 없어서 지원할수 있는곳이 거의 없는건 또 다른 문제였다. 이런저런 이유로 계속 졸업하는것도 미루었다. 고민으로 방황은 하였지만 파티로 유명한 UT 라는 대학교에 다니면서도 술을 마신적이 없었고 그 유명한 6번가도 관심을 가진적이 없었다. 대신 교회를 열심히 다녔고 고등학교 때 취미를 그대로 이어 웹사이트 도메인을 여러개 산후 학교나 숙소 지하 컴퓨터랩에 가서 몇개는 취미로 몇개는 돈을 버는 목적으로 운영하는게 금토같은 주말에 하는 여가활동이였는데 그러다가 스팸도 많아지고 사용자 수도 많아져서 처음에는 혼자 스팸관리 스크립트도 만들고 간단한 Content Management System (CMS) 도 만들어보았다. 하지만 어느정도 시간이 지나자 관리하기 힘들다 같이 일하는 파트너가 있거나 알고리즘과 테크닉을 제대로 배워서 좀더 수월하게 만들어야겠다 이런 생각이 들어 복합전공으로 선택하게 된게 컴퓨터과학이였다. 지금은 물리학이나 우주항공공학은 전혀 쓰지 않고 컴퓨터과학이 나의 인생 큰부분이 되었지만 시간이 지나면 언제 이 배웠던것을 다시 복습해서 무언가 만들어보고 싶은 생각은 있다.

결함 감내 시스템 (Fault-Tolerant System) 에 왜 관심을 가졌는가?

서론이 길어졌는데 그래서 지금도 여전히 나의 컴퓨터분야의 관심사는 웹개발에 있다. 배우는걸 즐겨서 주변사람들이 머신러닝이나 데이터과학 이런것을 이야기하면 관심은 가지지만 난 나이도 이젠 제법 있고 깊게 보는것보다 전체적으로 보는걸 좋아해서 지금은 기술적으로는 집중하고 싶은 분야는 소프트웨어 아키텍트쪽이다. 우선 모바일앱이든 데스크탑앱이든 웹앱이든 어떤 애플리케이션 (Application) 을 만들더라도 인터넷에 연결되지 않으면 쓸모없는 경우가 대부분이며 데이터를 주고 받을려면 기본적으로 웹서비스가 필요하다. 해커톤을 몇번 참여해봤는데 이럴때는 나같은 웹관련 개발자보다는 라즈베리 파이(Rasberry PI) 같은걸 사용하는 내장형 마이크로시스템 개발자나 Android 나 iOS 로 개발하는 모바일 개발자가 더 쓸모있지만 이런 디바이스들을 사용자가 직접 보고 사용할수 있는 클라이언트 (Client) 라고 본다면 실제적인 계산을 하고 솔류션 서비스들을 오케스트레이트 (Orchestrate) 해주는건 서버와 벡엔드라고 정리할수 있다. 그리고 이런 벡엔드는 실제적으로 PRODUCTION 환경에서 사용할때 필수적이다.

그런 웹서비스중에서도 내가 특히 관심을 가지는건 어떤 고급 트래픽 (high traffic) 그리고 많은 사용자가 동시에 사용하는 환경에서도 온전하게 (stable), 회복하며 (resilent), 빠르게 (fast), 안전하게 (safe) 돌아갈수 있는 결함 감내 시스템(fault-tolerant system) 을 구성하는것이다. 결함 감내 시스템을 한번에 이해할려면 아마존, 페이스북, 넥플릭스 같은 서비스를 생각해보면 알수 있을것이다. 수많은 사용자가 동시에 쓰면서 분명히 나쁜 목적을 가진 사용자들도 많고 엄청난 데이터를 주고 받는데도 별다른 다운타임이 없이 잘 돌아간다. 사실 넥플릭스나 구글 같은 시스템이 대단한 이유는 스마트한 알고리즘이나 인공지능에도 있지만 그것보다 높게 사야하는건 몇년동안 돌아가는데도 불과 몇분도 문제가 생기지 않을정도로 빠르게 잘 돌아가는 서비스에 달려있다. 이런 서비스를 구축할려면 수백개의 대형 데이터센터 그리고 어마어마한 가격과 성능의 하드웨어들도 중요하다. 하지만 하드웨어의 성능에 의존하지 않고 서비스를 원만하게 돌릴수 있게 만드는 소프트웨어도 그리고 그런 시스템을 뒷바침하는 소프트웨어 디자인이 필요하다.

쿠팡과 한번 인터뷰를 한적이 있었는데 여태까지 수많은 인터뷰를 보았지만 (Google, Facebook, Apple, Microsoft, Amazon, NASA, Lockheed Martin, Boeing 등등 몇백개의 회사) 이처럼 재미있는 인터뷰는 많이 없었다고 생각한다. 그리고 그 인터뷰를 통해서 배우는게 많았다. 그 중 한가지는 Akka 라는 분산 시스템 (Distributed Design System) 디자인 패턴중 하나인 Actor Pattern 을 쓰는 오픈소스 프레임워크를 알게 되었는데 후에 관심이 있어서 찾아보고 공부를 하였다. 이런 Actor Pattern 외에도 Fault-Tolerant 시스템을 만들기 위한 여러가지 테크닉과 툴이 있으며 그중 몇가지를 살펴보기로 하자. 그전에 결함 감내 시스템 에서 잠시 이야기하고 들어가기로 한다.

결함 감내 시스템 (Fault-Tolerant System) 에 관한 간단한 요약

기본적으로 어떤 서비스를 개발해서 PRODUCTION 환경에서 돌리게 되면 내 컴퓨터에선 잘만 돌아가던 (이걸 localhost 라고 한다) 것들이 하나둘식 문제를 드려내기 시작한다. 이럴때 결함 감내 시스템 에서 말하는 문제점이 크게 두가지로 요약될수 있는데:

  1. 하나는 실패-스톱 형상 (fail — stop behavior) 이고
  2. 두번째는 비잔틴 형상 (Byzantine Behavior) 이다.

실패-스톱 형상은 갑자기 잘 돌아가던 서비스 전체가 다운이 되거나 혹은 몇가지 시스템일부분이 실패해서 돌아가지 않는 상황을 뜻한다. 예를 들어 웹서버가 갑자기 다운이 되거나 데이터베이스가 다운되고 혹은 모듈중 하나가 대답을 안하는 경우이다.

비잔틴 형상은 모든 시스템이 돌아가지만 원하는 결과가 아닌 경우를 말한다. 여기서 비잔틴은 복장 미묘한 상황을 뜻하는데 돌아가긴 하지만 무언가 (예: 잘못된 데이터, 틀린값) 맞지 않는 케이스를 말하고 있다.

두가지중 어떤 경우도 원하는 상황이 아니며 아마존, 구글, 페이스북 같은 대형 서비스는 365일 24시간 문제없이 돌아가야 하며 잠시라도 문제가 생기면 몇십억 몇백억 손해가 나기 때문에 이런 문제를 잘 해결할수 있으면 구글 같은곳에서 모시고 올려는 케이스도 몇번 보았다. 대학교때 운영체제 (Operating System) 수업을 가르쳤던 Mike Dahlin (http://www.cs.utexas.edu/~dahlin/)이라는 교수님이 있었는데 나중에 보니 이분이 구글에 Distinguished Engineer 로 고용되셨다. 아마 그분이 적은 Byzantine Fault Tolerance and Beyond 라는 연구로 구글에 가셨지 않나 예상된다.

결함 감내 시스템 (Fault-Tolerant System) 을 구성할수 있는 몇가지 툴과 테크닉

우선 기본적으로 나도 제대로 된 Full Fledged 결함 감내 시스템을 만들어본적 없으며 그럴려면 아직 많은 공부와 경험이 필요한것을 미리 말씀 드린다. 다만 이런 시스템을 사용해보고 툴을 접해보고 일부분을 개발한적 있으며 그 중 몇가지 기본적인 몇개를 추천한다.

  1. 디자인패턴 — Circuit Breaker Pattern 과 이것을 이용한 Netflix 의 Hystrix

Circuit Breaker Pattern 은 Agile Manifesto 로 유명한 Martin Fowler 의 블러그에서 읽어볼수 있는데 (https://martinfowler.com/bliki/CircuitBreaker.html) 한마디로 정리하자면 원래 돌아가야 하는 시스템이 문제가 생겼을때 대비한 다른 백업시스템이나 Dummy 시스템으로 전환해주는 테크닉이다. 이 디자인패턴의 적용으로 제일 유명한건 Netflix 의 Hystrix 이고 오픈소스이다: https://github.com/Netflix/Hystrix/wiki. Citi 를 비롯해 지금 내가 다니고 있는 클라이언트 비롯 많은 기업들이 이 툴을 사용하고 있는걸 보았다. 다만 현재 이 툴을 만든 Netflix 는 이 프로젝트 업데이트를 중단했으며 대신 https://github.com/resilience4j/resilience4j 같은 Java 8 and functional programming 을 지원하는 프로젝트나 adaptive concurrency limits 같은 테크닉을 쓰는길로 바꿨다고 한다. (이건 왠지 구글의 Angular 1 에서 Angular 2 업그레이드처럼 뒷통수 맞는 느낌?)

2. 트래픽을 효율적으로 정리할수 있는 Load Balancer

분산 시스템의 기본인 Load Balancer 는 어떤 서비스를 만들던지 기본적으로 들어가야 한다. Load Balancer 의 개념은 하나의 서버가 아닌 여러개의 동일된 서비스화된 시스템을 돌려서 들어오는 트래픽을 FIFO 나 Round Robin 같은 스케쥴링 알고리즘으로 분산해서 정리해 보내는 동시에 한개의 서비스가 다운되더라도 다른 서비스가 지탱해줄수 있는것이다. 사실 이런점은 비행기의 듀얼 엔진과 비슷하다. 비행기는 엔진이 하나가 아니고 두개이상인데 하나가 불이 붙어서 고장나더라도 시스템이 불안전하긴 하지만 남은 엔진으로 무사히 착륙해주는 여분 (redundant) 시스템이다. Load Balancer 는 워낙 유명해서 수많은 툴이 있는데 NGINX (https://www.nginx.com/) 나 C 로 되어있는 HaProxy (https://www.haproxy.org/) 가 몇가지 예이다.

3. Actor Model 과 이것을 이용한 Akka

Actor Model 은 여러 프로세스가 동시에 들어올때 (concurrent) 문제없이 분산시켜 해결해주는 디자인 패턴이다. 이 계산을 하는 유닛을 Actor 라고 하며 이 Actor 들은 서로 서로 고립되고 메모리를 나누지 않는다. 자세한건 여기를 읽어보길 바란다: https://www.brianstorti.com/the-actor-model/

Actor Model 을 적용한 프레임워크 중 하나가 akka https://akka.io/ 이다.

4. Non-Blocking IO 그리고 Asynchronous 를 위한 Messaging Queue. 그런걸 적용한 Kafka 와 RabbitMQ

한때 Thread 를 사용한 개발이 유명한적이 있었다. 하지만 지금은 Java J2EE 에서도 Thread 사용을 금지하며 Streaming API 나 Akka 같은 Actor Pattern 이 대체로 나타나고 Javascript 에선 이미 NodeJS 가 이런 Non-Blocking IO 를 지원하고 있다. 한편 Kafka (https://kafka.apache.org/) 나 RabbitMQ (https://www.rabbitmq.com/) 같은 메시지 서비스는 동시에 처리해야하는 프로세스를 Thread 를 사용하지 않고 더 빠르게 문제없게 사용할수 있는 결함 감내 시스템 에 결정적인 역할을 한다.

그외에도 다양한 Netflix 의 Eureka (https://github.com/Netflix/eurek) 처럼 다양한 모니터링 시스템과 Chaos Monkey (https://github.com/Netflix/chaosmonkey) 처럼 PRODUCTION 환경에서 테스트하기 힘든 고도의 트래픽 상황을 미리 낮은 환경 (DEV, INT, QA, UAT, TST 등등) 테스트할수 있는 stress testing, performance testing 툴등이 있다.