• 2012-04-24

    성공하는 제품을 만들기 위한 팀 구축

    thanks to 박종천(블리자드)

    팀의 핵심 요소

    • 커뮤니케이션 <== 이게 제일 중요함
    • 효율
    • 생산성

    사람을 모아놓고 뭘 하지 고민하지 말라. 좋은 프로젝트를 설정하고, 돈을 모은 후, 적합한 사람을 골라서 배치하는 거다.

    신뢰와 지식

    효율이 떨어지면 커뮤니케이션이 안되고 있는 거다

    Role

    누구에게 무엇을 말할 것인가? (무엇을 책임지는가?)

    product owner 는 4-5년을 보고, team lead 는 3-4개월을 보고, 엔지니어는 1-2주 단위를 보는 거다. 롤 마다 뷰가 다르다.

    낭비(waste)

    해결책 보다는 원인이 중요하다.

    • 중요하면서 (내가) 실행할 수 있으면 => 즉시 한다.
    • 중요한데 (내가) 실행을 못하면 => 연기
    • 중요하진 않지만 실행할 수 있으면 => 위임
    • 중요하지도, 할 수도 없으면 => 무시(잊자)

    이건 zen to done 과 비슷하구나. 핵심은 해결못하면 고민하지도 마라는 점.

    우선순위

    • 중요하고 급하면 => 너무 명백하니까 오히려 쉽다. 누구나 다 안다.
    • 중요한데 안급하다 => 계획을 세운다. 이게 바로 리더가 해야 할 일이다.
    • 안중요한데 급하다 => 귀찮네..
    • 안중요하고 급하지도 않다 => 아주 사소한 일이다.

    판단하기(judgement)

    • 필요한가(need)/원하는가(want)
    • 아는가/모르는가

    위 조합으로 나오는 건

    • need+known : new feature
    • need+unknown : 계획을 세워야 한다. 이게 제일 중요함
    • want+known : change ui
    • want+unkonwn: 리팩토링

    모르지만 중요한 것부터 도전해야 한다. 나머지는 다 견적 나온다.

    known-want 부터 하면 실패한다.

    direction

    팀 간에 충돌은 당연. 오히려 충돌이 없는게 무서운 상황. 뭔가 잘 되어가고 있으면 의심하라. 배가 산으로 가는건 금방이다.

    속도 보다는 디렉션이 훨씬 중요하다. 잠시 멈춰도 정확하게 자주 해야 된다.

    속도가 빠를 수록 주의해야 한다. 속도는 일정해야 한다. 과속 택시 보다는 지하철이 좋은 거다. (예측하기 쉬우므로)

    기타

    • title : 직급. 성장하는 거다. associate < junier < senior < lead programmer … < cto
    • position : 현재의 롤

    • 블리자드 HR 팀의 핵심 명제: Attract < Develop < Engage : 꼬셔서 잘 발전시켜서 잘 적응시킨다.

    performance review

    • 생산성, 전문성, 팀웍, 지식, 역할, 구현
    • 각각의 항목을 측정해서 발전시킨다.

    vision & goal

    • 비전은 장기적, 목표은 단기적
    • 회사, 팀, 개인의 비전과 목표가 일치하는게 좋다.
    • 회사의 core values == 문화를 핵심 문장으로 표현하기

    3 가지 룰

    • 행복할 것
    • 목표를 잘 이룰 것
    • 매일 매일 배울 것
    Category:management
    Tags:team
  • 2012-04-21

    Node.js로 25만 동접 만들기

    via caustik's blog

    node.js 를 10만 동접으로 스케일링하기

    • 10만 동접을 처리하는데 CPU 점유율 40%, (virtual) 메모리 1.4G 를 차지함. 이 정도면 rackspace 2G 클라우드 서버일 경우 시간당 0.1$ 로 가능함.
    • 각 연결은 5초에 한번 메시지를 보냄. 대략 초당 4만개의 JSON 패킷이 보내짐. 응답성도 좋음.

    이런 성능을 위한 설정은:

    • Nagle 알고리즘을 사용안함: 빠른 응답성을 위해 커널 내부에 네트워크 버퍼링을 사용하지 않고 즉시 보내지도록 함. socket.setNoDelay().
    • v8의 idle 가비지 컬렉션을 끄기 위해 --nouse-idle-notification 옵션 사용: JS 객체가 2백만개 정도 되면 몇 초마다 가비지 컬렉션 때문에 1초 가까이 랙이 걸림. 실제로 객체들을 순회하는 데만 이 정도의 시간이 소모됨.
      [역주] 소스 코드를 보면 --expose_gc 옵션으로 실행해서 gc()를 실행할 수 있게 한 다음, /debug/gc 메시지를 보내서 가비지 컬렉션을 하게 되는데, 이걸 실행하는 순간 랙은 뭘 해도 피할 수 없음. ㅠㅠ

    node.js 로 25만 동접 만들기

    1. 가장 최근 태그된 v8 리비전의 성능이 그나마 낫다.

    2. 25만 연결은 v8의 1.4기가 힙 메모리 제한 하에서의 최대치. 이 상황에서도 CPU 사용량이나 메모리 사용량이 낮은 걸 본다면, 충분히 더 나아질 수 있을 듯.

    3. 여러 번 테스트해본 결과, SVN의 가장 최근에 태그된 리비전이 그나마 제일 안정적이었음

    4. 클러스터 모듈의 워커들을 이용

    5. 100개의 아마존 EC2 서버들로부터 초당 10만개의 JSON HTTP GET 요청을 보냄.

    6. 클러스터 모듈을 사용해서 일시적인 요청(?) 처리의 오버헤드를 줄임. (35만 연결 중 10만개 정도가 일시적이었다) [역주] 자식 프로세스로 어떻게 뭘 분산하는지는 현재 미확인
    7. 마스터는 이전과 동일. 워커는 CPU 당 하나씩 생성하고, 마스터와는 다른 포트를 사용해서 요청을 받아서 마스터로 포워딩함. 이렇게 한 이유는 오직 1.4기가 힙 제한 때문.

    V8의 1.4GB 힙제한 벗어나기

    • ulimit -n 999999: 소켓 오픈 개수 제한을 증가. 기본 1024.
    • --nouse-idle-notification: 가바지 컬렉터가 자동적으로 실행되는 걸 막음. 30초마다 4초짜리 랙이 걸리고 싶지 않으면 사용해야 함. --expose-gc 로 gc() 함수를 자바스크립트에서 직접 호출.
    • --max-old-space-size=8192 : 메모리 제한 최대값을 임의로 설정.
    • 최신 v8 소스를 약간 고쳐서 빌드: 메모리 관련 설정이나 가비지 컬렉터 실행 부분을 수정.

    최근엔 1.4G 제한을 넘어서 2.2G 까지도 사용할 수 있었음. :)

    [역주] node.js 서버 실행시 넘기는 파라미터:

    node --trace-gc --expose-gc --nouse-idle-notification --max-new-space-size=2048 --max-old-space-size=8192 sprites.js

    총평

    • 게임 서버를 개발시 이슈가 되는, 응답성, 동접 처리 등의 문제를 node.js 개발자들도 만나기 시작함. 의외로 메모리 제한이 문제가 된다는 게 특이했음. node.js 개발진은 메모리 제약은 클러스터 모듈로 분산해서 해결하는 걸 추천하는 듯.
    • 가비지 컬렉팅 문제는 응답성이 중요한 액션 게임을 개발할 경우 심각할 수 있음. (4초나 랙이 걸린다니! 그것도 30초마다!) 그래도 소셜 게임 수준은 걱정하지 않아도 될 듯.
    Category:programming
    Tags:node.js
  • 2012-04-16

    Python Iterator vs. Generator

    iterator

    임의의 sequence 를 순회하는데 필요한 정보를 담은 오브젝트.
    iter() 함수를 통해서 생성하고, next() 함수를 이용해서 index 를 증가시켜서 다음 객체를 리턴한다. 맨 끝에 도달하면 StopIteration 예외를 던진다.

    즉 for x in seq 는 내부적으로 아래와 같다.

    it = iter(seq)
    while 1:
      try:
        x = it.next()
      except StopIteration:
        break
    

    임의의 클래스에 iter() 과 next() 함수를 정의하면, in 연산자로 iteration 이 가능하다.

    class MyCollection:
      def __init__(self, seq): self.idx=0; self.seq=seq
      def __iter__(self): return self
      def next(self):
        if self.idx > len(self.seq): raise StopIteration
        self.idx += 1
        return self.seq[self.idx]
    

    generator function

    iterator 가 next() 호출을 통해서 값을 "리턴"하는 것과 달리, generator 는 next() 함수를 부르면 이전에 멈춘 곳부터 실행(resume)하다가 yield로 값을 리턴하고 다시 멈춤(pause)으로써, 결과적으로 값을 순차적으로 "생성"한다. 맨 끝에서는 역시 StopIteration 예외를 던진다.

    generator expression

    (x for x in seq) 처럼 [] 대신 () 로 list comprehension 을 묶으면 generator 를 간단히 만들 수 있다.

    리스트를 파라미터로 받는 함수에 그대로 넘길 수도 있다.

    sum(x for x in seq)

    Category:programming
    Tags:python
  • 2012-04-04

    AppEngine pipeline

    개요

    Datastore 에 task 순서를 저장하고 순차적으로 하나씩 실행한다.
    task 1 의 리턴값이 task2 의 출력값이 된다.
    내부적으로 task queue 를 사용한다.

    • run() 의 리턴값 또는 마지막 yield 값이 self.outputs.default.value 가 된다.
    • 여러 개의 값을 리턴할 수도 있다.
    • 값에 이름이 필요할 경우 output_names 와 fill() 함수를 이용할 것.
    output = [ slot, ... ] 
    

    2개를 순차 실행

    task2 에서 task1 을 yield 로 호출할 것.

    class Task1(pipeline.Pipeline):
      def run(self, input):
        return input*2
    
    class Task2(pipeline.Pipeline):
      def run(self, input):
        result = yield Task1(input)
        return input+1
    

    이때 x 는 Future 객체다. x 의 값을 읽어오려면 또다른 yield 로만 가능하다.

    common 모듈

    각종 다양한 파이프라인 기능을 지원한다.

    callback(), get_callback_task(), get_callback_url()

    어떤 태스크들은 사람이 중간에 개입해서 이메일의 링크를 클릭하거나, delay 처럼 일정 시간 후에 태스크큐를 통해서 비동기적으로 수행될 필요가 있다.

    이때 콜백 함수가 호출된다.

    finalize()

    아직 결과값이 저장되지는 않은 상태다.

    output_names & fill()

    하나의 값이 아니라 여러 개의 값을 이름 기반으로 넘겨야 할 때

    output_names = ['aa', 'bb']
    …
    self.fill(self.outputs.aa, 11)
    self.fill(self.outputs.bb, 'bbbbb')
    

    와 같은 방식으로 저장한다.

    with pipeline.After()

    futures 를 파라미터로 받아서 해당 태스크가 모두 끝난 경우 with 아래 문을 실행한다.

    common.Append()

    여러 개의 태스크를 실행한 후 하나의 리스트로 리턴한다.

    raise pipeline.Retry, Abort

    예외는 위와 같이 넘길 것

    yield common.Log.info()

    비동기 로그 남기기

  • 2012-04-02

    NoSQL 조사

    NoSQL DB 비교라는 문서를 기준으로 각 데이터베이스의 특성을 간략 조사해봤다.

    mongodb

    10gen 이라는 회사에서 운영. 오픈 소스. 컬럼 그룹 기반.

    • C++ based
    • SQL과의 호환성(쿼리, 인덱스)
    • protocol: BSON & custom
    • storage: memory mapped file
    • sharding
    • query: javascript expression
    • server script: javascript
    • 다이나믹 쿼리가 필요한 경우
    • map/reduce 보다 index 가 많은 경우
    • 데이터가 많을 때 성능이 중요한 경우
    • couch db 에 비해서 데이터가 자주 변하는 경우

    Riak

    • Erlang & C (+ JS) based
    • fault tolerance 가 최우선
    • Protocol: HTTP/REST
    • map/reduce: by JS & Erlang

    CouchDB

    • Erlang based
    • DB 안정성이 최우선. 손쉬운 사용.
    • Protocol: HTTP/REST
    • 자주 바뀌지 않는 데이터
    • 데이터 버전관리가 중요한 경우
    • ex> CMS, CRM

    Redis

    key-value store. github, disqus, digg, stackoverflow 에서 사용중이다.

    특징

    • C/C++ based
    • 속도가 최우선
    • Protocol: telnet like?
    • disk backed in memory db ??
    • disk swap 지원 안함
    • set, list, hash, sorted set 등 다양한 타입 지원
    • 트랜잭션도 있다..
    • 데이터 용량 == 메모리에 올라 갈 정도의 크기여야 한다
    • 자주 데이터가 바뀌지만 크기는 예측 가능한 분야에 적절
    • ex> 주가, 분석, 실시간 데이터, 실시간 통신..

    데이터 안정성

    via 스냅샷

    저장 방식
    • RDB(snapshot): 큰 파일 하나에 DB 전체를 저장.
    • AOF(Append Only File): 변경 사항(command)을 로그 파일에 계속 추가함. 서버가 뜰 때 이걸 쭈욱 읽어서 원본 데이터를 만들어낸다.
    • 둘 다 끄면 캐시 모드가 됨. 서버 끄면 사라짐.
    • 둘 다 적용하면, 마지막 rdb 다음부터의 AOF 를 읽어서 만들어냄
    RDB 의 장점
    • 특정 시각의 데이터를 하나의 파일에 담았다
    • 백업/복구에 용이: 주기적으로 RDB를 만들어서 외부에 백업하기 쉽다
    • 성능면에서 최고
    • 빠른 재시작
    RDB 단점
    • 데이터 손실 가능성: 파워 나감
    • 주기적으로 여러 RDB를 만들어야 된다.
    • 저장할 때마다 fork 한다. 이때 I/O 가 멈추거나 CPU가 스파이크 친다.
    • 물론 AOF 도 fork 를 하긴 한다.. 대신 조정이 가능.
    AOF 장점
    • 보다 안정적. fsync 정책을 튜닝 가능(매 초마다, 모든 쿼리 마다)
    • 기본 정책은 1초마다. 백그라운드 쓰레드가 실행함.
    • append only 라서 데이터 커럽션이 없다. 마지막 데이터가 깨질 경우에도 쉽게 고칠 수 있다.
    • 로그가 너무 커지면 자동적으로 다른 파일로 분할한다.
    • 로그 포맷이 이해하기 쉽다.
    AOF 단점
    • RDB 보다 파일 용량이 크다
    • RDB 보다 느리다
    • 데이터가 꼬일 확률이 존재한다. 과거에 그런 버그가 있었다. 근데 아직 버그 리포트는 없다.
    결론
    • 둘 다 사용해야 함
    • 스냅샷: dump.rdb 를 남김.
    • 초 단위 주기. 또는 데이터셋의 변화량 단위.
      ex> save 60 1000 === 60초 마다, 1000 개의 변화 마다
    • fork 해서 자식 프로세스가 dump.rdb 를 저장하면 기존 파일을 변경
    • AOS:

    cassandra

    페이스북이 개발해서 오픈소스화. 지금은 아파치에서 관리중. 페이스북/트위터/Digg 에서 사용. 컬럼 그룹 형태의 데이터 모델. 데이터 일관성 잘 지원한다.

    • 자바 기반
    • 읽기 보다는 쓰기를 많이 할 때
    • 모든 컴포넌트가 다 자바일때
    • 은행, 금융.

    couchbase(membase)

    via Features

    membase 가 couchbase 로 통합됨

    • Erlang & C 기반
    • memcache 호환성 + 영속성 + 클러스터링 이 중요
    • 존나 빠름
    • 디스크 영속성
    • web GUI
    • DB를 끄지 않고 업그레이드 가능
    • 데이터 접근 속도가 중요할 때, 많은 접근이 있을 경우, 높은 가용성 필요할 때
    • 징가 같은 highly concurrent web app

    HBase

    • google big table 의 오픈 소스 클론

    총평

    유력한 후보들

    • mongodb: 팔방미인. blob
    • redis: 로그 & 캐시
    • couchbase(membase): 메모리 기반 but 용량 한계. 근데 node.js 클라 없다.

    무시할 놈들

    • couchdb: 데이터가 자주 바뀐다…
    • cassandra: 자바 기반
    • riak: 머임..
    • hbase: 즐..
    Category:programming
    Tags:nosql