최근에 대규모 고성능의 채팅 애플리케이션 아키텍쳐를 구상하는 중에 ZeroMQ라는 프로젝트를 발견했습니다. 그리고 더 많은 검색을 통해 nanomsg가 ZeroMQ의 포크 버전이고 현재는 NNG(Nanomsg-Next-Generation)에서 활발히 개발이 진행되는 것을 보았습니다. 그리고 이것이 충분히 RabbitMQ 혹은 Redis의 대체제가 될 수 있을 것 같다는 생각이 들었습니다. 가장 큰 이유로는 다음과 같습니다:

  • 확장성을 고려하고 지원
  • 임베디드 장치에 사용될 정도의 가벼움
  • 필요한 기능만 구현할 수 있도록 하는 작고 빠른 기능
  • 대규모 스트림 처리도 중요하지만 채팅 메세지를 빨리 전달할 수 있는 저지연성

현재 상황이 제품을 빠르게 서비스해야 하는 상황이 아니기 때문에 당장 문제없이 당장 간단한 C 코드를 구현하여서 확인을 하려고 했습니다. 하지만 당장 C 생태계에 대한 정확한 지식없이 나오는 arm64 관련 컴파일 오류들을 해결하기에는 어려움이 있었고 진행하는 프로젝트에 대한 흥미를 잃기 싫어서 당장 커뮤니티를 찾았습니다.

GitHub - nanomsg/nng: nanomsg-next-generation -- light-weight brokerless messaging
nanomsg-next-generation -- light-weight brokerless messaging - GitHub - nanomsg/nng: nanomsg-next-generation -- light-weight brokerless messaging

그리고 NNG 프로젝트 Discord 서버를 찾을 수 있었습니다. 생각 이외로 잠잠한 서버였기에 당장 질문을 올려서 답변을 받을 수 있다는 희망감이 크지는 않았지만 일단은 질문을 올렸습니다. 정말로 저는 성능에 민감한 사람이고 당장 도움을 받아 진행하여 비즈니스가 포함되지 않은 이 상황에서 성능 최적화가 된다면 미룰 일이 아니라고 생각했기 때문입니다.

Seia — 02/10/2021
It would be nice if I can develop nng application natively on M1. I know that I can do it by installing all components like cmake in x86 releases but not that nice as I need to setup things in different architecture again.
Is there anyone tried nng with arm? Not cross compiling x86 to arm.
Happy to know if there is anyone in like my situation :)

의외로 생각보다 일찍 답변이 도착했습니다. 라즈베리파이에서 정상적으로 컴파일이 가능하다는 것이였습니다. 하지만 물론 Homebrew를 통하여 ARM64 릴리즈를 사용할 수 있다는 점에서 그리고 Homebrew를 통하여 컴파일을 할 수 있었다는 점에서 제 질문이 정확하게 전달되지 않았다는 것을 깨달았습니다.

robiwan — 02/10/2021
I've built/used nng on a Raspberry Pi.
Raspbian OS with default gcc/cmake/ninja

하지만 곧바로 프로젝트 핵심 개발자분에게서 메세지가 도착했습니다.

gdamore — Yesterday at 00:41
Probably not.  Some of the symbols are explicitly private.
Which symbols is it complaining about.
I am going to be ordering an M1 MBA so that soon this will be more commonly tested.
Having said that you will probably want a full arm64 tool chain.
I really don’t think the process for M1 should be any different than the x86 process. Except you need Xcode that works on M1.  Might need a newer CMake too - as CMake had OS awareness.

잇따른 대화에서 저는 제가 C 생태계에 익숙하지 않음을 정확히 하였고 다행히 개발자 분은 정확히 제 니즈를 캐치해주시고 적절한 대안을 이야기해주셨습니다. 이 자리에서 다시 감사하다는 말씀을 남깁니다.

gdamore — Yesterday at 03:11
Node doesn’t scale well.
->
Seia — Yesterday at 03:12
Yes, it has too much overheads.
->
Seia — Yesterday at 03:12
I already searched Kafka but seems like nng can do this better because I am developing chatting server.
->
gdamore — Yesterday at 03:12
But if you can tolerate some latency you can make it better using nng devices.

최종적으로는 조언에 따라 NNG의 Go 버전인 mangos를 시도해보게 되었습니다.

gdamore — Yesterday at 03:12
It might be easier to do this in go with mangos if you’re not comfortable with C.
Mangos will scale very well and is wire compatible with NNg and nanomsg
It’s a lot easier working from go.

새 프로그래밍 언어 시작하기

제가 새 프로그래밍 언어를 배우는 과정은 Node.JS를 통한 기초 확립 이후에 단순해졌습니다. 바로 버전 매니저를 찾고 공식 문서를 읽는 것입니다.

GVM: Go Version Manager

