Thread design 02 - 잠금을 고민하지 않는 프로그래밍

Thread design에 대한 이해는, 기본적으로 잠금 정책에 over head를 이해하고 있느냐에서 출발한다고 생각합니다.

잠금 기반 프로그래밍은, 자주 사용하는 코드가 잠기게 될수록 성능이 수직 하향합니다. 대기 하느라, 제대로 된 퍼포먼스를 낼 수 없다는 얘기죠.

그렇게 하지 않기 위해, 객체 간에 잠금에 신경쓰지 않게끔, 객체 간 접점을 줄여주어야 합니다.

좋은 Thread design의 목표는 어떻게 잡아야 할까요?

  • 접점 최소화
  • 손쉬운 비동기 처리
  • 의도한 대로 순차 처리 (순서가 중요한 동작의 순서 보장)

디테일하게 나열하자면 얼마든지 많겠지만, 저는 위 세가지 목표가 보장된 기반 코드는, 컨텐츠 구현 시에 필요한 요구 사항을 다수 충족 시킬 수 있습니다.

이런 문제가 현세대 멀티스레드 프로그래밍의 최선이라고 여겨졌는지, 많은 솔루션이 이런 니즈를 충족시키는 데에 최적화되서 개발이 되었습니다.

node.js는 무거운 작업마다 비동기로 던지고, 그 결과 값을 바탕으로 진행할 다음 작업을 지정함으로써 잠금과 순서를 고민하지 않는 프로그래밍을 유도하고 있습니다. 만약 무거운 작업을 비동기로 처리하지 않는다면, 프로그래머의 실수라고 규정 짓는 가이드라인을 제시했습니다.

erlang도 마찬가지입니다. 기본적으로 메시지로만 통신을 유도하면서, 각 작업 간에 겹치는 상황을 제거함으로써, 잠금을 고민하지 않도록 했죠.

이렇게 할때의 언어에 구애 받지 않는 핵심은, 작업마다 독립적으로 동작할 수 있어야 한다는 점입니다.

로직을 작성하는 데에 있어서, 이 객체마다 잠금을 걸었다 풀어주는 과정은 잠재적 성능 저하 지점을 만드는 과정이라 볼 수 있습니다.

아무리 측정을 자주 하는 팀이라 할지라도, 기존에 (논리적으로도, 성능 적으로도) 잘 동작하던 코드가 병목이 될 수 있는지 여부는 의심을 덜하기 마련이기 때문이죠.

그런 잠재적 우려 지점을 변수가 추가될 때 마다 늘리는 방식은 결코 좋다고 보기 어렵다는 결론에 도달해, 현재의 모델이 최선이라고 느끼는 상황이죠.

애초에 작업들이 모두 작게 쪼개져 있고, 그간에 영향을 받지 않는다고 확신 할 수 있다면 당연하게도 대기 없는 비동기 처리가 가능해집니다.

로직을 작성하는 사람이 고민해야 될 대상중에 순서만이 남은 것이죠.

작업들을 비동기로 분리하고 난 뒤의 로직의 순서 조절은 상대적으로 쉬운 문제가 됩니다. 결합도를 고민하지 않아도 되는 상황이 되어버렸기 때문에, 순서 보장 기능을 라이브러리나 프레임워크 단에서 지원 (혹은 스크립팅으로 조절) 해주기 쉽고, 그렇지 않은 경우에 구현하는 문제도 순서 보장 작업끼리 같은 큐를 사용하게만 해줘도 되는 것이죠.

요약하자면 비동기 프로그래밍에서의 성능을 장점으로 삼는 다수의 언어와 프레임워크가 내린 합리적인 선의 비동기 프로그래밍은, 작업간 결합도를 줄인 후, 작업을 병렬로 수행해 성능 향상을 노리는 쪽으로 가고 있습니다.

제 생각도, 합리적인 선의 선택이라고 보여집니다. 극한의 성능도 중요하지만, 로직 작성의 난이도를 낮추는 것도 중요한 문제거든요. 실수할 여지를 줄이는 장점도 물론 옵션이겠고요.

지금까지 thread-design에서의 잠금 최소화 프로그래밍에 대해 알아보았습니다.

Rails 5.0 Release

Rails 5.0: Action Cable, API mode, and so much more

Rails 5.0이 정식 릴리즈 되었습니다.

드디어! 웹소켓을 지원합니다. Action Cable이 바로 그것이죠.

기존 rails의 구조가 1 request-1 response를 기반으로 하는 만큼, 얼마나 웹소켓의 이벤트와 Rails ActionController 코드와 유연하게 연동이 되는지는 궁금합니다.

벌써 한글로 된 채팅 앱 구현 포스트가 올라왔네요!

Api Mode는 back-end로 client-side javascript나 native-application과 JSON으로 통신이 가능하다고 하네요.

