[ZooKeeper] (0) zookeepr는 무엇인가?

 보통 분산 시스템을 구현할 때, 모든 시스템이 완전히 독립적으로 돌아가는 시스템이 아니라면, 시스템 간의 락, 설정 공유, 리더 선출, atomic 한 연산 등을 구현하는 것이 필요하지만, 분산환경에서 이를 구현하는 것은 매우 어려운 일이다.  위의 기능들을 구현하기 어렵기 때문에 보통은 apache에서 제작한  zookeeper 라는 시스템을 이용하여 분산 시스템 간의 동기화된 작업을 구현한다.  zookeeper는 위의 기능들을 직접적으로 제공하지는 않지만 이런 일들을 하기 쉽게 해주는 환경을 제공한다.  zookeepr가 제공해주는 환경이라는 것은 일종의 공유 가능한 file system을 제공해준다. 그러면 사용자가 file을 이용해서 semaphore 나 mutex 를 구현하듯이 zookeeper를 이용해서 semaphore나 mutex등을 구현하여 사용하면 된다.  zookeeper는 분산환경에서의 다음과 같은 특징을 보장해준다. ZooKeeper의 특징 Atomicity  zookeeper에서 data의 저장은 원자성 을 가진다.  즉, node를 만들건 node에 data를 update하든 해당 request는 완벽하게 처리되거나 처리되지 않거나 하지 그 중간의 어중간한 상태는 존재하지 않는다. Consistency  분산환경에서, 특히나 data를 copy하여 여러 서버에 저장하면서  strong consistency 를 보장하는 것은 매우 어려운 일다. 그래서 zookeeper에서는 아래의 2가지 consistency를 보장한다.  첫 번째는 sequential consistency 다.  즉, 모든 요청은 들어온 순서대로 처리되고, 모든 서버가 요청을 같은 순서로 처리하는 것을 보장하는 것이다.  두 번째는 eventual consistency 다.  strong consistency와 달리, 모든 요청에 대해 모든 서버가 완벽히 같은 순간에 같은 값을 갖지는 않지만 결국에는 같은 값을 가질 것을 보장하는 것

config_script 재작성

이미지
 이 컴퓨터 저 컴퓨터 옮겨가면서 작업할 때, 컴퓨터별로 환경을 통일하는 작업은 귀찮은 일이다. 그래서 나는 이런  스크립트 를 만들어서 써왔다.  아직 사용하는데 큰 문제는 없었지만, 그때그때 필요한 기능들을 넣다 보니 스크립트가 난잡해지고, 내가 다른 프로젝트에서 작업할 때 자주 사용하지 않는 bash를 이용해서 만들다 보니 수정이 필요해서 코드를 다시 볼 때, 익숙하지 않아서 실수하는 문제가 생겼다.  그래서 이번 연휴를 맞아서 스크립트를 완전히 새로 작성하였다.  이번에 작업에서 초점을 맞춘 부분은 크게 2가지였다.  첫 번째는 시간이 지나도 알아보기 쉽도록 익숙한 언어로 작업할 것, 두 번째는 수정이 필요하거나 새로운 일이 추가될 때 확장하기 쉽도록 하는 것이었다.  첫 번째 요구사항을 맞추기 위하여 작업은 python을 이용하였다.  어차피 하는 대부분 작업이 조건에 맞추어 파일을 옮기고 command를 실행시키는 일들뿐이고 복잡한 일은 없어서 언어는 무엇을 사용해도 상관없어 보였기에 그중에 가장 익숙한 python을 이용했다.  두 번째 요구사항을 맞추기 위하여 기존의 스크립트를 분석해 보니 대부분의 일이 본 작업에 앞서 사전작업을 한다. 작업해야 할 파일 리스트에서 하나씩 꺼내서 source가 있는지 파악하여 에러처리를 하고 destination에 이미 파일이 존재하는지 확인하여 에러처리를 하고 source를 destination으로 복사/링크 등을 한다. 본 작업이 끝난 뒤 마무리 작업을 한다. 의 순서로 진행되었다.  그래서 Config라는 abstract class를 만들고, 각각의 단계에 맞춰서 pre() source_exists() resolve_conflict() do() post() 의 5개의 abstract method를 만들어 원하는 작업마다 Config를 상속받는 class를 만들어 상황에 맞게 위의 method들을 override 하는 방식으로 작업을 진행하였다

왜 Triple buffering을 사용하는가

