Live Engineering


애드센스 와이드


Golang 을 보고...

나는 프로그래머다의 애청자로서 자주 언급되었던 golang 에 호기심이 생겨 간단히 언어의 생김새를 살펴보았는데, 꽤 흥미를 끄는 부분이 있어 일하다말고(;) 잠시 생각을 공유한다. 

언어의 어떤 특성에 매료되는지는 사람마다 다를 것이다. 내 경우는, Java는 학교 과제 때문에 어쩔 수 없이 시작했지만 C/C++과 유사한 문법에 포인터의 명시적 사용 없이 객체를 가리킬 수 있다는 점이 좋았고, 이후에는 풍부한 오픈소스 생태계는 말할 것도 없거니와 구글 Guava 라이브러리를 사용해보면서 문법 구조를 유지하면서 저런 스타일의 API 디자인을 할 수 있다는 점에 감명을 받았다. Python의 경우에는 추가 라이브러리 없이도 풍부한 built-in data structure 를 쓸 수 있고, 거의 모든 리눅스 배포판에 기본 설치되어 있다는 점이 좋았고, django 나 flask 등으로 웹애플리케이션 프로토타입을 매우 손쉽게 만들 수 있다는 거, 그리고 별거 아닐지 모르지만 interactive 모드로 코드 한줄한줄 쳐가며 바로 결과를 보며 디버깅한다던지 하는게 넘 편하고 좋았다. 특히 이 파이썬은 내 박사과정 내내 실험, 결과 분석, 그래프 플롯팅 스크립팅에 지대한 공헌을 하였으므로 한줄 더 언급해도 좋을 것 같다. C의 경우, 포인터의 큰 팬은 아니지만, 리눅스 커널 공부를 하면서 function pointer를 어떻게 예술적으로 사용하여 어떻게 monolithic 한 linux kernel 이 모듈화가 될 수 있었는지를 배웠고 임베디드나 시스템 분야에서는 꼭 필요한 메커니즘임을 인정치 않을 수 없다. Force.com 플랫폼의 apex language 에 대해서는 회사 업무상 깊게 접해볼 기회가 있었는데 추가 포스팅이 필요할 것 같은데, 클라우드 앱을 짜는데 있어서 정말 쉽고 빠른 효율적인 언어임을 강조하고 싶고, 언젠가 기회가 되면 google appengine 과의 일대일 비교 등을 해보고 싶다. 간단히 말하면, MVC 구조의 전통적 웹애플리케이션을 포인트-앤-클릭 수준으로 손쉽게 후딱 만들수 있고, 원한다면 회사 고유의 비즈니스 로직에 맞게 customize 하는것도 가능하고, 클릭 한번에 클라우드에 deploy 가 되며, 모바일 앱과의 연동 및 앱 자체의 손쉽게 빌드하는 것도 도와주며, 자바스크립트 코딩 한줄 없이 매우 미려한 그래프 플롯팅도 가능하고, ... 이상의 설명은 다음 포스팅을 위해 아껴둔다. 

여하튼, 아직 golang 코드 한줄도 짜보지 않은 상태에서 문법만 보았을때 어떤 특성이 가장 좋았냐면, 나는 단연코 goroutine 과 channel 을 이용한 concurrent programming 을 꼽고 싶다. 좀더 간단히 말하면, asynchronous task를 위한 thread를 spawn 하고, 결과값을 받아오는 코드가 golang 의 언어적 특성으로 지원된다는 점이 가장 매력적으로 보인다. 이것이 왜 그렇게 멋져보이는가를 묻는다면, 그 이전에는 어떻게 이 목적을 달성할 수 있었는가를 보면 되지 않을까. 논의를 위해 C로 언어를 한정해 설명하겠지마는, 아마 다른 언어에는 내가 모르는 더 좋은 feature 가 있었을지 모른다는 점을 짚어두고 넘어가겠다. 

분산 컴퓨팅 환경에서 계산 및 스토리지 리소스를 "분산" 하는 것 못지 않게 중요한 기능은 결과를 "수집" 하는 것이라 볼 수 있다. Map 과 Reduce 가 하나의 단어 (MapReduce)로 자주 쓰이는 것도 같은 이유일 것이다. 거창하게 Hadoop 같은걸 만들려 하지 않아도 이는 작은 toy 프로그램에서 조차도 아주 쓸모있는 기능인데, 가령 web crawler 를 만들때 이걸 하나의 프로세스/쓰레드로 동작하도록 만든다면, 하나의 요청이 끝난 상태에서만 다음 요청을 처리할 수 있기 때문에 호스트의 리소스가 under utilized 되고 다중 쓰레드를 쓸때보다 훨씬 오랜 시간이 걸려 끝날것이다. 거의 모든 언어에서, 현재 실행중인 process 의 클론을 만드는 기능을 지원하는데 (사실은 OS의 fork() 시스템 콜을 이용할 테니 OS의 기능이라 봐야겠지만), 이 경우 parent process가 child process의 결과값을 가져오는 것은 당연한 수순일진대, 이 기능이 언어 차원에서 OS 서비스를 wrapping 해서 지원되기 보다는 매우 primitive 한 형태로 이용되어 왔다고 생각한다. (아, 여기서 Golang 이 이 문제를 처음해결한 언어라 말하는 것은 아니다.) parent 와 child process 가 계산 결과를 주던지 받던지 하려면 어떠한 형태로든 공유된 리소스에 의존을 해야만 할텐데, 다음의 몇가지 방법을 생각해 볼 수 있을 것이다:

1) child process 가 계산 결과를 파일시스템에 남긴다 (즉 결과 파일을 만든다). parent process 는 약속된 이름 (가령 child pid + blah blah .txt) 으로 부터 결과를 읽는다. 아니면, 이것의 변형으로 memory mapped file 을 사용하던지 tmpfs, 아니면 아예 DB 같은걸 쓸 수도 있다. 
2) child process를 fork 할때 애초에 쓰레드로 만든다 (pthread lib 같은걸 써도 되고). 즉, 이 경우 child process 는 parent process와 page table 을 완전히 공유하게 되고 (즉 virtual address X -> physical address Y 의 매핑이 둘간에 동일하다게 된다), 둘이 동시에 볼 수 있는 queue, stack 등의 데이터 구조에 push, pop 을 한다. 
3) child process와 parent process 간에 socket 으로 통신한다.
4) child process와 parent process 간에 shared memory 로 통신한다.
5) child process와 parent process 간에 pipe 로 통신한다.

어느 쪽이든, 단순한 기능의 병렬화 대가로 위의 옵션들은 골치가 아프다. 가장 나은 옵션을 꼽으라면 개인적으로는 3번을 꼽겠다. 일단 모든 항목들이 어느 정도의 코딩을 요구하는데, 이중 golang 의 channel보다 쉬운 걸 찾기가 힘들었다. 추가적으로, 1번의 경우 child process가 도중에 crash 가 되었다던지 등의 사건이 생겼을때 parent process가 어떻게 그것이 현재의 "run"에 의해 생성되었다는 걸 알까? 어떤 식으로는 timestamp 를 결과에 넣고 이걸 validate 해야 하고 등등이 필요하겠고 clean up 코드도 있어야 겠다. 2번의 경우, multi threading 이 제대로 동작하려면 shared variable 에 semaphore 나 spin lock 등을 걸어서 프로그래머가 직접 synchronization 을 컨트롤 해주어야 하는데, 이것이 꽤나 귀찮고 때때로 어렵다는건 따로 설명 않겠다. 3번의 경우, local host 에서 두 프로세스간 socket 통신을 하면 TCP 스택을 전혀 거칠 필요가 없으므로 성능이 괜찮게 나온다. 다만 socket programming 이 필요하고, non-blocking 으로 polling 하는거 등등 직접 구현해줄게 좀 있다 (golang 의 select 같은... toy 프로그램에서는 상관없겠지만). 4번의 경우 2번과 비슷하게 sync 를 프로그래머가 직접 맞추어 주어야 한다. 5번의 경우 pipe 의 구현이 OS 에 매우 dependent 하게 구현이 되어 있으며 기본 사이즈 제한이 있어서 output size 에 따라 broken pipe 에러를 꽤나 자주 볼 수 있다. 

3번이 가장 그래도 개인적으로 나은 옵션이라 했지만, 여전히 프로그래머가 marshalling/unmarshalling 등을 신경써주어야 하고, socket resource 가 무제한으로 제공되는 값싼 리소스가 아니라는 점, 에러 핸들링을 신경써주어야 한다는 점 등등... 이것들을 쉽게 쓰도록 도와주는 framework 들이 있을거라 믿어 의심치 않지만, 이런 것들을 설치하고 검증하고 해야 하는 고통을 모든 프로그래머가 동일하게 겪어야 된다는 건 심각한 낭비다. 

Golang 이 이런 가려운 부분을 긁어주고 있다고 본다. <-, -> 와 같은 깜찍한 심볼로 data direction 지정을 해주고 channel 에 type 지정을 해주면 marshal/unmarshal 도 손쉽게 해결이 되고 (아직 얼마나 flexible 할지에 대해서는 감이 없지만). 또한 여기에는 프로그래머들에게 message passing 스타일로 분산 프로그램을 짜라는 암묵적인 강제를 함으로써 synchronization issue 를 잠재적으로 제거하는데 도움을 주고 있다. MPI vs. OpenMP 의 대결에서 MPI 의 가장 치명적인 단점으로 지목되었던 것중 하나가 프로그래머가 프로그램을 재작성해야 한다는 것인데 (명시적으로 프로세스간 message를 send/receive 하는 스타일로), 애초에 golang 으로 짜여진 프로그램은 마치 공짜(?)로 그런 잇점을 얻는다는 환상을 주니 얼마나 좋은 선택인가. 사실, 정확히 같은 이유로 Erlang 에도 관심이 많이 있는데 (Riak, CouchDB가 이걸로 짜여있대서 관심이 많다는), community support 에 대한 확신이 크게 없어 깊이 다뤄볼 기회는 없었다. 하지만 Golang 이라면? 위에 잠깐 언급했지만 Golang 이 이런 비동기 쓰레드간 통신을 손쉽게 해결한 최초의 솔루션은 아닐 것이다. 당장 머리위에 떠오르는 생각으로는 병렬처리 수업시간때 잠깐 배웠던 MIT Cilk 도 비슷한 문법을 가지고 있는 것 같고, 아마 수십년전에 누군가의 머리에서 나온 생각이었을 거라 믿는다 ㅋ

