QCon London 2012에서의 Joe Armstrong의 강연입니다.
Building Highly Available Systems in Erlang by Joe Armstrong
Joe Armstrong은 에릭슨에서 일하던 1986년에 Erlang의 초기 버전을 개발했으며, Erlang OTP 프로젝트의 Chief Architect였습니다. Erlang은 1998년 open source로 나오기 전에는 에릭슨의 proprietary 언어로 개발 되었기 때문에 Erlang의 창시자라고 불러도 될지는 조금 애매하기는 하지만, 소위 Programming XXX라는 책 – Programming Erlang (2007)의 저자로서 그렇게 불러도 큰 문제는 없지 않을까 싶습니다. 2003년 PhD thesis로 Making reliable distributed systems in the presence of software errors이라는 논문을 내놓았는데 이 역시 Erlang에 관한 내용이고, 현재도 Erlang에 관련한 활동을 활발히 하고 있는 것 같습니다. Erlang의 역사에 대해서 좀 더 알아보기는 해야겠지만, 이런 것들만 보아도 꽤나 재미있는 이력이라고 생각합니다.
6 Rules
먼저 Redundancy, Consistent Hashing과 Chord의 Quorum System에 대해 간략하게 설명하고, Reliable Data Storage의 문제는 알고리즘 차원에서는 이미 풀렸다라고 선언합니다. 100% 납득이 가는 것은 아니지만, 그렇다고 인정하고 넘어간다면 그 다음엔 이 개념들을 어떻게 구현 – 코딩할 수 있을 것인가에 대해서, 6가지의 룰을 설명합니다. 결국 이러한 6가지 룰을 – 프레임워크나 라이브러리가 아니라 – 프로그래밍 언어 차원에서 구현한 언어가 바로 Erlang이라고 얘기하는 흐름이라서 조금 힘이 빠지는 느낌이 드는 것은 사실입니다.
1. Isolation
모든 것이 격리되어있다면, 더 많은 컴퓨터가 투입될 수록 시스템의 실패 확률은 점점 낮아질 수 있다는 얘기입니다. 이를 통해 10 nines도 실현 가능하다고 얘기합니다. Joe Armstrong은 Erlang 프로세스들이 공유하고 있는 문맥이 없다는 점으로 설명합니다. Erlang 프로세스들은 VM위에서 동작하는 가벼운 프로세스 (light-weight process)들로 일반적인 프로세스들처럼 메모리를 공유하고 있지 않습니다.
2. Concurrency
세상의 대부분의 문제들은 생각보다 병렬적(parallel)이고, 2대 이상의 컴퓨터를 제공함으로써 병행성(concurrent)을 확보할 뿐만 아니라 분산(distributed)된다고 얘기합니다. Erlang의 프로세스 얘기로 다시 돌아가면, 이론적으로 모든 Erlang 프로세스들은 병렬적으로 동작하고, 여러 core로 퍼져서 실행된다고 합니다.
3. Fault Detection
실패의 탐지를 위해서는 3대의 컴퓨터가 필요하다고 얘기합니다. 별도의 설명이 없지만 leader election의 이야기겠죠? Erlang 프로세스들은 실패를 탐지할 수 있도록 되어있고, 원격의 프로세스들을 연결해서 이들의 실패를 탐지해서 대신 문제를 해결하는 것도 가능하다고 합니다.
4. Fault Identification
실패한 원인을 아는 것도 중요하다고 얘기합니다. 이를 위해서는 4대의 컴퓨터가 필요하다고 얘기하는데 역시 consensus의 이야기일까요? 슬라이드에서는 코드를 함께 보여주지만, Erlang에서 에러를 알려줄 때, 마치 Exception 객체를 catch할 때 cause가 들어있는 것처럼 에러의 원인에 해당하는 코드도 함께 알려줍니다.
5. Live Code Upgrade
Erlang에 대해 간략한 설명을 들을 때 나름 감명깊었던 기능인데, Erlang에서는 애플리케이션이 실행되는 도중에 코드를 수정 – 업그레이드할 수 있습니다.
6. Stable Storage
Erlang에는 기본으로 제공되는 mnesia라는 storage가 있는데, 데이터를 disk와 RAM 둘다에 저장할지, RAM에 저장하되 복제할지 등등을 모두 customize할 수 있다고 합니다. 그 외에도 riak, couchdb 등의 꽤 잘 알려진 NoSQL storage들이 erlang에 기반하고 있습니다.
Messaging
발표의 중간 정도에서 Joe Armstrong은 몇가지 인용구를 보여주는데 아래와 같습니다.
the process achives fault containment by sharing no state with other processes; its only contact with other processes is via messages carries by a kernel messge system
–Jim Gray, Why do computers stop and what can be done about it?, 1985
실패를 격리하기 위해서는 프로세스 사이에 상태를 공유하지 않고, 하부의 메시지 시스템에 의해서 제공되는 메시지를 통해서만 다른 프로세스와 접촉해야한다라는 이야기네요. 1985년의 글이므로 아마 이 글이 Erlang의 설계에 커다란 영향을 미쳤을지도 모르겠습니다. Shared nothing 아키텍쳐라는 단어는 아마 다들 익숙하시리라 생각합니다. 현대의 웹 서비스 아키텍쳐에서는 이미 널리 쓰이고 있죠. 공유하는 상태를 분리하는 것은 매우 중요합니다만, 오히려 공기처럼 우리 주위에 있기 때문에 그 중요성이 간과되고 있는 것이 아닐까 생각이 들 정도입니다.
The big idea is “messaging” — that is what the kernel of Smalltalk/
Squeak is all about (and it’s something that was never quite completed
in our Xerox PARC phase)….–Alan Kay
한편, 메시징의 가장 큰 성공은 넓은 의미에서는 클라이언트-서버 아키텍쳐에 있다고 생각하지만, 좁은 의미에서는 우리에게 익숙한 것은 아니라고 생각합니다. 비동기적인 메시징과 메시지 디스패쳐 스타일의 애플리케이션은 아직은 자주 볼 수 있는 것은 아님에도 불구하고, 커다란 규모의 시스템에서는 오래전부터 요구되어 왔던 것이고, 인터넷 서비스의 규모가 점점 커지면서 점점 자주 보게되지 않을까 싶습니다.
Fail Fast and Early
Halt on failure: in the event of an error a processor should halt instead of performing a possibly erroneous operation.
Failure status property: when a processor fails, other processors in the system must be informed. The reason for failure must be communicated.
Stable Storage Property: The storage of a processor should be partitioned into stable storage (which survives a processor crash) and volatile storage which is lost if a processor crashes.
— Schneider, ACM Computing Surveys 22(4):229-319, 1990
6 Rules에서도 어느 정도 언급이 되어있지만 기본적으로는 failure를 detection할 수 있어야 하고 failure가 발생한 프로세스는 정지시키고, 안정적인 스토리지에 저장된 상태를 이용해 다른 프로세스가 failure를 복구하는 개념입니다. 높은 수준의 가용성을 요구하는 하드웨어에서 2개의 circuit을 준비하고 언제든지 하나의 circuit에서 failure가 발견되면 다른 circuit으로 대체하는 것과 같은 이야기 같습니다. 특히, 여러 인용을 사용하여 fail-fast와 fail-early를 강조하고 있는데, 이러한 scheme에서 fault 상태의 지속을 최소화하기 위해서는 당연한 이야기 같습니다.
Closing
이 발표를 들은 것은 애초에 Erlang 자체보다는 HA 시스템을 만들기 위한 방법에 대한 Erlang의 관점을 알고 싶었던 것이고, Shared nothing + Messaging 아키텍쳐, fail-fast, fail-early 등의 개념들의 중요성을 다시금 깨닫는 계기가 되었습니다.
Erlang을 사용해보지도 않은 상태에서 섣부른 생각일 수도 있겠지만, 이 발표를 통해 느낀 Erlang의 가장 큰 장점은 Shared nothing + Messaging 아키텍쳐의 애플리케이션을 개발할 때 필요한 거의 모든 것들을 공짜 로 또는 바로 (off-the-shelf) 제공한다는 것 같습니다. 현대의 웹 서비스들은 비교적 failure에 안전한 언어와 플랫폼 (Java), 실패를 탐지하고 복구하기 위한 메커니즘 (L4), 메시징에 기반한 프로토콜과 그 구현 (HTTP와 이를 concurrent하게 처리할 수 있는 웹 서버 구현), 안정적인 스토리지 (DB)로 만들어져 있기 때문에 역시 이 비용을 크게 느끼지 않는 것 뿐이지, 이러한 것들에 의존하지 않는 새로운 애플리케이션을 만들어야 한다면, 무시할 수 없는 비용을 치뤄야만 합니다. 예를 들어, 언제든지 segmentation fault를 맞이하더라도 이상하지 않는 C로 애플리케이션을 개발해야하고, 실패 탐지와 복구를 Linux HA를 사용하되, 애플리케이션의 요구사항에 따라 실패 탐지의 방법과 복구 방법을 개발해야하며, 메시징을 위해 RPC 프레임워크나 ESB를 개발하는거나 적절한 대안을 탐색하는 것, 새로운 애플리케이션의 특성에 적절한 분산 스토리지를 개발하거나 탐색하는 것 모두가 비용에 해당하는 것입니다. Erlang이 이에 게재되는 모든 문제를 해결하는 것이라고 생각하지는 않지만, 일부는 해결해주고 있다고 생각합니다.
한편으로는, Shared-nothing 아키텍쳐의 애플리케이션, 즉 상태를 공유하지 않아도 되는 애플리케이션은 개발하기도 쉽고, Scalability도 쉽게 보장되기 때문에, 비용은 애플리케이션 환경이나 요구사항에 따라서 다르겠지만, 상대적으로 쉬운 문제입니다. 정말 어려운 문제는 상태 즉, 안정적인 스토리지에 있습니다. 물론, 안정적인 스토리지의 구현에도 Erlang은 위에서 언급한 면에 커다란 도움을 줄 수 있다고 생각합니다만, 단지 구현상의 문제라고 보기에는 현실과 거리가 있다고 생각합니다. 안정적인 스토리지의 문제 전체 영역은 Erlang이 해결하는 영역에 비해서 훨씬 크다고 생각합니다.