Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Node에서 작은 범위의 확장 vs 넓은 범위의 확장

몇일전에 Node.js의 확장성에 대해서 흥미로운 글이 올라와서 찬찬히 읽어보면서 번역한 내용을 올립니다.(번역은 발번역.. 덜덜) 제가 현재 만지고 있는 스칼라와 Node라는 두 기술을 다 다루고 있기 때문에 저로써는 더 흥미로웠습니다.(물론 스칼라에 대한 얘기는 그다지 많지 않습니다.)



Node에서 작은 범위의 확장 대 넓은 범위의 확장
Node and Scaling in the Small vs Scaling in the Large


[원문]

BankSimple 서비스에 어떤 기술을 사용할지를 몇주동안 고민했습니다. Programming Scala의 공동저자라는 이유로 대부분의 사람들은 스칼라를 선택할 것이라고 생각했지만 이는 제가 공학 문제에 접근하는 방법이 아닙니다. 모든 문제에는 적절한 기술들이 있고 이를 제대로 사용하는 것은 기술자의 몫입니다.
(덧붙히자면 BankSimple에는 통합할 서드파티 자바코드들이 꽤 있기 때문에 Scala가 적합할 것이지만 이는 완전히 다른 주제입니다.)

Node는 Hacker News에서 가장 많이 이야기되는 기술 중 하나입니다. Node는 이벤트기반의 자바스크립트를 V8 가상머신위에서 동작하도록 하는 프레임워크입니다. 어떤 기술을 사용할지를 고민하면서 Node에 대해서도 고려했습니다. 어제 Node에 대한 일반적인 회의론을 트위터에 올리자 Node의 창시자인 Ryan Dahl이 더 자세히 이야기해 달라고 해서 이렇게 글을 올립니다.

뛰어난 프로그래머이면서 괜찮은 사람인 Ryan을 비난하기 위한 글은 절대 아닙니다. Ryan은 저레벨 C에 대해서 우리 대부분이 바라는 것보다 훨씬 많이 알고 있다는 것은 굳이 자세히 얘기하지 않아도 될것입니다. 그리고 빠르게 성장하는 열정적인 Node 커뮤니티에 의문을 가지는 것도 아닙니다. Node 커뮤니티처럼 즐겁게 작업할 수 있는 도구를 찾아서 함께 하기로 했다면 더욱 강력해 질 것입니다.

이 글은 오히려 Node 프로젝트의 2가지 목표에 대한 의문이고 이 2가지는 서로 상충하는 것으로 보입니다.



Node의 목표가 무엇인가?
다음은 Node 홈페이지의 소개부분입니다:

Node의 목적은 확장성있는 네트워크 프로그램을 쉽게 만들수 있도록 하는 것입니다.
그 다음 문단에는 다음과 같이 써있습니다:

블락킹이 없기 때문에 전문가가 아닌 프로그래머도 빠른 시스템을 Node로 개발할 수 있습니다.
그래서 Node의 목표가 확장성있는 네트워크 프로그램을 쉽게 만들게 해주거나 전문가가 아닌 프로그래머도 "빠른 시스템"을 개발할 수 있도록 하는 것인가요?

이 두 목표는 관련있는 것처럼 보이지만 현실에서는 완전히 다른 것입니다. 왜 그런지 이해하려면 제가 "작은 범위의 확장"과 "넓은 범위의 확장"이라고 하는 것들의 차이를 이해해야 합니다.



작은 범위의 확장(Scaling In the Small)
작은 시스템에서는 보통 어떤것이든 동작합니다.

비효율적인 데이터 접근과 스토리지 패턴에 캐쉬나 분산시스템도 없이 지역화도 신경쓰지 않으면서 가장 느린 프로그래밍 언어를 사용하더라도 수천명이 사용하는 웹애플리케이션을 만들 수 있을 정도로 현재 하드웨어의 성능이 좋아졌습니다. 이렇게 하드웨어가 좋지 않은 결정을 하는 것 보다도 빠르게 발전하기 때문에 가능한 모든 안티패턴을 사용해도 실행가능한 시스템을 만들 수 있습니다.