여기부터는 뜬금없는 리서치 이야기. Golang 관련 글을 보면 goroutine 은 thread 로 구현이 되어 있고, local stack size 가 static 이 아니고 dynamic 하기 때문에 수백만 thread 생성도 문제가 아니라는 이야기를 하는데, 벤치마킹을 해본건 아니지만 이게 사실이라면 이또한 아주 훌륭한 특성이다. Large-scale internet service를 만들기 위해 thread-driven 으로 가야 하느냐 event-driven으로 가야 하느냐의 싸움에서 (혹은 C10K, C100K 이슈), thread-driven 으로 가려면 local thread stack 이 2 MB 나 되기 때문에, 당시 머신에서 천개 쓰레드 정도밖에 못만들고, 이를 해결하려면 stack sharing 등등의 최적화를 해서 십만개 정도를 만들었다는 논문을 OS 수업시간에 배웠던것 같은데 (여기 수치는 부정확할 수도; 2000~2006 년 사이의 SOSP/OSDI 논문을 찾아보아야 함), golang 이 어떤 구현을 했는지는 모르겠지만 혹 thread-driven scalable HTTP server 라는 목적이 golang 으로 이루어질 수도 있는거 아닌가하는 뜬금없는 생각도 들고... golang 의 channel 이 발생시키는 sub-milliseconds latency 가 high performance SSD 등에 어떤 영향을 미칠 수 있는가를 분석해보는 것도 리서치 이슈가 될 것 같기도 하고... 만약 여기에서 뭔가 재밌는 리서치 이슈가 생긴다면, Moneta-D 같은 방식으로 user-level로 storage stack 을 가져와서 그걸 golang 으로 해결해보는 것도 재밌을 것 같다. NVM I/O path 에 asynchronous task 에 대한 의존도가 무척 큰 것 같은데, 그 철학이 golang 과 궤를 같이 하는 것 같은 느낌을 받았기 때문. 언젠가 연구할 수 있는 시간이 다시 돌아온다면!

여하튼 Golang 재밌을듯! 시간나면 공부해볼 가치가 있을 것 같다는 결론.

알뜰 프로그래밍 (economical programming)

최근 6개월간 정말 정신이 없었는데, 이직, 이사, 득녀(!)를 하였기 때문이다. 왜 조금 쉴만해지면 다시 바빠지는지, 아무래도 편하게 살 팔자는 아닌가보다. 아무튼 너무 즐겁고 기쁜 경험이었지만 한편으로 육체적/정신적으로 궁지에 몰리기도 하는 힘든 시기였음을 고백한다. 아무튼 새로운 회사에 적응하면서 떠오르는 여러 잡생각들을 그대로 흘려보내는 것이 아... » 내용보기

몇가지 게임 리뷰

이래저래 바쁜 일상으로 한참 게임을 잊고 살다가, 반년 전쯤 엑박 360을 싸게 매입하여 틈틈이 게임 라이프를 즐기는 중. 그전까지 가지고 있던 콘솔은 ps2, xbox (구엑박), nds. 이미 ps4 나 xbox one 이 나온 시점에 늦은 감은 있지만, 이미 격세지감을 느끼며 숨막히는 연출에 깊은 감동을 받은바, 간단히 개인적인 평점과 소감을 말해... » 내용보기

인터페이스 싸움

싸움 구경은 매우 재미있다. 사람간의 물리적 싸움이든, 스포츠를 통한 팀 싸움이든, 산업계의 기술/광고 싸움이든, 학계의 논문 싸움이든. 게다가 호각일 경우는 재미가 배가 된다. 오늘 포스팅은 학계의 논문 싸움, 그 중에서도 인터페이스 싸움에 관한 짧은 생각이다. CS에서 시스템 분야의 논문들 중에 재미있는 한 꼭지를 꼽으라면... » 내용보기

아마존 프라임 뮤직 (Prime Music)

In designing Prime Music, we wanted to remove the barriers between you and the music you love. We removed cost. You can listen to the entire Prime Music catalog for free — it's included in your Prim... » 내용보기