정확히 어느정도로 다른 어플리케이션과 유연하고, 성능상 잇점을 가져다줄 기능이 구현되었는지는 확인해봐야 알거 같네요.

빠른 개발 속도와, 상대적으로 낮은 학습비용에 비해 성능 문제와, 진입 자체는 쉽지만 많은 이해도를 요구하는 난제들도 함께 했던게 사실인 rails.

특히나 성능 문제로 인해 twitter는 rails를 포기하기도 해 많은 우려를 낳고 있었는데요, rails 5는 그런 우려를 불식시키고, 다시금 많은 장점으로 사랑받는 웹 프레임워크로 입지를 확고히할지는 더 두고 봐야할 문제라고 생각합니다.

자세한 Rails 5 차이점에 대한것은 제가 조금 더 사용해보고 알려드리겠습니다.

동기화에 대한 간략 정리

동기화 기본

목적

  • 모든 피어가 같은 결과를 얻게 하기 위함.

난제

  • 랜덤값 (시드 동기화)
  • 부동 소수점 실수 오차.

환경 변수

  • 어떠한 변수들을 동기화할것인가를 잘 결정지어야 한다.
  • 애니메이션 시스템에 영향을 주는 요소가, 커맨드 패턴으로 받는 변수 이외의 변수에 영향을 받는다면, 애니메이션 동기화는 불가능하다.
  • 또한 오브젝트간 충돌등의 물리처리가 중요하다면 이 것도 마찬가지로 관리해주어야 한다.

커맨드 패턴 사용

  • 서버가 난수까지 결정해서 주면 좋음.
    • 그럴러면 로직이 서버에 있는게 좋다.
      • 클라이언트는 결정지어진 결과값만 수신받아 표현한다라는 개념으로 가야 한다.
  • 티어간에 커맨드로 동기화를 하기 때문에, 동기화에 영향을 줄 임의 동작이 존재하면 안된다.

동기화 적용 시점

선동작 후보정

  • 액션성을 강조하기에 좋다.
  • 레이턴시가 클 수록 동작이 튄다.
    • A위치로 움직였다가, 서버 응답받고는 뜬금없이 B위치로 워프 하는 등의 동작을 함.
  • 지나치게 레이턴시가 커졌거나, 통신 오류가 발생했을 시에는 피어간 아예 다른 결과를 보게 되기도 한다.
  • 네트웍이 불안정할 수록 부적절하다.

응답 후동작

  • 레이턴시가 크면 클 수록, 느린 반응성으로 보인다.
    • 다만 모든 유저가 같은 결과를 볼 수 있다.
      • 결과를 받게 되는 타이밍은 차이가 날 수 있음. [응답을 받게 되는 시간이 얼마가 걸리냐에 달려있음]
  • 반응이 없을 순 있어도, 잘못된 결과를 보여주진 않는다.
    • 주로 MMORPG가 이렇게 구현되곤한다.

주고 받는 데이터의 형식

이벤트 단위

  • 어떤 동작을 했음을 전달하고, 해당 동작에 대한 동기화를 한다.
  • 커맨드 패턴화하기 딱 좋은 구조.
  • 로직 구현시 같은 Input (이벤트) -> Ouput을 보장하게 만들어야 한다.

상태 기반

  • 현재 어떤 상태가 됐음을 전송한다.
  • 기존 상태 -> 변경된 상태를 보간해야 하고, 보정 로직이 모든 유저가 일치하게 구현해야 하는 이슈가 있다.

동기화 주기

턴 베이스

  • 내부적으로 턴을 구성하는 방식이다.
    • 턴으로 구성된 로직 동기화 주기에 맞춰서, 패킷을 전송하고, 수신받아 이벤트 들을 처리한다.
  • 명확한 지연 허용 범위가 존재한다
    • n턴 이상 수신 받지 못하면, 통신 오류로 판정 가능하다.
  • 반응성에 대한 기준치도 존재해, baseline을 잡고 튜닝하기 좋다.
    • 결국 한 턴의 단위가 시간을 기준으로 하기 때문에 서버에서도 비정상적 일만큼 많은 패킷이나 과도하게 많은 액션을 수행하고 있는지 판별할 수 있는 기준이 되어준다.
    • 초당 처리 가능 패킷 수가 계산 가능한 수치가 되기 때문에, 기준을 잡을 수 있어 서버 당 수용 동접을 결정 짓기 쉬워진다.

패킷 단위

  • 동작마다 실시간 전송한다. nagle 알고리즘을 끄고 바로 바로 전송함으로써, 최대한 빠른 전송을 의도하고, 그만큼 빠른 반응성을 보여주기 위함이다.
  • 패킷은 하나당 패킷 헤더를 차지함으로, 뭉쳐서 보내기보다 패킷양도 큰 단점도 있다.
  • 이벤트 폭발에 취약하다.
    • 과도한 패킷이란걸 검증할 baseline을 잡기 어렵기 때문.
      • 그럼에도, 일정 수치 이상은 baseline을 벗어났다고 판정해 anti-floording 처리 해야 한다.