버전 매니저는 대부분의 언어에 실존합니다. 그리고 개발을 하다보면 분명히 새로운 버전의 프로그래밍 언어 런타임이 배포될 것이고 혹은 개발 중에 요구되는 버전이 있을 것이기 때문에 버전 매니저를 설치합니다. asdf-vm이나 sdkman같은 통합 소프트웨어 버전 매니저도 존재하지만 저는 통합 버전 매니저의 방식이 익숙해지지가 않아 하나하나 설치하는 방식으로 진행합니다.

GitHub - moovweb/gvm: Go Version Manager
Go Version Manager. Contribute to moovweb/gvm development by creating an account on GitHub.

그러나 M1인 관계로 새로 컴파일을 해야 하는 상황이었고 1.4 버전 이후에 기존에 설치된 Go가 필요한 것을 알아차렸습니다. 물론 1.4 버전 또한 M1에 준비된 버전은 아니었으므로 이 문제를 GVM 안에서 해결이 불가능하므로 일단 저의 최종적인 목표인 고성능의 PubSub 서버를 위해 직접 Go 홈페이지에서 런타임을 다운로드하여 설치하였습니다.

공식 문서 읽기

공식 문서를 읽는 것은 스스로 굉장히 좋은 습관이라고 생각합니다. 레거시한 코드 대신 언제나 신선한 코드가 제 머릿속에 첫 번째 습관으로 자리 잡을 수 있도록 돕기 때문입니다. 이는 제가 특히 사이클이 빠른 JavaScript 생태계에서 개발을 하면서 생긴 습관이기도 합니다.

블로그를 읽는 것이 분명히 도움이 안 된다는 뜻은 아니지만 되도록이면 최신의 그리고 검증된 튜토리얼로 시작하는 것을 좋아합니다.


Go은 어느 포지션에 위치해 있을까?

일단 저의 관점에서 살펴보면 무엇보다 좋습니다. 하지만 이 글에서 Go를 어떻게 시작하고 예제 코드 등을 다루지는 않을 것입니다. 느낀점을 서술해보자면 기초를 학습하며 가장 크게 다가온 것은 C스럽다라는 것입니다:

  • Go에도 포인터가 존재합니다
  • Strust라고 불리는, OOP 지향 언어에서 객체일 수 있는 것들이 존재합니다
  • 포인터라는 개념이 존재합니다
  • 가변 배열과 고정 배열의 개념이 나누어져 있습니다

그리고 C스럽지 않게 더 좋아진 것들이 굉장히 긍정적으로 다가오기도 했습니다:

  • 포인터는 자동으로 디레퍼런스됩니다
  • 함수 간에 "객체"를 레퍼런스하는 것과 단순히 형태를 넘겨주는 것의 차이가 존재합니다
  • 모듈 관리가 체계적입니다
  • 모든 코드가 IDE에서 별 다른 설정없이도 Lint될 수 있도록 플러그인이 준비되어 있습니다
  • 쉽습니다

마치 모던한 버전의 C 언어를 다시 배우는 느낌이었습니다. 또 그 외에 기존에 알고 있던 단일 실행 파일로 배포될 수 있다는 점 등등 굉장히 많은 장점이 동시에 활용될 수 있다는 것이 첫 인상을 더욱 좋게 만들었습니다. 특히 함수에서 객체를 레퍼런스하는 것이 선택적으로 다가온 지금 개발은 더욱 편해지지 않을까 하는 예상을 가지고 있습니다.

그리고 굉장히 쉽습니다. 한국의 커뮤니티를 중심으로 알고 있으나 많은 회사들에서 새로운 백엔드 스택을 고려할 때 Rust와 Go 중 하나를 고려하는 것을 보았습니다. 이 때에 Rust 대신 Go를 선택하는 것 자체가 이해가 되는 정도입니다. 제가 Rust를 처음 봤을 때에는 분명히 뭐가 이렇게 많은 느낌이 드는지 그리고 코드가 굉장히 복잡한 것처럼 보여졌습니다. 하지만 Go는 그렇지 않았습니다. 이 경험은 물론 개인적인 것이지만 단순히 Rust에서 제시되는 새로운 개념들이 생소하다기보다는 Go 자체가 굉장히 단순하다는 점이 더 크게 느껴졌습니다.

물론 Rust가 좋지 않다거나 하는 이야기는 아닙니다. 여전히 Rust는 좋은 언어이고 성능이 필요한 많은 곳에서 사용됩니다. 하지만 언어의 복잡도나 초기에 익숙해지는 시간 등의 면에서 살펴보았을 때 시장에 더 빨리 제품을 내놓을 수 있는 방법은 Go를 사용하는 것이라고 생각합니다. 그리고 이는 저에게도 굉장히 중요하며 제가 프로젝트의 성과없이 개발 시간이 길어지는 것을 잘 참는 편도 아니기 때문에 시간 상 Go로 개발하는 것을 선택했습니다.

Go의 장점 그 자체로 여러가지 면에서 좋은 경험이 될 것 같습니다. 이후에 그렇지 않다하거나 제가 빨리 포기하지 않았으면 좋겠네요. 👻