사실 이것은 놀라운 일입니다. 이는 어떤기술로도 아무렇게나 프로토타이핑을 할 수 있다는 의미이고 이러한 프로토타입은 생각보다 오래 유지되기도 합니다. 어떤 장애물을 만났을때도 별로 어렵지 않게 해결할 수 있다는 것입니다. 문제에 대해서 몇분 정도만 생각하면 해결할 수 있고 좀더 나은 구현기술을 선택하면 해결할 수 있습니다.

이곳이 Node가 적합한 곳이라고 생각합니다.

Node로 몰려드는 사람들을 보면 공손하게 제한된 성능 특징이라고 부르는 다이나믹언어 개발자들이 많습니다. 아키텍쳐에 Node를 추가함으로써 개발자들은 본질적으로 동시성에 대한 경험도 없고 극히 부자연스러운 런타임 성능만을 가지고 있다가 비교적 훌륭한 성능의 가상머신에서 동작하는 절반정도의 동시성 경험(이는 Node프레임워크가 엄격히 강제합니다.)을 가지게 되는 것을 의미합니다. Node에서 비동기적으로 재작성함으로써 애플리케이션에서 어려운 부분을 없애버렸습니다.

이는 놀라운 일이지만 명확하게 "전문가가 아닌 프로그래머"가 "빠른 시스템을 개발할 수 있다"는 Node의 두번째 목표입니다. 하지만 더 보편화된 넓은 범위의 확장에서는 할 수 있는 것이 별로 없습니다.



넓은 범위의 확장(Scaling In the Large)
대형 시스템에서 마법총알은 존재하지 않습니다.

시스템에 부하가 생겼을 때 어떤 기술로도 완전히 해결하지 못합니다. 확장작업을 한다는 것은 복잡성 해결이나 잘 적용된 기술의 조정, 개발능력, 통계적인 분석, 인프라조직적인 의사소통, 적절한 엔지니어링 관리, 빠르고 신뢰적인 하드웨어와 소프트웨어의 운영, 빈틈없는 모니터링 등등을 말합니다. 확장하는 것은 어렵습니다. 사실 너무 어렵기 때문에 확장성은 아주 경쟁력있는 장점이고 간단하게 가질수 있거나 다운로드하거나 복사, 구입 또는 훔칠 수 있는 성질의 것이 아닙니다.

이것이 "확장성있는 네크워크프로그램을 쉽게 만들게 해준다"는 Node의 주목표에 대한 비판입니다. 근본적으로 확장성을 쉽게 해주는 방법이 있다고 믿지 않습니다. 사람들은 보통 쉬운 문제와 쉬운 해결책을 헷갈려 합니다.

아주 제한적인 기술에서 좀 더 나은 기술로 바꾼다고 해결할 수 있다면 운좋게 쉬운 문제였다는 것이고 확장을 했다는 것을 의미하지는 않습니다. 트위터는 서비스를 확장하면서 엔지니어중 한명이 루비기반의 사내 메시지큐스칼라로 재작성하면서 해결한 것이 이러한 경우입니다. 물론 대단한 일이지만 작은 범위의 확장입니다. 넓은 범위의 확장은 기술을 선택하는 것보다 훨씬 어려운 일이기 때문에 트위터는 넓은 범위의 확장에서 여전히 힘든 싸움을 하고 있습니다.



성숙해지고 있는 Node
엔지니어에게 작은 범위의 확장에서 넓은 범위의 확장으로 이동하는 것이 어려운 일이라는 것이 Node에서 제가 걱정하는 부분입니다.(여러번 들어봤다고 하더라도 "콜백이 스파게티 코드를 만든다"는 논쟁을 하는 것이 아닙니다. 물론 콜백은 비동기 시스템에서 어려운 부분이긴 합니다.)