프로그래밍 언어 이야기

C++

  • 내가 가장 자신 있는 언어는 C++이다.
  • 가장 오랜 시간을 사용해왔고, 가장 많은 코드 작성을, 분석을, 테스트를, 서비스를 해왔던 언어기 때문이다.

ruby

  • 다음으로 익숙한 언어는 ruby다.
  • ruby를 통한 scripting, rails를 기반으로 한 web_service 등 C++ 다음으로 익숙하다고 볼 수 있다.

C#

  • 그 다음 언어는 C#.
  • unity에서도 c#, 간단한 툴 작업이나 TCP client, server 작업 등 몇 가지 작업들을 진행했다.

이외에도 이전부터 간단하게 사용 가능하던 언어는 몇 가지 있다.

php

  • 너무 오래전에 사용했다. 특히나 다른 분이 작업해두신 GM툴 기능 유지보수와, 게시판 하나 만들어본 정도였고, 최근 발전 방향을 보면 기대해봄직은 하지만…

perl

  • 써본지도 너무 오래… 특히 ruby를 익히고 난 이후는… 이제와서 perl의 학습을 하는건, 포트란, 파스칼, 코볼 같은 녀석을 놓지 못했던 익숙한 언어에 대한 미련처럼 비추어 질 수도 있단 생각도 든다.
  • 어떤 측면으로 봐도 ruby와 python이 너무 잘 대체했으니 말이다.

erlang

  • 함수형 언어의 개념과 이해도를 위한 학습 정도?
  • 조금 더 깊게 파고 들고자 할 땐 erlang보다 go lang이나 elixir를 사용해보고 싶다.

java script

  • 그래도 꽤 많이 사용한 편이다. WScript라는 스크립트 파싱 엔진을 통해 윈도우에서 batch script를 병행해 사용 해왔고, 실제 프로젝트에 적용했었으니… node.js를 통해서도 사용해보았으나, java script의 장점을 잘 모르겠다.
  • java script 처럼 자유도가 높은 언어를 서버 사이드에서 사용할 때에는, 분명히 보완재 (unit test 강제) 등이 필요 할텐데… 콜백 지옥을 탈출하는 방법도 많이 있고, typescript처럼 타입 자유도를 극복하는 방법도 있지만, 이런 많은 우려를 딛고 극복해야 할만큼 매력있는 언어인지는 잘 모르겠다.

이런 경험 들을 기반으로 가장 관심이 간 언어는… Go다. 정적 언어의 효율성과 동적 언어의 쉬운 적용이 장점이라고 하더라.

Go는 정적 타입 컴파일 언어의 효율성과 동적 언어처럼 쉬운 프로그래밍을 할 수 있도록 하는 것을 목표로 한다. 또다른 목적은:

Go의 장점

  • 안전성 : 타입 안전성과 메모리 안전성
  • 병행성과 통신을 위한 훌륭한 지원
  • 효과적인 가비지 컬렉션
  • 빠른 컴파일

한번 웹 서버로 작업하면서, 어떤 장단점이 있는지 좀 더 느껴보고 싶다.

또 관심이 가는 언어가 있는데, 바로 scala다. java api와 손쉽게 연동이 되며, 객체 지향 프로그래밍과, 함수형 프로그래밍의 장점을 잘 섞었다고 평가 받는 scala도 써보고 평가하고 싶다.

대부분의 스칼라 관련 문서들에서 스칼라와 자바의 연관성을 ‘너무 바빠서 다른 언어를 따로 배울 시간이 없는 자바 프로그래머를 위한’[5] 이라는 표현을 사용하여 나타낼 정도로 비슷한 부분이 많이 나타난다.

문제는 아직 내가 java를 능숙하게 사용하지 못한다는 점이다. 그렇다면 왜 스칼라? 바로…! ruby와 유사한 코딩이 가능하기 때문이다. 실제로 루비의 영향을 받았고 (위키 참조), 타입이 없는 언어이기도 하다. 또한 모든 것은 객체이기도 하다는 말은 스칼라에서도 통용된다.

루비의 단점은 성능 문제라거나, 비동기 작업의 리스크를 줄여줄 수 있는 언어란 생각이 든다.

현재의 두 언어를 살펴보는 이유는, rails의 성능 적인 이슈를 해결하려는 시도가 두 언어 위주로 이루어졌기 때문이다.

나 역시 rails의 장단점을 겪어본 입장에서, 크게 공감 되는 문제기도 하고.

과연… ruby의 뒤를 잇는 내 주력 언어가 이 두 언어 중에서 나오게 될까?

VSCode with Rails