이미지
  지난번 글 에서 double buffering 과 VSync 에 관하여 설명하였다.  이번 글에서는 VSync가 가지는 문제와 그것을 어떻게 triple buffering 이 해결하는지를 적어보도록 하겠다.  우선 다음 문제를 풀어보자. vertical interval이 16.6ms마다 있는 display를 사용하고 double buffering을 사용하는 드라이버에서 VSync를 사용한다고 했을 때 back buffer에서 scene 하나를 완성하는 데 걸리는 시간이 16ms인 프로그램을 작성하면 이 프로그램은 몇 fps가 나올 것인가?  매 frame마다 하나의 scene을 16ms 동안 그리고, 남은 0.6ms는 VSync를 기다리기 때문에 16.6ms마다 한 frame을 그려서 60fps가 나온다.  VSync를 기다리는 0.6ms가 아쉽기는 하지만 어차피 60fps 이상은 사람 눈으로 잘 구분이 안 되니 큰 손해를 보는 것은 아니다.  문제는 아래의 상황이다. vertical interval이 16.6ms마다 있는 display를 사용하고 double buffering을 사용하는 드라이버에서 VSync를 사용한다고 했을 때 back buffer에서 scene 하나를 완성하는 데 걸리는 시간이 홀수 번째 scene은 15ms, 짝수 번째 scene은 17ms가 걸리도록 프로그램을 작성하면 이 프로그램은 몇 fps가 나올 것인가?  매 프레임 back buffer에 그리는 데 걸리는 평균 시간은 첫 번째 경우와 같다.  그렇다면 이 케이스에서도 60 fps가 나올까?  아니다. 홀수 번째 frame에서는 15ms 동안 그림을 그리고 1.6ms 동안 기다리지만, 짝수 번째 frame에서는 back buffer에 그림을 그리는데 17ms가 걸렸기 때문에 첫 번째 vertical interval 때 swap buffer를 하지 못하고, 그 다음 vertical interval까지 기다려야 한다. 즉, 그림이 완성된 뒤 16.2m

copy와 flip - Double buffering의 2가지 기법

이미지
 Buffer는 그림을 그리기 위해 메모리에 잡아놓은 영역을 의미한다.  그래픽 드라이버가 화면을 갱신해야 할 때 이 영역에서 그림을 읽어 화면을 그린다.  과거의 graphic card(혹은 요새 나오는 저 사양의 embedded 용 graphic card)에서는 single buffering이라는 기법을 이용한다.  single buffering이란, 말 그대로 한 개의 버퍼만을 사용하는 방식이다. 완성된 그림을 buffer에 그리고, 화면에 그림을 그려야 할 때마다 이 buffer에서 화면으로 그림을 가져가는 것이다.  가장 기본적인 구현이지만, 이런 방식은 buffer에서 화면으로 가져가는 동안 buffer를 업데이트하지 못한다는 단점이 있다.  이런 단점을 해결하기 위하여 double buffering 이라는 기법을 사용한다. Double buffering  Double buffering에서는 front buffer와 back buffer라고 불리는 2개의 buffer를 사용한다. back buffer에 그림을 그리고 한 프레임이 완성되면 back buffer와 front buffer를 바꾼다. (이를 swap buffer라고 한다.) 화면에 그림이 필요할 때는 언제나 front buffer에서 화면을 가져간다.  화면이 읽어들이는 buffer는 언제나 front buffer이므로 화면을 업데이트할 필요가 있으면 언제나 back buffer에 그리면 된다.  이때 back buffer에서 front buffer로 옮기는 방식에는 2가지 방법이 있다. Copy  첫 번째 방법은 copy라고 부르는 방법이다. 이 방법은 front buffer는 그래픽 메모리에 만든다. back buffer는 그래픽 메모리나 시스템 메모리 어디에 만들어도 상관없지만, 보통 copy를 사용하는 경우는 그래픽 메모리를 아끼기 위한 경우가 많아서 back buffer는 시스템 메모리에 잡는다.  프로그램이 그림을 그리라고 하면 이를 back buffer에 그

Fluentd - Pluggable log collector

이미지
 지난번에 소개했던 글 에서 여러 가지 log aggregator들을 소개했었다. 이번에는 그중에서도 특별히 마음에 들었던 fluentd를 더 자세히 소개해 보도록 하겠다. Semi-structured log http://blog.treasure-data.com/post/13047440992/fluentd-the-missing-log-collector-software  우선 fluentd의 가장 큰 특징은 log를 time/tag/record형식 의 semi-structured 형식으로 저장한다는 것이다.  시간은 event가 발생한 시간으로 event를 fluentd로 넘겨줄 때 시간을 같이 넘겨주지 않으면, fluentd에서 받은 시간을 기록하게 된다.  tag는 이벤트를 만들 때 넘기게 되어 있는데, fluentd에서 사용하는 값이다. 이에 대해서는 config를 어떻게 하는지 설명하면서 설명하도록 하겠다.  record는 사용자가 저장하려고 했던 값들로 json 형식의 key/value pair로 저장된다.  semi-structured라고 해도 record가 json 형식으로 저장되기 때문에 원하는 형식대로 저장할 수 있다. Use case  fluentd는 config파일을 바꾸는 것만으로도 여러 머신들 간의 설정을 쉽게 바꿀 수 있다. http://blog.treasure-data.com/post/16034997056/enabling-facebooks-log-infrastructure-with-fluentd  위의 그림은 가장 기본적인 형태로 frontend에 붙어 있는 fluentd에서 보내는 이벤트를 중개 서버(?)에 해당하는 fluentd에서 한번 수집하여 최종 저장소에 보내는 형태이다.  위의 그림은 특별히 fluentd의 성능을 고려하여 하나의 중개 서버가 너무 무리하는 일 없도록 여러 개의 중개 서버에 나누어서 보내는 방식이다. http://docs.fluentd.org/articles/high-avai

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