Node의 뛰어난 부분은 모든 것이 파일I/O에 적합한 비동기라는 것입니다. Ryan가 Node에 대해 가지는 일관성과 명확한 가설에 대한 약속에 감탄하고 있습니다. 시스템의 작업부하에 대해서 깊히 이해하고 있는 엔지니어라면 Node 모델이 잘 맞는 곳을 찾아서 효과적으로 적용할 수 있을 것입니다. 이는 Node가 오랫동안 성숙한 개발이 이루어지기 전에는 알 수 없을 것입니다. 제가 작업했던 대부분의 변경작업이 그러했습니다. 데이터는 변경됩니다. 비동기 솔루션으로 잘 해결했지만 갑자기 이제는 쓰레드 기반이 더 나은 상황이 되거나 그 반대가 될 수 있고 혹은 전체적으로 바꾸어야 할 수도 있습니다.

Node에 대해서 깊게 열중했다면 동시성에 접근하는 한가지 방법에 열중한 것입니다. 문제와 해결책을 모델링하는 한가지 방법을 의미합니다. 이벤트 기반의 모델이 적합하지 않다면 당신은 속은 것입니다. 반면에 여러가지 동시성 접근(JVM, CLR, C, C++ GHC 등등)을 가진 시스템에서 작업한다면 동시성 모델을 바꾸는 유연함을 가질 수 있습니다.

이 순간까지도 이벤드가 반드시 성능이 좋다는 노드의 핵심 전제는 의문입니다. UC 버클리의 연구자들은 "높은 동시성, 낮은 오버헤드, 간단한 동시성 모델 지원을 포함한 모든 이벤트 기반의 장점을 쓰레드에서도 이룰수 있다는 것"을 알아냈습니다. 이에 대한 연구는 후에 이벤트와 파이프라이닝 접근은 동일하게 수행된다는 것을 보여주고 블락킹 소켓은 사실상 성능이 더 높아질 수 있다는 것을 보여줍니다. 자바진영에서는 넌블락킹 I/O가 항상 쓰레드보다 더 좋은 것은 아니라는 이야기가 정기적으로 나옵니다. 이 주제에서 애용되는 분석중 하나는 약간 노골적인 제목의 왜 쓰레드는 나쁜 아이디어인가(Why Threads Are A Bad Idea)이고 고성능 서버에서 쓰레드를 버리면 안된다는 결론에 다다릅니다. 광범위하게 적용할 수 있는 동시성 해결책은 없습니다.

사실 동시성에 하이브리드 접근을 하는 것은 학계의 방향에 관계없이 전진하는 것처럼 보입니다. 펜실베니아 대학의 컴퓨터 과학자들은 쓰레드와 이벤트의 조합이 양쪽세계의 최상의 것을 제공한다는 것을 알아냈습니다. EPEL의 스칼라팀은 Actor가 쓰레드 기반과 이벤트 기반의 프로그래밍을 쉽고 만족스러우면서 알기도 쉬운 하나의 추상화로 통합할 수 있다고 주장하고 있습니다. 벨 연구소에서 근구했었고 지금은 구글에서 Go 프로그래밍 언어 프로젝트를 하는 Russ Cox는 쓰레드냐 이벤트냐 하는 것은 터무니없는 질문이라고 이야기합니다.(이것 중 어느것도 시스템을 확장하는 분산적 관점에는 도달하지 못했습니다. 쓰레드는 단일 컴퓨터를 위한 구조이고 이벤트는 단일 CPU를 위한 구조입니다.) Erlang에서처럼 간단한 방법으로 머신을 넘나드는 분산작업에 대해서는 얘기하지 않았지만 빠르게 성장하는 시스템을 다루고 있다면 생각해 볼 가치가 있습니다.

그래서 관점은 다음과 같습니다. 노련한 엔지니어는 쓰레드기반과 이벤트기반, Actor나 실험적인 STM같은 대안적 동시성 접근을 섞어서 사용합니다. 그들은 "넌블락킹은 빠르다"라는 아이디어는 약간 어리섞다고 생각합니다. 이것은 확장성에 대한 도시적 미신입니다. 더 좋은 확장 솔루션을 가진 사람들은 한밤중에 Node로 시스템을 재작성하지 않습니다. 그들을 그들이 항상 했던 측정, 테스트, 벤치마킹, 생각하기, 문제에 적합한 학문적인 문헌을 유지하는 것을 하고 있습니다. 이것이 넓은 범위의 확장에서 필요한 것입니다.