현재까지 개발툴로 C#과 C++에서는 이견이 없이 visual studio 2015를 사용해왔습니다. ruby (& rails) 의 경우 visual studio에서 지원하지 않아, windows환경에선 aptana studio 3 (http://www.aptana.com/)를 사용했고요.

그러던차 node.js를 쓸 일이 좀 있어, visual studio에 node.js 플러그인을 설치해 사용하려 했습니다만… 버그인지 CPU 점유율이 25%이상을 점유하고, 메모리가 계속 증가해 visual studio가 크래시 되더군요. 같은 설치 상태에서, C#, C++은 문제가 없는데 node.js 프로젝트에서만 발생했습니다. -> VS2015 Update 2 이후 발생하지 않네요.

그리하여 다른 솔루션을 찾던 중, vs code를 사용해보았습니다. node.js 기반에서 며칠 사용해보니, 여러모로 편리했습니다 . atom기반 이라지만, atom의 학습비용이 드는 환경 설정 문제가 해결되어있어, 더더욱 편리하게 사용 가능했습니다.

node.js 개발 환경으로 아주 만족스러웠습니다. (visual studio 사용자 기준, atom보다 친숙하고, 편하다고 생각합니다) 자연스레 ruby (& rails) 개발 환경으로도 써볼까 하는 욕심이 들었는데요,

그리하여, vs code의 ruby plugin을 찾기 시작했습니다. https://marketplace.visualstudio.com/vscode/Languages?sortBy=Downloads

몇개 없더군요. 실제로 ruby의 debug plugin은 아래 하나라고 보시면됩니다. https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby

plugin github 링크

설치 방법은 Ctrl + P를 누르시고, ext install Ruby를 입력하시면 됩니다. 그리고 F5를 누르시면, 어떠한 언어로 해당 환경에서 구동 할 건지를 결정하는 창이 뜹니다.

Ruby를 선택하시면 기본 환경 설정 파일 (launch.json)이 생성됩니다.

저는 기본 생성된 json에서, program에서의 디버깅할 rb파일 명 (main.rb -> xlsx_magician.rb)과 args (없으면 ARGV[0]에 string undefined가 환경 변수 ARGV에 담겨 스크립트에 전달 됩니다.)를 추가했습니다.

여기서 주의하실 점은 “args”: [””] 로만 비울 경우는 undefined가 아니라, ARGV자체가 not available 상태라는 점입니다. “args” 항목을 아예 사용하지 않았을 때와 달라요.

launch.json에 “args” 항목 미사용시

  • ARGV = not available

    “args”: [”“]로 넘길 경우

  • ARGV = undefined

    “args”: [“Character.xlsx”]

  • ARGV = [“Character.xlsx”]

자 이제 rails 디버깅 환경에 대해 살펴볼까요?

rails의 경우에는 launch.json을 보강해주셔야 합니다. https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby을 참고하세요.

그리고 좌측에 DEBUG 구동 설정에서 Debug Local Files로 선택되어 있는 것을, Rails Server로 바꿔주셔야 합니다.

rails가 4.2.x로 넘어오면서, 기본 binding 주소가 local에서만 접근가능하게 바뀌었습니다. 그렇다 보니 환경 변수를 넘기고 싶었는데요, 위 설정에서 args에 아무리 파라미터를 확장해봐도, rdebug-ide.bat 파일에 넘어가는 인자가 확장되더군요. 오픈 소스인지라 github의 해당 소스 코드를 직접 찾아보니 더 명확해지더군요. rdebug-ide.bat에 넘기는 인자만 확장 될 뿐입니다.

그리하여, 기본적으로 -b 0.0.0.0으로 bind 하는 것과 같은 결과를 내기 위한 방법을 찾아봤습니다.

아래 링크에서 보이듯 boot.rb를 고쳐주시면, 기본적인 서버 구동시에도 0.0.0.0으로 bind 됩니다. https://fullstacknotes.com/make-rails-4-2-listen-to-all-interface/

물론 여전히 아쉬운 점은, 다른 인자를 못 넘긴다는 점인데요, 이 부분은 환경 설정 rb 파일을 변경해서 테스트하는 방법 정도로 절충해야 할 거 같네요.

vscode-ruby를 변경하는 방법도 있긴 하지만, 저는 우선 여기까지로 환경 설정을 마무리했습니다.

실제 개발 환경으로 사용하는 데에 크게 무리가 없었습니다. eclipse 기반의 aptana studio 3가 큰 만족도가 아니었다는 점도 한 몫 한다고 보고요.

vscode도 아직은 ruby 개발 환경으로 아쉬운 점이 있지만, 그래도 현재 까지의 윈도우에서의 개발 환경도 그다지 만족스럽지 못한, 번거로운 점이 많았다는 것을 감안했을 때, 대안이 될 수 있지 않을까 합니다.