이미지
https://docs.google.com/presentation/d/12A5RlMCVDN6tA_zUnLrZ0TN5v08gz2GhlRdzxy3T3mU/edit?usp=sharing  회사에서 최근에 Log aggregator system으로 무엇을 사용해야 할지 조사해본 자료다.  우선 log aggregator가 무엇인지 한 문장으로 설명하면, 여러 머신에서 쌓인 로그들을 한 번에 분석할 수 있도록 수집하여 주는 시스템을 말한다.  요새는 특히나 클라우드 시스템이 유행하면서 같은 일을 하는 시스템임에도 다른 머신에서 돌아가는 일이 많아지면서 필요성이 크게 증가하였다. 이번 조사로 알게 된 것들을 적어보도록 하겠다. Scribe  우선 scribe 는 Facebook에서 제작하고 사용하던 log aggregator system이다. scribe:  http://www.cnblogs.com/brucewoo/archive/2011/12/13/2285482.html  후에 다른 로그 수집 시스템들을 보면 알겠지만, Scribe는 다른 시스템보다 간단한 구조로 되어 있다.  Scribe는 일종의 message queue와 message queue에 쌓인 message를 DB에 저장해 주거나, DB가 실패하였으면 local에 저장하였다가 DB가 복구되었을 때 다시 DB에 저장해 주는 것만을 책임진다. 다시 말하면, message queue에 실제로 메시지를 보내는 부분은 사용자가 직접 작성하여야 한다는 것이다.  흔히들 말하는 scribe의 장점은 c++로 만든 만큼 다른 시스템들의 3~5배 정도의 성능을 보여준다는 것이다. 하지만 실제 scribe 사용자들은 무엇보다도 Facebook이 실제로 사용하였던 솔루션인 만큼 성능과 안정성에서 신뢰도가 있다는 것을 장점으로 뽑는다.  하지만 나는 scribe를 사용하는 것을 추천하지는 않는다.  일단 가장 큰 문제는 더이상 Facebook이 Scribe를 사용하지 않는다는 것이다. Faceboo

Actor model and akka

다음 프로젝트로 scalable 한 게임 서버프레임워크 구현을 진행 중이다. 아직 구상 중이라 결정된 것은 없지만, scalability와 functional 한 특성을 동시에 살릴 수 있는 scala 의 akka프레임워크 가 후보로 들어왔고 이에 대해 간단하게 정리하여 발표할 기회가 있었다. 일단 발표자료 는 간단하게 키워드들만 적었기에 이에 대해 보충 설명을 해보고자 한다. akka는 무엇인가  akka는 scala로 구현된 concurrency 제어를 위해 actor model을 도입한 프레임워크로 java와 scala API를 제공한다. 우선 akka는 actor model을 기본으로 하고 있기 때문에 akka의 특성을 이해하려면 actor model을 이해해야 한다. Actor의 특징  actor model은 간단히 설명하면 behavior, state, mailbox로 구성된 actor를 기본 단위로 하는 message processing을 이용하여 behavior를 비동기적으로 실행하는 model이다.  이때 기본단위가 되는 actor는 몇 가지 특징이 있다. 우선 각 actor는 서로 간에 공유하는 자원이 없고 서로간의 state를 건드릴 수 없고, 오로지 message를 이용해서만 간섭할 수 있다.  message는 mailbox에 쌓였다가 들어온 순서대로 처리된다.  실행되는 behavior는 message에 의해 결정되고, 할 수 있는 일은 자신의 state를 바꾸거나, child actor를 만들거나, child actor를 죽이거나 다른 actor에 message를 보낼 수 있다.  actor model의 actor는 사실 OOP에서 말하는 object와 매우 비슷하다.  object는 member variable(state)을 가지고 있고, 어떤 방식으로 동작할지 method(behavior)를 가지고 있다.  method는 다른 object를 만들거나, 자기가 관리하는 object를 부수거나 다른 object의