결론
제가 엔지니어링에 시간을 투자한 결과 비동기와 다른 동시성 모델방법을 섞을 수 있는 유연함을 가진 시스템에서 더 작업을 하고 있습니다. 하이브리드 동시성 모델은 그리 간단하지 않고 Node의 접근처럼 순수하지도 않지만 융통성을 가지고 있습니다. BankSimple은 초기단계이기 때문에 작은 범위의 확장으로도 괜찮은 문제들을 가지고 있고 Node는 이 초기단계에서는 납득할만한 선택일 것입니다. 하지만 넓은 범위의 확장이 필요해 졌을때를 생각하면 더 많은 가능성을 열어두고 스트레스를 받으면서 크게 재작성해야 하는 상황에 직면하지 않을 것입니다.

Node는 열정적인 커뮤니티와 똑똑한 커미터들, 밝은 미래를 가진 사랑스러운 코드입니다. 특히 다이나믹 언어의 배경을 가진 넓은 웹개발자 세대가 만날 수 있는 초기 확장문제를 당장 해결할 수 있는 "브릿지 기술"로써 적당합니다. 노드는 네트워크 기반의 문제들을 해결할 필요가 있는 중급개발자들에게 납득할만한 성능을 가져다 준다는 면에서 두번째 목표에 더 적합합니다. 특정계열의 개발자들에게 Node는 익숙하고 재미있습니다. 그리고 시작하기 쉽다는 것도 부인할 수 없습니다. Node 커뮤니티는 웹프레임워크, 패키지 관리, 테스팅 라이브러리등 익숙한 수레바퀴를 다시 만들면서 좋은 시간을 보내고 있습니다. 이들을 시기하는 것이 아닙니다. 모든 프로그래밍 커뮤니티는 자산들에게 맞게 이러한 것들을 다시 만듭니다.

Node가 어디에 적합한지는 명확하지만 중요한 확장문제에서는 만병통치약이 없다는 것을 알아야 합니다. Node와 엄격한 비동기 이벤트기반의 접근은 넓은 범위의 확장을 포함하는 기술과 방법론의 흐름에서 아주 초반지점에 있다고 생각합니다.

인기있는 솔루션에 접근할 때는 신중해야 합니다. 모든 사람이 인기있는 새기술을 사용하는 것 같지만 극소수는 그들만의 속도로 확장작업을 실제로 이뤄내고 있습니다. 작업과 연구를 존중하는 이들이 시간이 지나면서 도구와 기술을 성숙시키고 있습니다. 새로운 기술에 시간을 들이고 있다면 배우고 함께 성장할 준비를 해야 합니다. 그리고 스스로 부자연스러운 점을 찾아냈을 때 갈아타야 할지도 모릅니다.

물론 이것은 쉽지 않습니다.



이 글에 대한 노드커뮤니티의 반응은 침착한 편이라고 생각됩니다.

가정자체가 잘못되었다거나 Node에도 worker가 있는데 무슨 소리냐 하는 등의 반응도 있지만 대부분은 일리있는 지적이고 생각해 볼만한 글이라는 얘기가 많습니다.

몇가지 인상깊었던 부분은 본문의 "쓰레드는 단일 컴퓨터를 위한 구조이고 이벤트는 단일 CPU를 위한 구조입니다."에 동의할 수 없다고 하니까 이는 "쓰레드는 시스템 레벨의 개념이고 이벤트는 애플리케이션 레벨의 개념이다"라고 정정한 부분입니다.

그리고 가장 인상깊었던 이야기는 개발자가 비개발자보다는 훨씬 합리적인 성향을 가지고 있지만 우리도 사람이기 때문에 비합리적으로 행동하기도 하는데 개발자들이 기술적인 논의를 할때 중요한 사실을 잊어버리고 있다는 것이었습니다. 그것은 우리는 우리가 사용하는 도구를 사랑하기 때문에 사용하는 것이고 사용하면서 행복을 느끼지 못한다면 우리는 도구를 바꿀 것이라는 것입니다.

2011/09/09 02:57 2011/09/09 02:57