Monthly Archives: February 2011

Monitor Object Pattern

Monitor Object Pattern 입니다.

똑바로 일하라(REWORK) – 37Signal


Getting Real 라는 내용의 책으로 유명한 37Signals 라는 회사가 있다. 직원수는 고작 1~20명 수준이지만, 지금 세계의 많은 웹 개발자들을 편하고, 강력하게 만들어낸 Ruby on Rails 라는 걸 만든 회사입니다.( 개인적으로 외국업체들은 작은 Startup 일 수록 스스로의 생산성 향상은 높이기 위해서, 멋진 기술을 많이 개발하는 듯합니다. memcached, gearman, MogileFS를 만들어낸 Danga 라는 회사도 그렇습니다.

그렇다면 REWORK라는 어떤 책일가요? 사실 Getting Real 이라는 책도 내용이 간단하지만, 쏙은 꽉찬 그런 책인데, REWORK 역시 그런 책입니다. 시작 부분은 자신들이 하고싶은 큰 문장으로 나타내고, 그 뒤에 설명식으로 나오는 일종의 자기개발서이지만, 재미난 내용들이 많습니다.

자신들의 가치를 위해서 오래된 고객을 거절하라라든지(정확히는 고객의 요구때문에, 자신들의 철학을 바꾸지 말라는 것입니다.) 벤처가 아닌 사업을 시작하라는 말과, 5시 이전에 직원을 퇴근 시켜라 등의 멋진 문구들이 있고, 자신들의 기업 문화를 소개하고 있습니다. REWORK 의 장점은, 37Signal 자체가 인원수가 적은 소위 벤처라고 불러야 할 크기지만, 거기서 나오는 제품들은 정말 수많은 사람들이 사용하는 제품들을 계속 계속 만들고, 나타내는 형태라, 이 회사를 추종하는 수많은 사람들이 있습니다.

그리고, Getting Real 과 이걸 함께 읽어보면, 아, 나도 이런식으로 가야겠구나, 하면서 강하게 사람을 끄는 뭔가가 있습니다.
이미 Getting Real 은 한글로 번역되어서 공개되어 있기 때문에, 공짜로 읽으실 수 있습니다. http://gettingreal.37signals.com/GR_kor.php (저는 영어를 잘 못하기 때문에, 한글판이 아니면 정보 얻기가 힘듭니다. 쿨럭…)

꼭, 따라 하실 필요는 없지만, 자신의 일, 또는 사업을 하시는 특히 IT 쪽으로 도전을 하고 싶은 분들에게는 읽어보길 권해드립니다.

Cassandra Simple Authentication Example with pycassa

There is a Simple Python Example
For Cassandra SimpleAuthentication

from pycassa import index, connect, connect_thread_local, gm_timestamp, ColumnFamily, 
        ColumnFamilyMap, ConsistencyLevel, NotFoundException, String, Int64, 
        Float64, DateTime, IntString, FloatString, DateTimeString

import pycassa

auth = {'username':'username','password':'password'}
pool = pycassa.connect('Tweet', ['localhost:9160'], True, 10, auth)

cf = ColumnFamily(pool, 'Standard1')

print cf.get('charsyam2')
print cf.get('charsyam')

Use Strict String Key Map

일반적으로 Parameter 전달은 가끔씩 고민을 하게 만드는 문제입니다.

parameter[String key] = value 방식은 간단하고 다수의 파라패터를 쉽게 넘길 수 있습니다.

그러나 String 의 특성상, 오타를 내면 바로 바로 오동작을 일으키게 만드는 원인이 될 수 있습니다.

그런데, 조금만 생각을 추가하면, 넣을 수 있는 ‘Key’를 제한 한다면 어떨까요?

아주 간단하게 Key Name 을 제한해서 이미 허용해둔 값들만 Set 할 수 있도록 만들면 간단하지 않을까요?

물론, 허용 Key Name을 추가할 수 있도록 만들어 두고, 테스트 코드에서 한번씩 확인하게 해주면,

의외로 간단하면서, 실수하기 쉬운 파라매터나 Conf 설정을 쉽게 할 수 있을듯 합니다.

다음은 위에 말한 기법을 이용한 python singleton 예제입니다.

 class Parameter(object):
    key_list = [ 'name', 'price', 'size' ]

    def init(self):
        self.m_param_keyword = {}
        self.m_param_dict = {}

        for key in self.key_list:
            self.add_allow_key( key )

    def get_keys(self):
        return self.m_param_dict.keys()

    def get_allow_keys(self):
        return self.m_param_keyword.keys()

    def add_allow_key(self, key):
        self.m_param_keyword[ key.lower() ] = True

    def add_allow_keys( self, keys ):
        for key in keys:
            self.add_allow_key( key )

    def is_valid_key( self, key ):
        if self.m_param_keyword.get(key, False) == True:
            return True

        return False

    def __init__(self):
        self.init()

    def set( self, key, value):
        lower_key = key.lower()
        if self.is_valid_key( lower_key ) == False:
            return False

        self.m_param_dict[lower_key] = value
        return True

    def get( self, key ):
        return self.m_param_dic[key]

if __name__ == '__main__':
    paramter = Parameter()

    print parameter.set( 'name', 'charsyam' )
    print parameter.set( 'price2', 10 )

    parameter.add_allow_keys( ['inventory'] )
    print parameter.get_allow_keys()

    print id(conf1), id(conf2)

Zookeeper Example with Python

Zookeeper 는 apache 에서 진행하는 분산 코디네이터 입니다. 이를 이용해서 분산 락이라든 지, 현재 사용가능 한 Worker or Server 정보를 얻어오는 등의 여러가지 작업을 쉽게 할 수 있습니다. zookeeper 의 구조에 대해서는 다음 기회에 좀 더 자세히 설명해 드리기로 하고 일단 간단한 zookeeper 를 이용한 example을 보여주려고 합니다.

Zookeeper 에는 임시노드를 생성할 수 있는 기능이 있습니다. 임시노드는 세션이 끊어지면, 지정된 시간뒤에 사라지는 노드입니다. 즉, 특정 서버가 죽거나 하면 연결된 정보가 자동적으로 사라집니다. 다음 예제는 Echo 서버가 시작될 때 Zookeeper 에 자신의 Information( ip, port ) 을 등록하고, 장애로 서버가 동작하지 못하는 경우에 대한 샘플입니다.

실제 동작은 세션이 끊어진 뒤에 일정 시간 동안은 노드가 남아있으므로, 잠시 동안 오류가 발생하다가, 시간이 지나면 해당 노드 정보가 사라지므로 클라이언트들은 정상인 서버로만 접속을 하게 됩니다. 이런 부분은 분산 컴퓨팅에서 장애의 허용, 복구 같은 내용과 연관이 되게 되는데, 잠시 동안만 실패하므로, 사용자는 거의 정상적인 서비스를 할 수 있게 됩니다.

다음 그림과 같이 서버는 최초에 실행되면서 zookeeper 에 자신의 정보를 저장합니다.

클라이언트는 시작시 zookeeper 에서 위의 정보를 읽어서 서버에 접속하게 됩니다.

장애시에는 다음과 같이 자동으로 연결 정보가 사라지므로 클라이언트는 정상 서버로 계속 접속하게 됩니다.

다음은 서버 Sample 입니다.

#/usr/bin/env python

import zookeeper, time, threading
from gevent.server import StreamServer
from gevent import monkey; monkey.patch_socket()
import socket
monkey.patch_socket()

END_MARK='rn'

def handler(socket, address):
    print 'New connection from %s:%s' % address
    # using a makefile because we want to use readline()
    packet = ''
    socket.settimeout(2)

    while True:
        data = socket.recv(1024)
        if not data:
            print 'Connection Close from %s:%s' % address
            return

        packet += data
        if END_MARK in packet:
            socket.sendall(packet)
            print packet
            break

PORT_NUM = 12345

if __name__ == '__main__':
    # to make the server use SSL, pass certfile and keyfile arguments to the constructor
    server = StreamServer(('0.0.0.0', PORT_NUM),handler)
    # to start the server asynchronously, use its start() method;
    # we use blocking serve_forever() here because we have no other jobs

    connected = False
    conn_cv = threading.Condition()

    def my_connection_watcher(handle,type,state,path):
        global connected, conn_cv
        print "Connected, handle is ", handle
        conn_cv.acquire()
        connected = True
        conn_cv.notifyAll()
        conn_cv.release()

    conn_cv.acquire()
    print "Connecting to Zookeeper -- "
    handle = zookeeper.init("172.27.0.2:2181,172.27.0.3:2181,172.27.0.4:2181", my_connection_watcher)
    while not connected:
        conn_cv.wait()

    conn_cv.release()

    ZOO_OPEN_ACL_UNSAFE = {"perms":0x1f, "scheme":"world", "id" :"anyone"};

    rootnode_name = "/zk-servers"
    ret = zookeeper.exists(handle, rootnode_name, None )
    if None == ret:
        zookeeper.create(handle, rootnode_name, "data", [ZOO_OPEN_ACL_UNSAFE], 0 )

    host = socket.gethostbyname(socket.gethostname())
    data = host + ":" + str(PORT_NUM)
    zookeeper.create(handle, "/zk-servers/echoserverlist", data, [ZOO_OPEN_ACL_UNSAFE], zookeeper.EPHEMERA
L|zookeeper.SEQUENCE)

    print 'Starting echo server on port %s' % PORT_NUM
    server.serve_forever()

다음은 클라이언트 입니다. 모두 최초 접속시에 목록 리스트를 가져와서 랜덤하게 하나를 선택해서
접속하게 됩니다.

import zookeeper, time, threading
from gevent.server import StreamServer
from gevent import monkey; monkey.patch_socket()
import random
import socket

connected = False
conn_cv = threading.Condition()

def my_connection_watcher(handle,type,state,path):
    global connected, conn_cv
    print "Connected, handle is ", handle
    conn_cv.acquire()
    connected = True
    conn_cv.notifyAll()
    conn_cv.release()

conn_cv.acquire()
print "Connecting to localhost:2181 -- "
handle = zookeeper.init("172.27.0.2:2181,172.27.0.3:2181,172.27.0.4:2181", my_connection_watcher)
while not connected:
    conn_cv.wait()
conn_cv.release()

ZOO_OPEN_ACL_UNSAFE = {"perms":0x1f, "scheme":"world", "id" :"anyone"};

rootnode_name = "/zk-servers"
ret = zookeeper.exists(handle, rootnode_name, None )
if None == ret:
    print "There is no zk-servers keys"
    exit()

children = zookeeper.get_children(handle, rootnode_name, None)
size = len(children)
if 0 == size:
    print "There is no zk-servers echo server lists."
    exit()

idx = random.randint(0,size-1)


child = children[idx]
nodename = rootnode_name + "/" +  child
(data,stat) = zookeeper.get(handle, nodename, None)
print idx, data, stat

ip, port = data.split(':')
print ip, port

clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsock.connect( (ip, int(port)) )
clientsock.sendall("Hi, this is test!rn")
recvdata = clientsock.recv(1024)
print "Data: ", recvdata
clientsock.close()

업계가 감추려 하는 컴퓨터 보안의 진실 – the myths of security

처음에 책 제목을 보고, 책을 읽은 다음에 생각난 것은 “낚였다” 입니다. 아, 물론 책 내용이 나쁜것이 아닙니다. 다만!!! 제목이 조금 잘못된게 아닌가 합니다. 원서의 제목은 밑에 있듯이 “the myths of security” 입니다. 보안에 대한 잘못된 오해!!! 이정도의 느낌인데, 아 뭔가 업계가 감추고자 하는 것이 있는가? 이렇게 생각해 버린거죠.

책 내용 자체는 상당히 흥미 진진한 내용들을 담고 있습니다. 저자 분 자체가 맥아피에서 안티바이러스 엔진 쪽을 담당하셨던 분이고 지금은 맥아피에서 SaaS 부분 CTO 로 있는 분인데, 사람들이 착각하기 쉬운 부분들에 대해서 본인의 생각을 잘 설명해주고 계십니다.

제가 특히 책을 보고 놀라웠던 점은, 지금의 인증서 기반 보안의 헛점을 이용해서 15만불 정도 들이면, 실제 인증기관을 만들어서 “사기” 등의 행동을 할 수 있다는 것입니다. 저런 건 돈이 들어서 못할꺼야? 라고 생각했던 제 생각이, 충분히 가능하다는 것이죠. 그 외에도, 왜 안티바이러스 즉, 백신이 깔리면 왜 느려지는가 등등 전체적으로 사용자들이 알아두면 좋을 재미난 내용들이 많이 있습니다.

특히, 우리가 일반적으로 안전하다고 믿는 많은 것들이 사실 안전하지 않다라는 것과, 다만 워낙 쉽게 뚫리는 PC가 많아서 일반적으로 시간을 덜 쓴다가 안전함의 이유라는 것을 아시게 되면, 충격을 받으실 껍니다.

클라우딩 컴퓨팅 – 당신이 알고 있는 컴퓨터의시대는 끝났다.

현재의 IT 에서의 가장 큰 화두 두개는 “클라우드” 와 “모바일” 입니다. 특히, 최종 사용자의 입장에서 위의 두개는 서로 떨어져 있지 않고, 하나로 보입니다. 왜냐하면 우리는 “스마트폰” 을 이용하여, 메일을 읽고, 친구와 SNS 로 이야기를 나누고, 음악을 듣고, 동영상을 보며, 생활을 하고 있습니다.

“모바일”은 쉽게 와 닫는데, “클라우드” 는 과연 뭐냐? 라고 물어보신다면, 최종 사용자의 입장에서 클라우드는 예전과 동일합니다. 눈에 보이는 것, 사용성은 일반 “웹하드”를 쓰거나, 포털에 접속해서 메일을 보내고, 읽을 때, 동일합니다. 단지 예전보다 인터넷 접속이 편해지고, PC에 있던 자료를 웹에 올려놓고 쓰는 수준에서는 말이죠.

이미 관심 있는 분들도 많으시겠지만, 구글, 네이버등에서는 웹으로 문서 작성및 저장 할 수 있는 기능을 제공하고 있습니다. 구글의 구글 App 이라고 부르는 부분에서는 엑셀과 같은 것, 파워포인트와 비슷한 것들도 제공할 수 있습니다. 세일즈 포스닷컴 같은 곳도 있구요. 클라우드에서는 이런 부분은 SaaS(Software As a Service) 라고 부릅니다. 사용자 입장에서는 그냥 웹에서 일반적인 소프트웨어(문서작성, 동영상감상) 를 사용한다고 느끼게 됩니다.

이제 또 다른 부분을 보면 Google App Engine 이라든가, 아마존에서 시작한 BeansTalk 같은 경우에는, 개발자의 입장에서 쉽게 쇼핑몰일이라든지, 일정관리 사이트 등의 특정 기능들을 하는 사이트를 쉽게 만들어서 최종 사용자들에게 서비스 할 수 있게 해줍니다. 이미 밑단의 많은 기능들을 Google 이나 아마존에서 제공해주므로, 처음에는 쉽게 접근이 가능하지만, 다른 쪽에 다시 이런걸 구축하기는 힘들어집니다. 즉, 일종의 Platform을 제공해 줍니다. 이런 부분을 우리는 PaaS( Platform as a Service) 라고 합니다.

그리고 아예 컴퓨터를 가상으로 제공해주는 서비스가 있습니다. 실제 물리적 PC일 수도 있고, 가상화를 이용한 가상화된 PC 일 수도 있습니다.(보통은 가상화입니다.) 사용자가 요청하면 바로 몇분 이내에 서비스를 할 수 있는 서버가 제공됩니다. 그냥 하나의 서버를 받은 것이므로, 필요한 소프트웨어라든지, 환경 설정이라는 것들을 사용자가 해야 합니다. 이를 Iaas( Infrastructure As a Service ) 라고 합니다. PaaS의 경우에는 사용자가 컨트롤 할 수 있는 부분이 적지만, IaaS의 경우는 나중에 다른 곳으로 옮기기도 쉽습니다. 그리고 사용자가 매번 설정하기가 번거로울 수 도 있기 때문에, 미리 구축된 서버 이미지를 가지고(AMI) 바로 서버를 생성해 줍니다.

현재 SaaS로 앞서가고 있는 곳은 구글, 세일즈 포스 닷컴 등이고, PaaS는 구글, 아마존, IaaS는 아마존, KT도 이번에 새로 도전하고 있습니다. Joyent, Rackspace(OpenStack을 만들어서 공개했죠) 등등 유명한 업체들이 많습니다.

데스크탑 가상화라는 것을 이용해서 아이패드나, 아이폰 등에서 실제 윈도우 PC 나, 가상적으로 제공되는 윈도우 PC에 접근해서 충분히 업무를 볼 수 있는 것이 현실입니다. 현재 KT 가 내부 업무를 이런식으로 처리하기 위한 준비를 하고 있는 것으로 압니다. 이렇게 되면, 정말로, 아무데서나 복잡한 문서를 작성하고, 결재를 받을 수 있는, 정말 스마트 모바일 오피스가 구축이 되는 겁니다.

전체적으로 책 자체는 클라우드 쪽에 관심이 있는 초보자를 위한 책입니다. 기술적인 구성이 어떻게 되고, 이런 부분은 별로 업습니다. 그래도 클라우드란게 무엇이고, 앞으로 우리에게 어떤 변화를 줄 것인지! 에 관심이 가신다면, 읽어보시면 재미있게 읽을 수 있을꺼라고 생각합니다.

혹시나, 좀 더 클라우드에 관심이 생기신다면, 다음과 같은 책들을 읽으시면 좋습니다.
개념 입문서 : 클라우드 컴퓨팅, 클라우드의 충격
기술서 : 클라우드 컴퓨팅 구현 기술, 클라우드 컴퓨팅 애플리케이션 아키텍처

등을 추천해 드립니다.

검색 패턴 – 우리에게 검색의 의미란?

“검색 패턴”이라는 책 이름을 처음 봤을때, 생각한 건, 아, 검색에 대한 기술 서적이 새로 나왔구나. 라는 생각이었습니다.

아직 검색 관련 기술 서적이 거의 없는 국내 현실에서 단비 와 같은 책이 아닐까 하고 두근두근 거리는 가슴을 안고 페이지를 넘기니, 잠시 실망할 수 밖에 없었습니다. 왜냐하면, “검색 패턴” 이라는 책은, 검색을 만들기 위한 어떤 기술적인 부분이 들어가야 하고, 그걸 어떻게 구현해야 하는가? 에 대한 책이 아니기 때문입니다.

그럼 “검색 패턴” 이라는 책은 어떤 책일까요? 좀 더 대상을 명확하게 나누자면, 검색에 대한 관심이 있는 모든 사람이 대상이 댈 수 있습니다. 검색에서, 사용자의 접근 패턴이 어떻게 되는가? 인지는 어떤 식으로 이루어지는가? 우리가 보여주는 화면 구성은 올바른가? 사용자에게 검색 경험을 쉽게 제공하는가? 등등, 어떻게 보면, UX 적인 부분에 대한 설명입니다.

간과하기 쉽지만, 이런 부분은 검색 시스템을 만들 때, 단순한 기술보다, 더 중요한 부분입니다. 아무리 성능이 좋아도 쉽지 않다면, 사용하지 않기 때문이죠.

구글의 경우, 철자가 틀린 단어를 입력했을 경우, 해당 결과와 함께, 사람들이 더 많이 입력한 정확한 철자의 검색결과를 클릭 한번에 볼 수 있도록 상위에 함께 배치합니다.
또, 특정 사이트는, 미리, “CharSyam” 을 검색할려고 하면, “CharSyam charsyam.pe.kr , “CharSyam Korean-American”(전 재미교포가 아닙니다. 저랑 비슷한 이름을 가진 분이 계신거죠) 이런식으로 좀 더 명확하게 결과를 구분할 수 있는 자동완성을 제공할 수도 있습니다.
또 다른 사이트는 검색결과의 우선순위에 따라서 이미지의 크기를 서로 다르게 배치해 주기도 합니다.
심지어 야후는 검색어 자동완성을 이미지로 보여주려고 하는 시도도 하고 있습니다.

“업계가 감추려 하는 컴퓨터 보안의 진실” 이라는 책을 보면, 추천사에 맥아피의 전임 부사장겸 CTO 였던 크리스토퍼 볼린이라는 분이, 정말 뛰어난 기술은 “고객의 목소리”를 듣고, 이를 해결해주는 것이다 라는 말을 하고 있습니다. 보안이라는 분야가 검색이라는 분야와 완전히 다른 분야이지만, 위의 말은 정말로 중요하다는 생각이듭니다. “구글” 이라는 기업이 왜 성장했을 까요? 검색의 품질이 좋았기 때문이라는 것을 모두 알고 있지만, 그 때 고객의 목소리는, “검색의 품질” 이였고, 구글이 이에 대해 잘 캐치가 되었기 때문이 아닐까요? 아직 국내에서는 구글이 네이버나 다음을 따라잡지 못하는 이유가(세계적으로는 정반대이긴 합니다.) 우리 나라 사용자의 목소리는 “통합 검색” 이었고, 네이버나, 다음이 그 목소리를 잘 충족한 것이 아닌가 합니다.

검색의 기술적인 부분 또한 중요하긴 이렇게 검색의 UX는 엄청나게 중요한 역할을 합니다. 이런 부분은 꼭 포털에서만 일어나는 것이 아닙니다. 지금의 화두는 “소셜” 이라고 생각합니다. “소셜네트웤”, “소셜커머스” 이렇게 여러가지가 있는데, GPS 를 이용한 위치 정보를 이용한 “맛집 탐색” 이라든지, “쿠폰 발행” 이라든지, 이런 검색의 경험은 일반적인 검색과 또 다릅니다.

해당 위치의 지도에서 목록을 보여줄 수도 있고, 리스트 형태로 인기도 순으로 표시해줄 수도 있습니다. 리스트를 표시하는 방식도 한번에 모든 걸 보여줄 수도 있고, 페이지 방식으로 보여줄 수도 있고, 밑으로 내려가면, 자동으로 밑에 추가가 되는 형식도 됩니다. 리스트 형식 대신에, 플로우 형식으로, 이미지를 보여주듯이 보여줄 수도 있습니다. 또한 증강 현실을 이용해서 보이는 곳의 정보를 보여줄 수도 있습니다. 즉 검색은 정보의 탐색 만이 아니라, 이를 어떻게 표현하고 전달 할 것인지도 중요한 이슈가 됩니다.

“올 컬러” 였던 것도 좋았지만, 이 책을 읽으면서 가장 좋았던 점은, 검색을 위한 기술이 아니라 검색이라는 것 자체에 대한 설명이었습니다. 200p 정도의 짧은 책이지만, 그 내용은 사고의 폭을 많이 넓혀주는 좋은 책입니다.

File Description Passing with Python

요새 Python 에 대해서 공부를 하고 있습니다. 정확하게는 Python 을 이용한 서버인데

서버의 대세는 Multi-Core, Multi-Threading 입니다. 그런데

cPython 의 경우에 GIL(Global Interpreter Lock) 이라는 무서운 녀석이 이 Multi-Threading 을

막고 있습니다.( JPython 이나 IronPython 의 경우는 Lock 구현이 달라서 이런 문제가 없다고 합니다.

그러나 많은 모듈들이 cPython 으로 존재하고 있어서 T.T )

GIL은 다음 사이트에서 http://www.dabeaz.com/python/UnderstandingGIL.pdf 자세한 정보를 얻을 수

있습니다.

그래서 cPython 을 쓸 때 Multi-Core 를 활용하기 좋은 모델은 Multi-Thread 가 아니라 Multi-Process

라고 할 수 있습니다. 그렇다면 Multi-Process를 활용한 서버 모델에는 어떤 것들이 있을까요?

일반적으로 서버 프로그래밍을 조금 공부하셨던 분들은(절대로 하셨던 분들이 아니라 공부하셨던 분입니다. -__- )

Preforked 방식이나, Process Per Client 방식에 대해서 아실껍니다.

일반적으로 적은 규모에서는 Client Per Process 의 방식이 구현이 편하고, 적당한 성능을 발휘해 주는 데,

처리량이 많거나 동시 접속 수가 많다면, Client Per Process 방식은 좋은 방식은 아닙니다. 그래서 선택하게

되는 것이 Preforked 방식입니다.( Thread 방식에서는 Thread Pool 을 많이 사용합니다. 똑같이 Thread Per Client

나 PreThread 방식도 사용가능합니다. )

그런데 이럴 때, Accept 를 어떻게 할 것인지에 대해서 고민을 하게 됩니다.

보통 일반적으로 쉽게 사용할 수 있는 모델은 Accept Socket 을 생성한 후 Fork 해서 Child 에서 직접적으로

Accept를 하게 되는 모델입니다. Unix Network Programming 의 서버 모델을 참고하세요.

그런데 위의 모델의 경우 Thundering herd problem 이라는 것에 걸리게 됩니다. 같은 Descriptor 에 대해서

Acceptor 나 Select 를 하게 되어서 Event 를 대기하게 된 Process 들이 하나의 Event 가 발생했을 때,

모두 wake up 하게 되어서 서로 경쟁하고 그 중 하나만 Accept 가 성공한 다음 다시 나머지 Process 들이 Sleep

해야 되는 이슈가 발생하게 되는 겁니다. 그래서 Unix Network Programming 의 책을 보게 되면, Parent 에서만

Accept 를 하고 실제 accept 된 socket 은 CHILD 에게 passing 하므로써 해당 Process 가 해당 Client 를 처리하게

하는 모델이 가장 좋다고 제안합니다.(첫번 째 모델로, Lock 을 이용해서 전체 중에 Lock을 획득한 하나만 Accept 를 하게

하는 방법도 있습니다.)

Thread 라면 굉장히 쉽게 File Descriptor 전달이 쉽습니다. 그런데 Process 간의 전달은 조금 힘이듭니다.

Advanced Progamming in Unix Environment 에 보면 해당 방법이 나와있는데, 예제 코드만 보면 이해가 어려워서

특히 Python 에서 어떻게 하는지 어렵기 때문에 간단한 샘플을 만들어보았습니다. 결과만 보면 쉬운걸 고생했습니다.

먼저 Python 에서 직접전으로 FD 전달이 안되고 linux 에서는 UnixDomianSocket 을 이용한 sendmsg, recvmsg 를

사용해야 합니다. 검색을 해보면 이것외에, fcntl.ioctl 을 이용하는 방법들이 있는데 linux 에서는 안되더군요. T.T
(왜 2.6에서도 안되는 T.T)

단 이미, 선지자들이 sendmsg, recvmsg binding 을 만들어 두어서 쉽게 사용할 수 있습니다.

python-passfd 를 설치하면 됩니다.

#!/usr/bin/env python

import os
import sys
import subprocess
import fcntl
import SocketServer
import socket, time
from passfd import sendfd, recvfd
import _passfd

m_max_process_cnt = 10
m_cur_process_cnt = 0
os_pipe_list = []

count = 0
class SocketHandler(SocketServer.StreamRequestHandler):
    """
    """

    def handle(self):
        global count
        sock = self.request
        if count == 10:
            count = 0

        pout = (os_pipe_list[count])
        print "pipe out" , str(pout), sock.fileno()
        try:
            sendfd( pout, sock )
            sock.close()
        except Exception, e:
            print e

        count += 1

def child_do(index, pin):
    'child_do()'

    try:
        while True:
            'do'
            fd, m = recvfd(pin);
            print index, fd, m
            sock = socket.fromfd(fd,1,1)
            sock.send("1234")
            sock.close()
            return

            while True:
                data = sock.recv(1024)
                if not data:
                    print "closesocket: ", sock.fileno()
                    sock.close()
                    break
                else:
                    sock.send(data)
    except:
        sys.exit(1)

def parent_do():
    'parent_do()'
    try:
        server = SocketServer.TCPServer( ("localhost", 8000), SocketHandler )
        server.serve_forever()
    except:
        sys.exit(1)

if __name__ == "__main__":

    for i in range(m_max_process_cnt):
        (pin, pout) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
        print pin, pout

        pid = os.fork()

        if pid == 0:
            pin.close()
            child_do(i, pout)
        else:
            pout.close()
            os_pipe_list.append(pin)

    parent_do()

    sys.exit(0)

Cassandra Secondary Index 사용방법, Cassandra 0.7.0 에서는 name 을 바로 Column 명으로 사용하지 못합니다.

Cassandra 에서 Secondary Index 를 사용하기 위해서 테스트를 하다가 좀 삽질을 하게
되었습니다.

현재 https://issues.apache.org/jira/browse/CASSANDRA-1995 에 등록되어 있고
0.7.1 에서는 Fix 된 문제라고 합니다. 문제는 간단하게

$ bin/cassandra-cli –host localhost
Connected to: “Test Cluster” on localhost/9160
Welcome to cassandra CLI.

Type ‘help;’ or ‘?’ for help. Type ‘quit;’ or ‘exit;’ to quit.
[default@unknown] create keyspace demo;
[default@unknown] use demo;
[default@demo] create column family users with comparator=UTF8Type
… and column_metadata=[{column_name: full_name, validation_class: UTF8Type},
... {column_name: birth_date, validation_class: LongType, index_type: KEYS}];

[default@demo] set users[bsanderson][full_name] = ‘Brandon Sanderson’;
[default@demo] set users[bsanderson][birth_date] = 1975;
[default@demo] set users[prothfuss][full_name] = ‘Patrick Rothfuss’;
[default@demo] set users[prothfuss][birth_date] = 1973;
[default@demo] set users[htayler][full_name] = ‘Howard Tayler’;
[default@demo] set users[htayler][birth_date] = 1968;

[default@demo] get users where birth_date = 1973;

위와 같은 형태로 Column Family 가 생성이 가능합니다. birth_data 가 Seconday Index 로 설정이
되었습니다.

LongType 말고 UTF8Type 도 같은 방식으로 생성이 가능합니다.

[default@demo] update column family users with comparator=UTF8Type
… and column_metadata=[{column_name: full_name, validation_class: UTF8Type},
... {column_name: birth_date, validation_class: LongType, index_type: KEYS},
... {column_name: state, validation_class: UTF8Type, index_type: KEYS}];

[default@demo] get users where state = ‘UT’;

그런데 위에 column_name 을 name 으로만 지정하면 제대로 동작하지 않습니다.
이는 show cluster name 이라는 keyword 를 파싱하기 위한 동작의 side-effect 라고 합니다.

그러면 꼭 name 을 사용하지 못하는가? 는 아닙니다.

get Users['charsyam'];
get Users[charsyam];

이 동일하게 동작하는 것 처럼 name 대신에 ‘name’으로 지정해주면 문제는 해결됩니다.
단, 사용할 때도 이때는 꼭 get Users['charsyam']['name'] 형태로 이용해야 합니다.

Follow

Get every new post delivered to your Inbox.

Join 28 other followers