블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

분산 로그 수집기 Fluentd 소개


조대협 (http://bcho.tistory.com)



요즘 들어 빅데이타 분석 관련 기술들을 보다보니, 역시나 여러 데이타 소스에서 데이타를 수집해 오는 부분이 여러 데이타 소스를 커버해야 하고, 분산된 여러 서버에서 데이타를 수집해야 하는 만큼 수집 컴포넌트의 중요성이 점점 더 올라가는 것 같다.

그래서 요즘 빅데이타를 위한 데이타(및 로그) 수집 플랫폼을 보고 있는데, 예전 Flume 등 여러 로그 수집 솔루션이 있었는 것에 비해서 조금 정리된 느낌이라고나 할까?  Scribed, Fluentd 그리고 ELK (Elastic Search + Logstash + Kibana 조합)에서 사용되는 Logstash등이 있는데, 대부분 Fluentd와 Logstash로 수렴 되는 것 같다. 양쪽 모두 오픈소스이고 별도의 엔터프라이즈 라이센스 정책을 가지고 있다.

Logstash는 아키텍쳐 적응에 대한 유연성과 연동 솔루션에 대한 호환성을 강조하고 있기 때문에 타 솔루션과 연동이 강하고 반면, Fluentd는 아키텍쳐의 단순성과 이를 기반으로 한 안정성을 초점을 두고 있다. 그래서 아키텍쳐 구성이나 설정이 간단하다.


이 글에서는 Fluentd에 대한 간략한 개념과 사용 방법에 대해서 알아보도록 하겠다.

Fluentd를 이용한 로그 수집 아키텍쳐

Fluentd를 이용한 로그 수집 아키텍쳐를 살펴보면 다음과 같다.

아래 그림과 같이 각 서버에, Fluentd를 설치하면, 서버에서 기동되고 있는 서버(또는 애플리케이션)에서 로그를 수집해서 중앙 로그 저장소 (Log Store)로 전송 하는 방식이다.




위의 그림은 가장 기본적인 구조로 Fluentd가 로그 수집 에이전트 역할만을 하는 구조인데, 이에 더해서 다음과 같이 각 서버에서 Fluentd에서 수집한 로그를 다른 Fluentd로 보내서 이 Fluentd가 최종적으로 로그 저장소에 저장하도록 할 수 도 있다.


중간에 fluentd를 넣는 이유는, 이 fluentd가 앞에서 들어오는 로그들을 수집해서 로그 저장소에 넣기 전에 로그 트래픽을 Throttling (속도 조절)을 해서 로그 저장소의 용량에 맞게 트래픽을 조정을 할 수 있다.

또는 다음 그림과 같이 로그를 여러개의 저장소에 복제해서 저장하거나 로그의 종류에 따라서 각각 다른 로그 저장소로 라우팅이 가능하다.


Fluentd 내부 구조

Fluentd를 이용해서 로그 수집 아키텍쳐를 구성하는 방법을 대략적으로 알아보았는데, 그렇다면 Fluentd 자체의 구조는 어떻게 되어 있을까?

Fluentd는 크게 다음 그림과 같이 Input,Parser,Engine,Filter,Buffer,Ouput,Formatter 7개의 컴포넌트로 구성이 된다.  7개의 컴포넌트중 Engine을 제외한 나머지 6개는 플러그인 형태로 제공이 되서 사용자가 설정이 가능하다.

일반적인 데이타 흐름은 Input → Engine → Output 의 흐름으로 이루어 지고,  Parser, Buffer, Filter, Formatter 등은 설정에 따라서 선택적으로 추가 또는 삭제할 수 있다.



Input

Input은 로그를 수집하는 플러그인으로, 다양한 로그 소스를 지원한다. HTTP, tail, TCP 등 기본 플러그인 이외에도, 확장 플러그인을 통해서 다양한 서버나 애플리케이션으로 부터 다양한 포맷의 데이타를 수집할 수 있도록 해준다.

Parser (Optional)

Input 플러그인을 통해서 데이타를 읽어도 데이타 포맷이 Fluentd에서 지원하지 않는 데이타 포맷인 경우가 있기 때문에, 이 데이타를 파싱 하기 위해서, Parser 플러그인을 선택적으로 사용할 수 있다. Regular expression  기반으로 스트링을 Parsing 하는 플러그인 뿐 아니라, apache, nginx, syslog등 다양한 포맷의 데이타를 파싱할 수 있는 플러그인을 제공한다.

Filter (Optional)

Filter 플러그인을 읽어드린 데이타를 output으로 보내기 전에, 다음과 같은 3가지 기능을 한다.

  • 필터링

  • 데이타 필드 추가

  • 데이타 필드 삭제 또는 특정 필드 마스킹

필터링은 특정 데이타만 output 필드로 보내고, 나머지는 버리도록 한다. 예를 들어 로그 데이타에 “seoul”이라는 문자열이 있을 경우만 로그 서버로 보내거나 “error”, “warning”과 같은 특정 패턴이 있을 경우에만 로그 저장소로 보내도록할 수 있다.


데이타 필드 추가는 기존 들어온 로그 데이타에 데이타를 전송한 서버명 (Host명)등을 추가해서 로그 저장소로 보낼 수 있다.

마지막으로 데이타 필드 삭제는 불필요한 필드를 삭제하거나 개인 정보등 민감 정보를 삭제하거나 해쉬화하여 데이타 저장소로 보낼 수 있는 기능을 한다.

Output

Output은 Input 플러그인과 반대로, 앞에서 필터링된 데이타를  데이타 저장소 솔루션에 데이타를 저장하도록 한다. (mongodb나 AWS S3 , Google의 Big query등)

Formatter (Optional)

Output 플러그인을 통해서 데이타를 저장소에 쓸 때, Formatter 를 이용하면 쓰는 데이타의 포맷을 정의할 수 있다.(cf. Input의 parser가 포맷에 맞게 읽는 플러그인이라면, Formatter는 Output을 위한 포맷을 지정하는 플러그인이라고 보면 된다.)

Buffer (Optional)

Input에서 들어온 데이타를 바로 Output으로 보내서 쓰는것이 아니라 중간에 선택적으로 Buffer를 둬서 Throttling을 할 수 있다. 버퍼는 File과  Memory 두가지를 사용할 수 있다.

간단하게 구조와 작동 원리를 보면 다음과 같다.



<그림. fluentd의 로그 writing 흐름>

원본  http://docs.fluentd.org/articles/buffer-plugin-overview


버퍼에는 로그데이타를 분리하는 tag 단위로 chunk가 생성이 된다.

chunk는 태그별 큐라고 보면 된다. 예를 들어 error, info, warning, user 와 같이 태그를 분리하면 error 로그는 error chunk에 저장이 되고, info 로그는 info chunk에 저장된다.

Chunk에 데이타가 쌓여서 buffer_chunk_limit 만큼 chunk가 쌓여서 full이 되거나, 또는 설정값에 정의된 flush_interval 주기가 되면 로그 저장소로 로그를 쓰기 위해서 Queue에 전달이 된다.


<그림. Memory buffer 설정 예제>

참고 : http://docs.fluentd.org/articles/buffer-plugin-overview


다음 Queue에서는 데이타를 읽어서 로그 저장소에 데이타를 쓰는데, 로그 저장소에 문제가 없다면 바로 로그가 써지겠지만, 네트워크 에러나 로그 저장소 에러로 로그를 쓰지 못할때는 retry_wait 시간 만큼 대기를 한 후에, 다시 쓰기를 시도한다. 다시 쓰기를 실패하면 전에 기다린 시간의 2배 만큼, 또 실패하면 또 2배만큼을 기다린다. (1초, 2초, 4초,8초…) 다시 쓰기 시도는 설정값에 지정된 retry_limit 횟수까지 계속 진행한다.

만약에 Queue 가 차버렸을때 처리에 대한 정책을 설정할 수 있는데, “exception”과, “block” 모드 두가지고 있고, exception 모드일 경우에는 BufferQueueLimitError 를 내도록 하고, block 모드의 경우에는 BufferQueueLimitError가 해결될때 까지, input plugin을 중지 시킨다 (더이상 로그를 수집하지 않는다는 이야기).

Queue가 차버렸을때 다른 처리 방법으로는 큐가 다 찾을때, Sencondary output을 지정해서, 다른 로그 저장소에 로그를 저장하는 방법이 있다. 예를 들어 로그를 mongodb에 저장하도록 했는데, mongodb 나 네트워크 장애로 로그를 쓸 수 없는 경우에는 secondary output을 AWS S3로 지정해놓고, S3로 로그를 일단 저장하게 하고 나중에 mongodb가 복구된 후에, S3에서 다시 mongodb로 로그를 수집하는 방식을 취할 수 있다.



<그림. Secondary output 설정 예제>

출처 : http://docs.fluentd.org/articles/buffer-plugin-overview


Buffer 플러그인과, 에러 처리에 대한 자세한 내용은 http://docs.fluentd.org/articles/buffer-plugin-overview 를 참고하기 바란다.


데이타 구조

다음으로 Fluentd가 내부적으로 어떻게 로그 데이타를 핸들링 하는지 데이타 구조를 살펴보면 다음과 같다.



출처 :http://pt.slideshare.net/frsyuki/fluentd-set-up-once-collect-more


데이타는 크게 3가지 파트로 구성된다. Time, tag, record

  • Time : 로그데이타의 생성 시간

  • Record : 로그 데이타의 내용으로 JSON형태로 정의된다.

  • Tag : 이게 가장 중요한데, 데이타의 분류이다. 각 로그 레코드는 tag를 통해서 로그의 종류가 정해지는데, 이 tag에 따라서 로그에 대한 필터링,라우팅과 같은 플러그인이 적용 된다.

간단한 테스트

테스트 환경은 맥북을 기준으로 하였다.

http://docs.fluentd.org/articles/install-by-dmg 를 따라서 테스트를 하면 되는데, 먼저 fluentd를 받아서 인스톨을 한다.

인스톨이 끝나면, fluentd 프로세스인 td-agent는 /opt/td-agent/usr/sbin/에 인스톨이 된다.

그리고 디폴트 설정 파일은 /etc/td-agent/td-agent.conf에 저장된다.

td-agent.conf의 내용을 보면 다음과 같다.



<ROOT>

 <match td.*.*>

   type tdlog

   apikey xxxxxx

   auto_create_table

   buffer_type file

   buffer_path /var/log/td-agent/buffer/td

   <secondary>

     type file

     path /var/log/td-agent/failed_records

     buffer_path /var/log/td-agent/failed_records.*

   </secondary>

 </match>

 <match debug.**>

   type stdout

 </match>

 <source>

   type forward

 </source>

 <source>

   type http

   port 8888

 </source>

 <source>

   type debug_agent

   bind 127.0.0.1

   port 24230

 </source>

</ROOT>



<source> 부분을 보면 type이 http, port가 8888인 정의가 있다. 이 정의는 http://localhost:8888 로 부터 로그를 수집하겠다는 정의이다.

다음 <match>부분을 보면 <match debug.**> 라는 정의로 태그가 debug.**  로 정의된 로그에 대해서 type stdout으로, stdout (화면)으로 바로 출력하겠다는 정의이다.

http://localhost:8888/{debug.**} 로 들어오는 요청에 대해서 stdout으로 로그를 출력하겠다는 설정이다.


설정 파일을 확인했으면, 이제 기동을 해보자

/opt/td-agent/usr/sbin 디렉토리에서 -c 옵션으로 설정 파일을 지정하고 td-agent를 다음과 같이 실행해보자

% ./td-agent -c /etc/td-agent/td-agent.conf


에이전트가 실행되었으면 curl 명령을 이용하여 http://localhost:8888/debug.test 로 {"json":"message"} 로그 문자열을 전송해보자

% curl -X POST -d 'json={"json":"message"}' http://localhost:8888/debug.test


다음은 실행 결과 이다.





다음과 같이 td-agent가 기동된 후에,  맨 아랫줄에 debug.test 라는 태그 이름으로 {“json”:”message”}라는 로그가 수집되어 출력된것을 볼 수 있다.

데몬으로 실행하기

앞에서는 CLI상에서 foreground로 실행을 하였는데, 맥에서 서비스로 백그라운드 작업으로 실행을 할 수 있다. 실행 방법은

%sudo launchctl load /Library/LaunchDaemons/td-agent.plist

를 실행하면 백그라운드로 실행된다. 백그라운드로 실행을 위한 스크립트인 td-agent.plist는 fluentd설치시  /Library/LaunchDaemons/td-agent.plist에 자동 생성된다.

백그라운드 작업이기 때문에, stdout이 없고 stdout으로 출력되는 로그는 /var/log/td-agent/td-agent.log로 확인할 수 있다.





실행중인 프로세스를 종료 하는 방법은

%sudo launchctl unload /Library/LaunchDaemons/td-agent.plist

를 사용하면 된다.


다음 글에는 실제로 fluentd 를 설정해서 Google의 Bigquery또는 큐로 로그를 전달하는 설정 방법에 대해서 알아보겠다.



저작자 표시 비영리
신고
Spark의 전체적인 스택 구조

조대협 (http://bcho.tistory.com)

스파크의  전체적인 스택 구조를 보면 다음과 같다.





  • 인프라 계층 : 먼저 스파크가 기동하기 위한 인프라는 스파크가 독립적으로 기동할 수 있는 Standalone Scheudler가 있고 (그냥 스팍만 OS위에 깔아서 사용한다고 생각하면 된다). 또는 하둡 종합 플랫폼인 YARN 위에서 기동될 수 있고 또는 Docker 가상화 플랫폼인 Mesos 위에서 기동될 수 있다.
  • 스파크 코어 : 메모리 기반의 분산 클러스터 컴퓨팅 환경인 스팍 코어가 그 위에 올라간다. 
  • 스파크 라이브러리  : 다음으로는 이 스파크 코어를 이용하여 특정한 기능에 목적이 맞추어진 각각의 라이브러리가 돌아간다. 빅데이타를 SQL로 핸들링할 수 있게 해주는 Spark SQL, 실시간으로 들어오는 데이타에 대한 리얼타임 스트리밍 처리를 해주는 Spark Streaming, 그리고 머신러닝을 위한 MLib, 그래프 데이타 프로세싱이 가능한 GraphX가 있다.

현재 글에서 설명하고 있는 부분은 먼저 스파크에 대한 기본을 이해하기 위해서 Spark Core 부분을 중점적으로 설명하고 있다. 


저작자 표시 비영리
신고



Apache Spark Cluster 구조

스팍의 기본 구조는 다음과 같다.
스팍 프로그램은 일반적으로 “Driver Program”이라고 하는데, 이 Driver Program 은 여러개의 병렬적인 작업으로 나뉘어져사 Spark의 Worker Node(서버)에 있는  Executor(프로세스)에서 실행된다.



1. SparkContext가 SparkClusterManager에 접속한다. 이 클러스터 메니져는 스팍 자체의 클러스터 메니져가 될 수 도 있고 Mesos,YARN 등이 될 수 있다. 이 클러스터 메니저를 통해서 가용한 Excutor 들을 할당 받는다
2. Excutor를 할당 받으면, 각각의 Executor들에게 수행할 코드를 보낸다.
3. 다음으로 각 Excutor 안에서 Task에서 로직을 수행한다.


  • Executor : Process
  • Task : A Unit of work that will sent to one executor

cf. Storm 과 개념이 헷갈릴 수 있는데, 
Storm 은 Node가 하드웨어 서버, Worker가 프로세스,Executor가 쓰레드
Spark 은 Worker Node가 하드웨어 서버, Executor가 프로세스 이다.  


저작자 표시 비영리
신고



Apache Spark 설치 하기


조대협 (http://bcho.tistory.com)


Spark 설치 하기


1. 스팍 홈페이지에서 다운로드.


다운로드시 Pre-built in Spark을 골라야 함. 여기서는 Hadoop 2.6용으로 빌드된 스팍을 선택한다.








2. 스팍 쉘을 실행 해보자


인스톨 디렉토리에서, 

%./bin/pyspark





을 실행하면, 위와 같이 파이썬 기반의 스팍 쉘이 실행됨을 확인할 수 있다.


3. 로깅 레벨 조정 및 간단한 스팍 예제


디폴트 로깅은 INFO 레벨로 되어 있기 때문에, 쉘에서 명령어를 하나라도 실행하면 INFO 메세지가 우루루 나온다. (몬가 할때 결과 값보다, 오히려 INFO 메세지가 많이 나온다.)

그래서, conf/log4j.properties 파일을 conf/log4j.properties.templates 파일을 복사해서 만든후 

log4j.rootCategory를 Info에서 WARN 레벨로 다음과 같이 수정한다.


log4j.rootCategory=WARN, console






환경 설정이 끝났으면 간단한 예제를 돌려보자

$SPARK_HOME 디렉토리에 있는  README.md 파일을 읽어서, 라인 수를 카운트 하는 예제이다.





스팍은 자체적으로 클러스터를 모니터링 할 수 있는 차체적인 Web UI가 있다. 

http://localhost:4040에 접속하면 다음과 같이 스팍 클러스터에 대한 모니터링 화명을 얻을 수 있다.









저작자 표시 비영리
신고

ZooKeeper란 무엇인가?

조대협 (http://bcho.tistory.com)


소개


분산 시스템을 설계 하다보면, 가장 문제점 중의 하나가 분산된 시스템간의 정보를 어떻게 공유할것이고, 클러스터에 있는 서버들의 상태를 체크할 필요가 있으며 또한, 분산된 서버들간에 동기화를 위한 락(lock)을 처리하는 것들이 문제로 부딪힌다.


이러한 문제를 해결하는 시스템을 코디네이션 서비스 시스템 (coordination service)라고 하는데, Apache Zookeeper가 대표적이다. 이 코디네이션 서비스는 분산 시스템 내에서 중요한 상태 정보나 설정 정보등을 유지하기 때문에, 코디네이션 서비스의 장애는 전체 시스템의 장애를 유발하기 때문에, 이중화등을 통하여 고가용성을 제공해야 한다. ZooKeeper는 이러한 특성을 잘 제공하고 있는데, 그런 이유로 이미 유명한 분산 솔루션에 많이 사용되고 있다. NoSQL의 한종류인 Apache HBase, 대용량 분산 큐 시스템인 Kafka등이 그 대표적인 사례이다.

분산 시스템을 코디네이션 하는 용도로 디자인이 되었기 때문에, 데이타 억세스가 빨라야 하며, 자체적으로 장애에 대한 대응성을 가져야 한다. 그래서 Zookeeper는 자체적으로 클러스터링을 제공하며, 장애에도 데이타 유실 없이 fail over/fail back이 가능하다.


Apache Zookeeper의 기능은 사실상 별로 없다. 디렉토리 구조기반으로 znode라는 데이타 저장 객체를 제공하고, (key-value식). 이 객체에 데이타를 넣고 빼는 기능만을 제공한다. 일단 디렉토리 형식을 사용하기 때문에 데이타를 계층화된 구조로 저장하기 용이하다.


데이타 모델


데이타 모델은 간단하다. 디렉토리 구조의 각 노드에 데이타를 저장할 수 있다.



 

노드는 아래와 같이 기능에 따라 몇가지 종류로 나뉘어 지는데 


  • Persistent Node : 노드에 데이타를 저장하면 일부러 삭제하지 않는 이상 삭제되지 않고 영구히 저장된다.

  • Ephemeral Node : 노드를 생성한 클라이언트의 세션이 연결되어 있을 경우만 유효하다. 즉 클라이언트 연결이 끊어지는 순간 삭제 된다. 이를 통해서 클라이언트가 연결이 되어 있는지 아닌지를 판단하는데 사용할 수 있다. (클러스터를 구성할때 클러스터내에 서버가 들어오면, 이 Ephemeral Node로 등록하면 된다.)

  • Sequence Node : 노드를 생성할때 자동으로 sequence 번호가 붙는 노드이다. 주로 분산락을 구현하는데 이용된다.


Watcher


Watch 기능은 ZooKeeper 클라이언트가 특정 znode에 watch를 걸어놓으면, 해당 znode가 변경이 되었을때, 클라이언트로 callback 호출을 날려서 클라이언트에 해당 znode가 변경이 되었음을 알려준다. 그리고 해당 watcher는 삭제 된다. 


ZooKeeper 활용 시나리오


Zookeeper는 단순히, 디렉토리 형태의 데이타 저장소이지만, 노드의 종류별 특성과, Watcher 기능들을 활용하면 다양한 시나리오에 사용할 수 있다. 


  1. 큐 : Watcher와 Sequence node를 이용하면, 큐를 구현할 수 있는데, Queue 라는 Node를 만든 후에, 이 노드의 Child node를 sequence node로 구성하면, 새롭게 생성되는 메세지들은 이 sequence node로 순차적으로 생성된다. 이 큐를 읽는 클라이언트가 이 큐 node를 watch 하도록 설정하면, 이 클라이언트는 새로운 메세지가 들어올 때 마다 call back을 받아서, 마치 메세지 Queue의 pub/sub 과 같은 형태의 효과를 낼 수 있다. 대용량 메세지나 애플리케이션 성격상의 메세지는 일반적인 큐 솔루션인 Rabbit MQ등을 활용하고, ZooKeeper는 클러스터간 통신용 큐로 활용하는 것을 고려해볼 수 있다.

  2. 서버 설정 정보 : 가장 일반적인 용도로는 클러스터 내의 각 서버들의 설정 정보(Configuration)를 저장하는 저장소로 쓸 수 있다. 정보가 안정적으로 저장이 될 뿐 아니라. Watch 기능을 이용하면, 설정 정보가 저장될 경우, 각 서버로 알려서 바로 반영을 할 수 있다.

  3. 클러스터 정보 : 현재 클러스터에서 기동중인 서버 목록을 유지할 수 있다. Ephemeral Node는 Zookeeper 클라이언트가 살아 있을 경우에만 유효하기 때문에, 클러스터내의 각 서버가 Ephemeral Node를 등록하도록 하면, 해당 서버가 죽으면 Ephemeral Node 가 삭제 되기 때문에 클러스터 내의 살아 있는 Node 리스트만 유지할 수 있다. 조금 더 발전하면, 클러스터가 master/slave 구조일때, master 서버가 죽었을 때, 다른 master 서버를 선출하는 election logic 도 구현이 가능하다. (https://zookeeper.apache.org/doc/r3.4.6/recipes.html#sc_recipes_Queues 참고)

  4. 글로벌 락 : Zookeeper를 이용하여 많이 사용되는 시나리오 중의 하나인데, 여러개의 서버로 구성된 분산 서버가 공유 자원을 접근하려고 했을때, 동시에 하나의 작업만이 발생해야 한다고 할때, 그 작업에 Lock을 걸고 작업을 할 수 있는 기능을 구현할때 사용한다. 자바 멀티 쓰레드 프로그램에서 synchronized를 생각하면 쉽게 이해가 가능할 것이다.

자세한 구현 방식과 시나리오에 대해서는 https://zookeeper.apache.org/doc/r3.4.6/recipes.html 를 참고하기 바란다.


설치

https://zookeeper.apache.org 에서 gz 파일을 다운 받아서, 압축만 풀면 간단하게 설치는 끝난다. 여기서는 안정 버전인 3.4.6 버전을 사용하였다. 그리고 c:\dev\tools\zookeeper 디렉토리에 압축을 풀었다.


간단한 테스트 하기

$ZooKeeper_home/conf/zoo.conf를 다음과 같이 작성하자

clientPort=2181

tickTime=2000

dataDir=c:\\temp\\


그리고

c:\dev\tools\zookeeper>.\bin\zkServer.cmd로 서버를 구동한다. 이때 하나의 서버만 구동하기 때문에, 이를 standalone 모드라고 한다. (원래 Production에서는 데이타 복제를 통한 페일오버를 지원하기 위해서 여러개의 서버를 띄운다.)

다음으로 zookeepr에 접속해보자

C:\dev\tools\zookeeper>bin\zkCli -server 127.0.0.1:2181


다음과 같이 쉘이 실행됨을 확인할 수 있다.



 

다음으로, 새로운 znode를 하나 만들어보자. 다음과 같이 create 명령을 이용하여 zk_test 노드를 “hello”라는 값으로 생성한다. 다음에, get 명령을 이용하여 데이타를 조회한다.

 

다음으로, my_server1 라는 노드를 추가로 만들자 그리고, ls / 명령어를 실행하면 다음과 같이 아까 만든 zk_test 노드와, my_server1 노드가 생성됨을 확인할 수 있다.

 


참고 자료

https://zookeeper.apache.org/doc/r3.4.6/zookeeperStarted.html

http://helloworld.naver.com/helloworld/textyle/294797 이 글은 레디스 클러스터를 주키퍼를 이용하여 구현한 실 사례로, 읽어볼 여지가 있다.


저작자 표시 비영리
신고

grpc 설치하기

프로그래밍 | 2015.04.02 02:11 | Posted by 조대협

Google RPC 설치하기

(조대협 http://bcho.tistory.com)


지난 GRPC 소개에 이어서 오늘은 JAVA에서 GRPC를 사용하기 위한 설치 방법을 설명한다.


  • https://github.com/grpc/grpc-common/tree/master/java
  • https://github.com/grpc/grpc-common
  • https://github.com/grpc/grpc-common/blob/master/java/javatutorial.md
  • https://github.com/grpc/grpc-java


글들을 참고하였으며, 컴파일 환경 설정등을 위해서 생각보다 시간이 많이 소요된다. (삽질,Visual Studio 설치 포함 한 2~3시간 걸린듯)


grpc hello world / java





grpc-java 설치하기

https://github.com/grpc/grpc-java#how-to-build 를 참고


준비 : java 8, maven 3.2.x,gradle 2.3 필요


1. 코드 받기

 C:\dev\libs> git clone https://github.com/grpc/grpc-java


2. 관련 라이브러리 설치


1) Netty 4.1 설치

grpc-java는 Netty 4.1에 기반함. 아래절차에 따라서 설치한다.

cd C:\dev\libs\grpc-java>

$ git submodule update --init

$ cd lib/netty

$ mvn install -pl codec-http2 -am -DskipTests=true


2) Protocolbuf 3.0.0-alhpa-2 설치 (windows)

안타깝게도 알파버전이라 윈도우즈용 인스톨 바이너리가 없다. 소스 받아서 직접 컴파일해야 한다.

윈도우 환경에서는 C/C++ 컴파일러가 필요하니까는 간단하게 Visual Studio 무료 버전을 깔자 https://www.visualstudio.com/en-us/products/free-developer-offers-vs.aspx

(무료 버전 제공)

다음은 c:\dev\lib\protobuf에 설치 하는 순서이다.


C:\dev\libs>git clone https://github.com/google/protobuf.git


다음으로, C:\dev\libs\protobuf\vsprojects 에 들어가면 visual studio 프로젝트 파일이 있음

VC로 Release 빌드하면 됨. (이때 반드시, Release 모드로 빌드할것, Debug 모드로 빌드하면 나중에 grpc-java 빌드할때 링크에러남). Test 코드 빌드하다가 에러가 나는데 무시하자. 테스트 코드가 안들어가 있다.


빌드 후, C:\dev\libs\protobuf\vsprojects 아래에 readme.txt를 보고 따라할것


C:\dev\libs\protobuf\vsprojects\Release 에 빌드 결과가 생김

안에 protoc.exe가 생김



3. grpc-java 설치


위에서 만든 protoc.exe를 path가 있는 디렉토리에 복사하거나.

본인의 경우에는 위의 디렉토리 자체를 다 PATH에 걸어버렸다. (연관 라이브러리들이 있어서리)

다음으로 grpc-java를 설치하자


앞에서 받은 grpc-java 디렉토리로 가서

$ gradlew install -Pprotobuf.include=C:\dev\libs\protobuf\src  -Pprotobuf.libs=C:\dev\libs\protobuf\vsprojects\Release


여기까지 했으면 grpc 설치가 완료되었다. 실제로 동작하는지 확인하려면, 예제 코드를 돌려보면 되는데, 실행 방법은 다음과 같다. 


서버 실행

gradlew :grpc-examples:helloWorldServer -Pprotobuf.include=C:\dev\libs\protobuf\src  -Pprotobuf.libs=C:\dev\libs\protobuf\vsprojects\Release



클라이언트 실행

gradlew :grpc-examples:helloWorldClient -Pprotobuf.include=C:\dev\libs\protobuf\src  -Pprotobuf.libs=C:\dev\libs\protobuf\vsprojects\Release


실행시 위와 같이 protocol buf lib 위치와 소스 위치를 지정해야 하는데, 매번 지정하기 귀찮다면 다음과 같이 환경 변수로 넣어놓아도 된다.

Since specifying those properties every build is bothersome, you can instead create %HOMEDRIVE%%HOMEPATH%.gradle\gradle.properties with contents like:

protobuf.include=C:\\path\\to\\protobuf-3.0.0-alpha-2\\src

protobuf.libs=C:\\path\\to\\protobuf-3.0.0-alpha-2\\vsprojects\\Release


저작자 표시 비영리
신고

Numpy Install

빅데이타/머신러닝 | 2015.02.10 01:31 | Posted by 조대협

NumPy 설치 하기


파이썬으로 머신 러닝을 구현하기 위해서는 수학 라이브러리인 numpy가 필요하다

설치는 

http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy 에서 *.whl 파일을 다운로드 받은후

pip install numpy-1.9.2rc1+mkl-cp27-none-win_amd64.whl (64 비트 기준)

으로 설치 하면 된다.



설치후 확인을 위해서는 위와 같이 from numpy import * 를 한후에, random.rand(4,4)가 제대로 실행되는지 확인하자


참고

머신러닝이나 빅데이타 분석을 위해서는 NumPy 뿐만 아니라 matplot등 다양한 수학 모듈을 깔아야 하는데, 방화벽등이 있거나 하면 깔기가 매우 까다롭다. (의존성 관계도 복잡하고). 그래서 수학용 모듈을 모아 놓은 파이썬 인스톨패키지가 있다. http://www.scipy.org/install.html

처음부터 이걸로 까는게 시간을 절약할 수 있는 방법일듯

저작자 표시 비영리
신고

Windows 7에서 Ruby 개발환경 설정하기




MongoDB in Action 몽고디비 인 액션

저자
카일 뱅커 지음
출판사
제이펍 | 2012-04-20 출간
카테고리
컴퓨터/IT
책소개
MongoDB나 NoSQL에 경험 없는 개발자를 위한 쉽고 실전...
가격비교


이책을 공부하다보니, 예제가 ruby라서, 예상치 않게 Ruby를 살펴보고 있는데, 윈도우즈7에서 Ruby 개발 환경 설정하는 것이 쉽지 않아서 설정 방법을 요약하고자한다.


1. Ruby Install 하기

http://rubyinstaller.org/downloads/ 에서 Ruby Install 바이너리를 받아서 설치한다. 2.2.0-p481(x64)

여기까지는 보통 문제 없이 잘된다.


향후에 모듈을 설치하려면 보통 컴파일 에러가 나오면서 잘 안되는 경우가 많다.

%gem install bson_ext


2. SSL 에러 해결하기

회사등에서 설치할 경우, https를 통해서 gem repository에 접근하는데, 회사 방화벽이나 Proxy에서 SSL 인증서를 변경한다면, 인증서 오류로 인해서 SSL오류가 나면서 설치가 되지 않는 경우가 있다. 이런 문제를 해결하기 위한 대안으로는 gen repository 사이트에 대한 연결을 https에서 http로 변경하면 된다.

% gem sources -r https://rubygems.org/

% gem sources -a http://rubygems.org/


3.컴파일 환경 설정하기

다시 인스톨을 시도 해보면, 또 에러가 날 수 있는데, 컴파일 환경이 설정되어 있지 않는 경우이다. (아래와 같은 에러)



 이 모듈은 native 모듈 (C/C++로 짜여진 모듈)을 포함하고 있기 때문에 십중팔구 인스톨이 안된다. 네이티브 모듈은 컴파일이 필요한데, 이 C/C++을 컴파일 할 수 있는 컴파일러가 없기 때문이다.

Ruby에서는 gcc를 컴파일러로 사용하는데, 윈도우즈에서 이러한 컴파일 환경을 설정하려면 Ruby DevKit을 인스톨 해주면 된다.



http://rubyinstaller.org/downloads/ 에서 설치한 Ruby 버전에 맞는 Development Kit을 받아서 실행한다.

실행하면 압축이 풀리는데, 해당 디렉토리로 가서

%ruby dk.rb init 
을 실행한후

%ruby dk.rb install -f 

를 실행한다.

이때 install 과정에서 config.yaml 파일이 잘못되었다고 에러가 나올 수 있다.(안나오면 다음 스탭으로 진행)

config.yaml 파일을 열어보면 여기에 Ruby 를 설치한 Home directory가 init 단계에서 지정되어 있어야 하는데, 제대로 지정이 안되는 경우가 있다. config.yaml 파일을 열어서 Ruby 설치 디렉토리를 아래와 같이 지정한다. 

※ 아래는 ruby가  C:/dev/lang/Ruby200-x64 에 설치되어 있을 경우이다.


# This configuration file contains the absolute path locations of all

# installed Rubies to be enhanced to work with the DevKit. This config

# file is generated by the 'ruby dk.rb init' step and may be modified

# before running the 'ruby dk.rb install' step. To include any installed

# Rubies that were not automagically discovered, simply add a line below

# the triple hyphens with the absolute path to the Ruby root directory.

#

# Example:

#

# ---

# - C:/ruby19trunk

  - C:/dev/lang/Ruby200-x64


4. msys-1.0 라이브러리 패치

여기까지 하고 다시 모듈 인스톨을 다시 시도 해보자. 그래도 안되고 아래와 같은 에러가 나는 경우가 있다.

m.AllocationBase 0x0, m.BaseAddress 0x60E90000, m.RegionSize 0x170000, m.State 0x10000

Ruby는 윈도우에서 모듈 컴파일을 할대, 앞서 설치한 DEVELOPMENT KIT을 통해서 컴파일을 하는데, 이 KIT는 cygwin을 기반으로 되어 있다. 위의 에러는 cygwin 모듈중에서 나는 에러로

http://support.code-red-tech.com/CodeRedWiki/VirtualAllocPointerNull  에서 msys-1.0.dll을 다운로드 받아서 Development Kit을 설치한 디렉토리의 /bin 디렉토리에서 msys-1.0.dll을 앞에서 다운로드 받은 dll로 overwrite시켜주면 된다.


여기 까지 진행하고 다시 모듈을 인스톨해보면 대부분의 경우 설치가 될것이다.



저작자 표시
신고

'프로그래밍 > Ruby' 카테고리의 다른 글

Ruby 개발환경 설정하기 (윈도우7에서)  (1) 2014.08.18
루비 기본 문법 정리  (1) 2014.08.18

Couchbase Server

#4. 뷰(View) 이해하기

조대협 http://bcho.tistory.com


뷰는 카우치베이스의 아주 강력한 기능중의 하나이다. RDBMS의 뷰의 개념과 유사한 개념으로, 원본 데이터로부터, 필터링을 통하여 원하는 형태의 데이터로 변환하여 보여주는 일종의 읽기 전용 테이블과 유사한 개념으로 보면 된다. 이를 통해서 키-밸류 스토어 기능만 제공하는 일반 NoSQL에 비해서 filtering 뿐만 아니라, Indexing,grouping,ordering과 같은 다양한 기능을 이 뷰를 이용하여 사용할 수 있다.

카우치베이스의 뷰는 원본 데이터에서 자바스크립트로된 맵&리듀스(Map&Reduce) 함수를 통해서 데이터를 정재한 후에, 뷰로 만들어낸다. 간단하게 개념을 잡아보면 다음과 같다.

 


좌측 그림과 같이 이름을 ID로 하고, Country,Role,Age라는 필드를 가지고 있는 값을 VALUE로 저장하고 있다고 하자, 필터링해서 보고 싶은 데이터는 여기서 Country와 Role만을 필터링 하고 싶다. 그래서 맵&리듀스 함수(여기서는 맵 함수만을 사용하였음)를 이용해서 오른쪽과 같은 뷰를 만들어낼 수 있다.


맵&리듀스(Map&Reduce)함수


뷰를 이해하려면 맵&리듀스함수에 대해서 정확하게 이해해야 한다. 맵함수는 버킷에 저장된 모든 데이터에 대해서 맵함수를 실행한다. 뷰를 정의할 때 맵함수는 반드시 정의해야 한다.

function(doc,meta){

 emit(doc.role,doc.country);

}

맵함수는 두개의 인자를 전달 받는다. “doc”는 버킷내의 저장된 개별 데이타로 각 데이터별로 id와 JSON 도큐먼트의 값을 갖는다. “meta” 는 그 데이터에 대한 메타 데이터 (flag,cas 값등)을 리턴한다.

맵함수에서는 이렇게 받은 개별 데이터를 emit이라는 함수로 가공하여 리턴한다. emit 이라는 함수에 필터링등의 로직을 적용할 수 가 있다. emit(인자1,인자2)의 인자1은 뷰의 KEY값을 리턴하고, 인자2는 뷰의 밸류값을 리턴한다.


 emit 함수를 거쳐 맵함수를 끝내면 ID,KEY,VALUE 형식의 데이터 셋이 나오는데, 이를 카우치베이스에서는 “Index”라고 부른다. ID는 원래 데이터에 대한 ID이고, KEY는 뷰의 키값이다. Index는 이 KEY에 따라서 정렬(sorting)된 형태로 리스팅 된다.  그리고 마지막에는 뷰의 값(VALUE)가 저장된다. 이렇게 생성된 Index는 디스크에 저장된다.


저장된 index를 이용해서 리듀스함수(Reduce)를 실행할 수 있는데, 리듀스 함수를 이용해서는 Grouping 기능을 사용할 수 있다. RDBMS의 group by sum이나 group by count와 같은 간단한 기능에서부터 복잡한 계산을 자바스크립트를 이용해서 구현하는 것이 가능하다.



정리하자면 뷰에는 각 버킷내의 개별 데이터를 변환하는 맵함수와, 변환된 개별 데이터를 그룹별로 모아서 처리할 수 있는 리듀스 함수를 갖는다.


Design Document


하나의 버킷에는 여러 개의 뷰를 생성할 수 있다. 아래 그림과 같이 뷰는 Design document라는 단위로 묶이게 되고 각 뷰는 그에 대칭 되는 맵&리듀스 함수를 가지고 있다.

 

 

카우치베이스의 문서를 보면 http://blog.couchbase.com/10-things-developers-should-know-about-couchbase 성능상 무리가 없게 하기 위해서는 하나의 버킷당 4개의 Design Document 정도가 적절하며, 하나의 Design Document당 최대 10개 정도의 뷰를 구현하는 것이 적절하다고 권고하고 있다. (즉 버킷당 최대 40대 정도의 뷰가 적절)


콘솔에서 뷰 만들기


개념을 이해 했으면 이제 간단한 뷰를 만들어보자, 카우치베이스는 웹콘솔에서 뷰생성 및 개발 테스트를 할 수 있도록 지원한다. 카우치베이스 웹콘솔로 이동한후 상단메뉴에서 “Views” 메뉴를 선택한후 아래에 나오는 리스트박스에서 뷰를 생성하고 싶은 버킷을 선택한다. 

다음으로, 아래에 나오는 “Create Development View” 버튼을 선택하면 뷰를 생성할 수 있다.


 

생성 버튼을 누르면 아래와 같이 대화상자가 뜨는데, 첫번째는 Design Document 명이다. 그리고 다음 텍스트 상자가 뷰 이름을 넣는 상자이다.

 


이때, design document를 넣는 텍스트박스에서 Design Document 이름이 “dev_”로 시작하는 것을 볼 수 있는데, Design document는 두 가지 타입이있다. 개발을 위한 개발용 “Development view”와 실제 운영에서 사용할 수 있는 “Production view”가 있다. 이 둘의 차이점은 다음과 같다.

  • Development View : 처음에 뷰를 생성하면 Development View로 생성된다. Design document 이름은 “_design/dev_”로 시작된다. Development View의 경우 버킷의 모든데이타에 대해서 Index를 만드는 것이 아니라 개발 목적이기 때문에 일부의 데이터에 대해서만 Index를 생성한다.
  • Production View : Development View를 이용해서 개발과 테스트를 완료하면 Publish하여 Production View로 전환한다,  Production View는 버킷의 전체 데이터로 Index를 생성한다. 

※ Development View에서 개발 및 테스트가 완료되었으면 반드시 Production View로 배포를 진행해야 한다.

뷰가 생성되었으면 콘솔에서 아래와 같이 뷰의 맵&리듀스 코드를 작성하고 테스트를 해볼 수 있다.



위에 "▼cath”라는 창에 맵&리듀스 코드 작성을 돕기위해서 버킷에 저장된 데이터 중 random으로 출력해서 샘플로 보여준다. “cath”는 샘플로 출력되는 도큐먼트의 ID이다.

아래 “▼View Code” 창 부분에는 왼쪽에는 맵 함수를 오른쪽에는 리듀스 함수를 직접 코딩해볼 수 있다. 그리고 맨아래 부분에는 이 맵&리듀스 함수를 실행했을 때의 결과를 출력해준다.

그 아래 부분에는 Filter Result라는 버튼이 있는데, 이 버튼을 통해서 맵&리듀스에 의해 생성된 결과를 필터링 할 수 있다. 도큐먼트 ID나 KEY의 범위등 지정해서 pagination등에 활용할 수 있다. 자세한 필터에 대한 내용은 향후에 설명하도록 한다.

 





뷰를 이용하여 다양한 기능 구현하기

이러한 뷰를 이용해서 카우치베이스는 다양한 데이터 조작이 가능한데, 대부분의 NoSQL은 키밸류 형태로 RDBMS에서 지원하는 Indexing, Grouping, Sorting 등 강력한 기능을 지원하지 않는 경우가 많다. 카우치베이스에서는 뷰를 이용해서 이러한 기능등을 구현할 수 가 있다.


Indexing 

RDBMS의 Index와 같은 개념으로, 도큐먼트 ID이외에 다른 필드로 검색이 가능하게 해주는 기능이다. NoSQL에서는 이를 Secondary Index라고도 부르는데, Secondary Index를 지원하는 다른 NoSQL의 경우, 제대로 성능이 나도록 설계되어 있는 경우도 있지만, Secondary Index를 기반으로 검색을 할 경우, 분산된 전체 노드를 FULL SCAN해서 (전체 목록을 뒤져서) 검색 결과를 한 노드로 합쳐서 리턴하는 형태로 구현되어 있는 경우가 있다. (Riak의 예전 Secondary Index의 구조) 이 경우, 전체 노드가 O(N)으로 전체 레코드를 검색해야 하기 때문에, 전체적인 성능 저하가 매우 심하다. 앞에서도 언급했지만, 카우치베이스는 이를 Incremental view의 개념을 사용해서, Secondary Index에 해당 하는 필드를 키로 잡은 새로운 물리적인 테이블을 내부적으로 만들기 때문에, Index를 이용한 검색도 타 NoSQL에 비해서 성능이 좋은 편에 속한다.


Extracting & Filtering

필터링은 SQL문장에서 select where라고 보면 된다. 조건에 맞는 특정한 도큐먼트만 select하는 것이 가능하다.

다음과 같은 도규먼트들이 버킷에 저장되어 있다고 할때

{

   "name": "yuna",

   "country": "us",

   "ssn": "140515-1234123",

   "sex": "female"

}

여기서 country="us" 인 것만을 쿼리하고, 전체 필드중 일부 필드(컬럼)만을 가지고 리턴하는 뷰를 만들려고 하면, 다음과 같은 맵 함수를 이용하면 된다.
function (doc, meta) {
  if(doc.country=="us") emit(doc.name,doc.country,doc.ssn);
}
emit에 오는 첫번째 필드가 KEY로 사용된다. 
단 뷰 함수에 의해서 필터링이 된 경우에는 물리적인 Index가 생기기 때문에, country를 Korea,Canada등과 같이 동적으로 변경하는 것이 불가능하다.
이런 동적인 필터링은 카우치베이스의 필터를 이용해서 가능한데, 동적으로 나라에 따라서 필터링을 하고 싶다면, 조건을 적용할 필드를 키로 리턴한 후, 키에 대한 필터링을 하면 되는데, 다음과 같이 맵 함수를 작성한 후에 뷰를 생성하고
function (doc, meta) {
  emit(doc.country,doc.name,doc.ssn);
}
아래와 같이 필터 조건에 key를 "us"로 지정하면 doc.country가 "us" 인 도큐먼트만 쿼리가 된다.
※ 문자열은 반드시 "" 을 사용해서 지정해야 한다.


Sorting
카우치베이스에서 소팅은 뷰의 키값을 기반으로 한다. 소팅의 기준으로 하고자하는 필드를 KEY로 잡으면, 뷰에서는 디폴트로 오름차순으로 키에 따라 정렬을 해준다. 내림 차순으로 정렬을 하기 위해서는 위의 필터에서 descending이라는 옵션을 체크 해주면 된다.

리듀스(Reduce)함수를 이용한 Grouping 연산
Grouping은 RDBMS의 group by와 유사한 기능으로 같은 country인 도큐먼트 수를 카운트하거나, 태어난 해별 사용자 수를 하는 것과 같은 그룹 단위의 연산을 할 수 있다.
먼저 Grouping의 개념을 사용하기 위해서는 Compound Key라는 개념을 이해해야 하는데, 카우치베이스의 Grouping 연산은 이 Compound Key를 기본으로 한다. Compound Key랑 뷰의 키를 [] (배열) 형태로 정의한 경우이다. 예를 들어 키를
["Country","생년","성별"] 과 같은 형태의 배열 형태로 정의하는 것이다. Grouping은 이 Compound Key의 Level 단위 (즉 배열의 첫번째 값으로만 그룹을 만들것인가? 아니면 첫번째,두번째 값을 포함해서 그룹으로 잡을 것인가) 로 처리한다.
실제 예제를 살펴보자. 다음과 같은 JSON 도큐먼트가 있을때,
{
   "name": "yuna",
   "country": "us",
   "ssn": "140515-1234123",
   "sex": "female"
}
앞에서 언급한 형태의 Compound Key를 만드는 함수는 다음과 같다, 
function (doc, meta) {
  var year = doc.ssn.substring(0,2);
  emit([doc.country,year,doc.sex],1);
}
이 맵함수를 이용하면 뷰는 다음과 같아진다.
["canada","69","male"] 1
["korea","75","male"] 1
["us","08","female"] 1
["us","14","female"] 1
["us","75","female"] 1
그러면 국가별로 사용자 수를 통계를 내려면, 리듀스 함수에 "_count" 라고 정의하고
필터에 group 옵션을 선택한후에, group level을 1로 지정한다.

이렇게 하면, Compound Key의 첫번째 필드 (country)를 기반으로 그룹핑을 하고, 리듀스 함수에서 이 그룹단위로 _count 연산을 수행한다.

카우치베이스에는 리듀스함수에서 사용할 수 있는 기본적인 함수를 미리 정의해놨는데, 아래와 같다.

  • _sum : 밸류값을 더한다. (밸류 타입이 Integer라야 함)
  • _count : 그룹별로 묶인 값들의 수를 카운트 한다.
  • _stats : 각종 그룹값을 계산해준다, 위에서 나온 sum뿐만 아니라, sum,count,min(최소값),max(최대값),sumsqr(Sum of square : 제곱합) 값을 출력해준다.
Pagination 
뷰에서 만들어진 데이타는 쿼리시에 pagination을 지원할 수 있다. 필터를 통해서, 뷰의 start/end key값을 정의하거나, start/end 도큐먼트ID를 지정하면 그 범위내의 도큐먼트만 쿼리할 수 있다. (위의 필터 설정 그림 참고) 콘솔에서는 나와 있지 않지만 필터에 추가로 limit라는 옵션을 주면, 최대한 읽어올 수 있는 도큐먼트 수를 정의할 수 있다.
예를 들어 뷰의 키로 1~100까지 100개의 도큐먼트가 있을때, start key=11,end key=50으로 하면 11~50까지의 50개의 레코드가 리턴된다. 여기에 limit=10을 추가하면 11~20까지의 레코드만 리턴되낟. start/end와 limit를 적절하게 사용하면 페이징 기능을 구현할 수 있다. limit를 설정하는 방법은 SDK를 이용하여 뷰를 호출하는 방법에서 알아보도록 한다.

다음번에는 SDK를 이용해서 뷰를 생성하고, 뷰에 대한 쿼리를 수행하는 방법에 대해서 알아보도록 하겠다.









저작자 표시
신고

Couchbase Server

#3. node.js를 이용하여 카우치베이스에 CRUD 구현하기

조대협 http://bcho.tistory.com


SDK를 이용한 프로그래밍


이제, 프로그래밍 언어를 이용해서 실제로 카우치베이스에 데이타를 저장해보자. 


카우치베이스에서 지원하는 데이터 타입


앞서 예제에서 카우치베이스 웹콘솔을 통해서 JSON 도큐먼트를 저장해봤다. 카우치베이스는 JSON 도큐먼트뿐만 아니라, 키-밸류 스토어 형식으로 일반 string(문자열), integer(숫자)도 저장할 수 있다. JSON 도큐먼트 이외의 데이터 형은, 콘솔에서는 테스트가 불가능하고, SDK를 이용해서 프로그램을 작성해서 테스트를 해야 한다.


SDK를 이용한 데이터 접근


카우치베이스의 데이타를 접근하기 위한 메서드들은 다음과 같다. 이해를 돕기 위해서 SQL 문장과 비교해놓은 테이블을 보면

(출처 : http://docs.couchbase.com/couchbase-devguide-2.5/index.html#couchbase-sdks-and-sql-commands)

SQL Command

Couchbase SDK Method

INSERT, to create.

set and add

SELECT, to retrieve/read data.

get, multiple-retrieves, and get-and-touch (get and update expiration).

UPDATE, to modify data.

set with a given key, or add with a new key, or replace with a key, or cas, also known as Check-and-Set. Used to update a value by providing the matching CAS value for the document. There are also methods for incrementing and decrementing numeric values, changing the expiration for a value, as well as pre-pending or appending to stored objects.

DELETE, to remove data.

delete, deletes information associated with a given key.

프로그래밍 언어에 따라 제공되는 SDK에 따라서 다소 차이는 있지만 대부분의 흐름은 다음과 같다.

1) 카우치베이스로 connection 연결

2) 카우치베이스 버킷을 명시하여 client를 생성

다음으로, SDK에서 제공되는 메서드를 이용해서, CRUD 연산을 아래와 같이 수행할 수 있다.


INSERT

  • Upsert : set (key,value) , key 에 해당하는 값을 value로 저장한다. 만약에 key에 이미 값이 저장되어 있으면, value로 업데이트 한다. (upsert)

  • Insert : add (key,value) , key에 해당하는 값을 value로 저장한다. 단, 이미 key에 대한 값이 존재하면 에러를 리턴한다. (insert)

SELECT

데이타를 읽어오는 SELECT는 매우 단순하다. get(key) 명령어를 사용한다.

  • Get : value:=get(key), 키에 해당하는 값을 리턴한다.

  • Multiple get : values[] = get(keys[]), 키들에 해당하는 값들을 리턴한다. 키 리스트를 배열 형태의 인자로 넘긴다.

  • Get & touch : 키에 해당하는 값을 리턴하고, 해당 키에 대한 값의 TTL을 초기 값으로 복구한다. 예를 들어 TTL이 30분인 값이 10분전에 저장되었을때, (현재의 TTL은 20이 남는다.) touch를 하게 되면 TTL 값이 다시 30으로 복귀된다. SDK에 따라 다소 메서드 정의가 다르지만, 일반적으로 get/multiple get시 옵션으로 새로운 TTL expiry time을 주는 방식으로, TTL 값을 복구시킬 수 있다.

UPDATE

  • Replace (key,value) : key에 해당하는 값을 value로 업데이트 한다. 만약에 key에 대한 값이 존재하지 않으면 에러를 리턴한다 (update).

  • Touch(key) : 해당 key 에 대한 TTL 값을 재 설정한다.

  • Check and Set (CAS) : Replace와 같은 업데이트 기능을 한다. 단, CAS 값을 같이 인자로 넘겨서 CAS값이 같을 경우에만 Replace를 하고 다를 경우에는 에러를 리턴한다.
    ※ CAS에 대해서는 뒤에서 다시 자세하게 설명한다.

  • Incr/Decr : 앞서도 잠깐 언급했지만, 카우치베이스에는 밸류를 저장할 때, JSON 도큐먼트뿐만 아니라 integer와 같은 숫자값도 저장이 가능하다. 숫자값을 저장했을 경우에는 incr,decr 명령을 이용하여 값을 더하거나 뺄 수 있다.

  • Append/prepend : 밸류가 JSON 도큐먼트나 integer 타입이 아닌, string 문자열로 저장되었을 경우에, append 명령어를 이용하여 문자열 뒤에 새로운 문자열을 붙이거나, prepend 명령어를 이용하여, 저장된 문자열 앞에 새로운 문자열을 붙일 수 있다.

DELETE

  • Remove(key) : 키에 해당하는 데이터를 삭제한다.

Lock 제어

  • Lock/UnLock : 명시적으로 해당 키에 해당하는 데이터에 Lock을 걸거나 풀 수 있다. Lock이 걸려 있을 경우에는 다른 클라이언트에 의해서 해당 데이터에 대해서 접근이 불가능하며, Lock을 풀때에는 Lock을 걸 때 리턴 받은 CAS 값을 가지고 Lock을 풀어야 한다.


db.lock('test-key', function(err, result) {

  if (err) throw err;


  // Do some work


  db.unlock('test-key', {cas: result.cas}, function(err, result) {

    if (err) throw err;


    console.log('Success!');

  });

});



참고 CAS(Check & Set)

CAS는 Check and Set의 약자로, 하나의 도큐먼트에는 CAS의 값이 설정이되어 있고, 도큐먼트의 값(VALUE)가 변경될 때 마다 이 CAS의 값도 변경된다. 이는 일관성을 유지하기 위함인데, 값이 {TOTAL:10}이라는 도큐먼트가 있다고 하자. 애플리케이션에서 이 값을 GET한후에 +1을 해서 다시 저장하는 시나리오가 있을때,


①     클라이언트 A가 GET을 하고+1을 한후에, 다시 SET으로 {TOTAL:11}을 저장하기 전에,

②     클라이언트 B가 GET으로 {TOTAL:10}의 값을 가지고 갔다고 하자.

③     클라이언트 A가 {TOTAL:11}을 저장한후에

④     클라이언트 B도 TOTAL+1을 해서 {TOTAL:11}을 저장하게 되면


위의 시나리오에서는 두개의 클라이언트 A,B가 +1씩 더해서 저장하는 시나리오이기 때문에 값이 12가 되어야 하지만 위와 같이 11이 되는 현상이 발생한다. 일관성이 깨지는 문제인데, 이러한 일관성 문제를 예방 위해서 보통 RDBMS의 경우 lock을 거는 방법을 사용하지만 카우치베이스와 같은 분산 DB의 경우에는 전체 분산 노드 간에 lock을 거는 것이 성능상 문제를 야기할 수 있기 때문에, CAS라는 필드를 사용한다.

위와 같은 경우에 {TOTAL:10}일 때 CAS값이 1이라고 가정하면, GET을 할 때 클라이언트는 {TOTAL:10} value 뿐만 아니라 CAS값 1을 같이 가져온다. 그리고 값을 다시 SET하려하 할 때, 서버에 저장된 도큐먼트의 CAS값과 SET을 하고자 하는 클라이언트가 가지고 있는 CAS 값이 일치해야 SET이 성공한다. 위의 경우 클라이언트 A,B 모두 GET시에는 CAS값을 1을 가지고 갔다고 했으면, 3에 의해서 해당 도큐먼트의 CAS값은 2(다른값)으로 변경이 되었을 것이고, 4에서 클라이언트 B가 이전 CAS값 1을 가지고 SET을 시도하면, 도큐먼트의 CAS값과 다르기 때문에 에러가 발생하게 된다.




Node.JS를 이용한 카우치 베이스 프로그래밍


그러면 Node.JS를 이용해서 카우치베이스의 데이터를 억세스 해보자.

Connection 연결 및 간단한 get/set

아래 코드는 간단하게 카우치베이스에서 Connection을 연결하고, 데이터를 set한 후에, get으로 읽어오는 부분이다.


 

var couchbase = require('couchbase');

 

var bucket = new couchbase.Connection({

    'bucket':'mybucket',

    'host':'127.0.0.1:8091'

},function(err){

    if(err){

        console.error('couchbase server connection error');

        throw err;

    }

})

 

json_document = {

    'name':'terry',

    'country':'korea',

    'role':'architect'

}

// set

bucket.set('mykey',json_document,function(err,result){

    if(err){

        console.error(err);

    }

    // get

    bucket.get('mykey',function(err,result){

        if(err){

            console.error(err);

        }else {

            console.log(result);

        }

        process.exit(0);

    });

});

 


var couchbase = require('couchbase');

 

var bucket = new couchbase.Connection({

    'bucket':'mybucket',

    'host':'127.0.0.1:8091'

},function(err){


카우치베이스 모듈을 Import한다. 만약에 카우치베이스 모듈이 설치되어 있지 않다면, “npm install couchbase” npm 명령을 이용해서 모듈을 먼저 설치하도록 하자. 카우치베이스 모듈은 C 라이브러리를 포함하고 있기 때문에, GCC나 비주얼 스튜디오와 같은 C 컴파일러가 환경에 설치되어 있어야 한다.

모듈을 import했으면, bucket으로의 연결을 만들어야 한다. Connection에서 bucket 필드에 연결하고자 하는 버킷명과, host 필드에는 연결하고자 하는 호스트명/포트를 명시한다. 이때 호스트명/포트는 array 형태로 정의할 수 있다. 만약에 연결하려는 호스트가 장애가 나서 연결이 되지 않을 경우 자동으로 array 내의 다른 호스트로 연결을 시도한다.

그리고 하나의 Connection을 연결하더라도 내부적으로 한 개가 아니라 여러 개의 Connection이 생기는 것을 확인할 수 있는데, Node.JS의 카우치베이스 SDK는 내부적으로 Connection Pooling 기능을 제공해서 여러 개의 Connection을 연후에, 매번 Connection을 새롭게 만들지 않고, 재사용하도록 하기 때문에 별도의 Connection에 대한 관리를 할필요가 없다.

json_document = {

    'name':'terry',

    'country':'korea',

    'role':'architect'

}

// set

bucket.set('mykey',json_document,function(err,result){

 


카우치베이스에 연결이 되었으면, 버킷에 set 메서드를 이용하여 데이터를 저장한다.메서드의 순서는 bucket.set(키,저장할 데이터,옵션,콜백함수(err,result){..}); 로 정의된다.

옵션 부분은 생략할 수 있다. 

옵션 부분에는 

  • cas : 위에서 설명된 Check and Set 값. 이 값이 이전의 CAS 값과 일치하지 않으면 set 이 실패한다.

  • expiry : TTL값으로, 이 시간이 지나면 자동으로 데이터가 삭제 된다.

  • persist_to integer : integer에 정의된 노드의 숫자만큼 데이터가 복제된후에 쓰기 작업을 끝낸다. 예를 들어 10개의 노드가 있는 카우치베이스 클러스터에서 이 값이 2면, 마스터 노드를 포함하여, 2개의 노드에 쓰기가 완료되면 set 작업이 완료된 것으로 리턴한다.

  • replicate_to integer  : integer에 정의된 원격 노드 (다른 클러스터) 숫자 만큼 복제가 완료되면 set 작업이 완료된것으로 리턴한다.

bucket.get('mykey',function(err,result){

다음으로 set으로 입력한 값을 get을 이용하여 조회 한다. 메서드의 순서는 

bucket.get(키,옵션,콜백함수(err,result){…});

순서로 정의 된다. 키에 대한 밸류값을 콜백함수의 “result”변수를 통해서 리턴한다.

옵션으로는

  • expiry integer : 값을 정할 수 있는데, 이 값을 지정하면 TTL 값이 이 값으로 다시 세팅된다. 앞에서 설명한 Get & Touch를 구현할 때 사용할 수 있다.

간단하게 set/get에 대한 예제를 살펴보았다. Node.JS의 카우치베이스 SDK는 단일 키에 대해서 set/get 뿐만 아니라 여러키에 대한 다중 set/get을 함께 지원한다.

setMulti(kv, options, callback), getMulti(kv, options, callback)

를 이용하면, 동시에 여러 키에 대한 업데이트나, 여러키에 대한 데이터 SELECT를 수행할 수 있다.

작성한 예제를 수행해보면 다음과 같은 결과를 얻을 수 있다.



 

도큐먼트 삭제


도큐먼트에 대한 삭제는 remove(키,옵션,콜백함수(err,result){..}); 를 사용해서 삭제하면된다.

적용할 수 있는 옵션은 set에서 사용한 cas,persist_to,replicate_to를 동일하게 사용할 수 있다.


Integer값과, String 값에 대한 처리


앞에도 설명하였지만 카우치베이스에 값은 JSON 도큐먼트뿐만 아니라, integer, string값도 저장할 수 있고, 이 값에 대해서는 incr/decr과 같은 숫자 전용 메서드와 append/prepend라는 문자열 전용 메서드를 지원한다.

다음은 String 값을 ‘ hello ‘라는 문자열로 세팅한후 append 를 이용해서 문자열 뒤에 ‘ node.js ‘ 라는 문자열을 추가하고 prepend 명령을 이용해 문자열 앞에 ‘ im couchbase ‘ 라는 문자열을 추가한 후에, get 명령을 이용하여 문자열을 가져와서 출력하는 예제이다


 

var couchbase = require('couchbase');

 

var bucket = new couchbase.Connection({

    'bucket':'mybucket',

    'host':'127.0.0.1:8091'

},function(err){

    if(err){

        console.error('couchbase server connection error');

        throw err;

    }

})

 

// set

bucket.set('string',' hello ',function(err,result){

    if(err){

        console.error(err);

    }

    // get

    bucket.get('string',function(err,result){

        if(err){

            console.error(err);

        }else {

            console.log(result);

        }

        bucket.append('string',' node.js',function(err,result){

            if(err){

                console.error(err);

            }else{

                console.log(result);

            }

            bucket.prepend('string',' im couchbase' ,function(err,result) {

                if (err) {

                    console.error(err);

                } else {

                    console.log(result);

                }

                bucket.get('string', function (err, result) {

                    if (err) {

                        console.error(err);

                    } else {

                        console.log(result);

                    }

                });

            });

        });

    });

});

 


위의 예제를 수행하면 결과는 다음과 같다.


 

prepend와 append도 set과 마찬가지로 옵션을 줄 수 있는데, 적용할 수 있는 옵션은 expiry,cas,persist_to,replicate_to 등을 적용할 수 있다.

다음은 integer 값을 저장하고, incr/decr을 이용하여 저장된 값을 증가/삭제하는 예제이다.

/**

 * Created by bw.cho on 2014-07-07.

 */

var couchbase = require('couchbase');

 

var bucket = new couchbase.Connection({

    'bucket':'mybucket',

    'host':'127.0.0.1:8091'

},function(err){

    if(err){

        console.error('couchbase server connection error');

        throw err;

    }

})

 

// set

bucket.set('number',100,function(err,result){

//bucket.incr('number',{initial:100},function(err,result){

    if(err){

        console.error(err);

    }

    // get

    bucket.get('number',function(err,result){

        if(err){

            console.error(err);

        }else {

            console.log(result);

        }

        bucket.incr('number',{offset:10},function(err,result){

            if(err){

                console.error(err);

            }else{

                console.log(result);

            }

            bucket.incr('number',{offset:-1},function(err,result) {

                if (err) {

                    console.error(err);

                } else {

                    console.log(result);

                }

                bucket.get('number', function (err, result) {

                    if (err) {

                        console.error(err);

                    } else {

                        console.log(result);

                    }

                });

            });

        });

    });

});

위의 코드는 먼저 set 명령어를 사용하여 ‘number’라는 키에 대한 값을 숫자 100으로 세팅한후에, 

bucket.set('number',100,function(err,result){

다음으로, incr 명령을 이용해서 이 값을 증가 시킨다. 이때 아래와 같이 옵션에 offset이라는 값을 지정할 수 있는데, off set은 증분값이다. off set 값 만큼 더해지는데, 아래의 경우 10을 설정했기 때문에, +10을 해서 값이 110이된다.

bucket.incr('number',{offset:10},function(err,result){

옵션에서 offset을 설정하지 않으면, 디폴트로 +1이 더해진다.

또는 아래 처럼 offset을 -1과 같이 마이너스 값을 사용하게 되면 그 값을 빼진다.

bucket.incr('number',{offset:-1},function(err,result) {

다음은 위의 소스코드에 대한 실행 결과이다.

 

하나 주의 깊게 봐야 할 것은

bucket.incr('number',{initial:100},function(err,result){

과 같이 incr에서 initial 값을 설정할 수 있는데, 이는 마치 upsert와 같이 동작한다. 만약에 해당 키값으로 정의된 값이 있다면, 기존의 값을 그대로 사용하고 만약에 해당 키로 설정된 값이 없다면 이 initial 값으로 set를 하게 된다.

decr 명령어도 증가가 아니라 값을 감소 시킨다는 점에서 사용법은 동일하다.


저작자 표시
신고

Couchbase Server

#2 기본 개념 잡기

조대협 http://bcho.tistory.com

개념 잡기


카우치베이스 서버 설치가 끝났으면 기본적인 개념을 잡아보도록 하자.


Document 기반의 Key-Value 스토어


카우치 베이스느 키, 밸류 스토어이다 하나의 유니크(Unique)한 키에, 값을 저장하는 방식이다. 저장 되는 값은 JSON 도큐먼트가 저장된다. 키는 최대 250 바이트, (밸류)의 경우에는 카우치베이스 버킷의 경우 20MB, Memcached 방식의 버킷의 경우 1MB 까지 저장이 가능하다.

저장할때, 키와 값뿐만 아니라 메타데이타가 같이 저장되는데, 메타 데이타에는 CAS,TTL,Flag 3가지가 저장된다.

저장할때, 키와 값뿐만 아니라 메타데이타가 같이 저장되는데, 메타 데이타에는 CAS,TTL,Flag 값 3가지가 저장된다.

CAS는 데이타에 대한 일종의 타임 스탬프와 같은 개념으로, 여러 클라이언트가 같이 데이타를 ACCESS 했을때, 일관성(Consistent) 문제가 생기는 것을 해결해줄 수 있다. (자세한 내용은 나중에 설명한다.)

TTL 은 Time To Live 로, 데이타의 유효 시간을 정의한다. TTL을 정의해놓은 데이타는 TTL 시간이 지나면 자동으로 삭제 된다.

FLAG는 카우치베이스 클라이언트에서 사용하는 메타데이타 이다. 

이러한 메타데이타는 하나의 메타데이타 (CAS,TTL,Flag)는  60바이트의 메모리를 차지하게 된다.

카우치베이스 server는 모든 Key와 메타데이타를 메모리에 유지하기 때문에 데이터 모델링 또는 용량을 설계할때, 이 부분을 고려해서 RAM의 사이즈를 결정해야 한다.


버킷(Bucket)


버킷은 일종의 RDBMS의 데이타베이스 같은 공간이다. JSON 도큐먼트들은 이 버킷에 저장된다.

각각의 버킷은 고유의 속성 값을 가지고 있다. 버킷별 사용할 수 있는 메모리양, 옵션으로 버킷별로 접근할 수 있는 TCP 포트를 지정하거나, 접근 비밀번호를 지정할 수 있으며, 버킷에 들어가는 데이타에 대한 복제본의 수등을 정의할 수 있다.

하나의 클러스터에서 버킷은 최대 128개까지 생성할 수 있으나, 보통 성능상 10개를 권장한다.

http://docs.couchbase.com/couchbase-manual-2.0/#setting-maximum-buckets-for-clusters


뷰(View)


카우치베이스의 강력한 기능중의 하나인데, 이 뷰를 이용해서 RDBMS에서 제공되는 Indexing, grouping, sorting등을 가능하게 한다. 이 뷰는 데이타베이스 뷰와 유사한 개념을 갖는데, 카우치베이스의 뷰는 인크리멘탈 뷰 (Incremental view)라는 컨셉을 가지고 있다.

예를 들어 설명해보자. 사용자 정보를 저장하는 버킷에서, 사용자 정보를 저장하는 JSON 도큐먼트 안에 SSN(Social Security Number)라는 이름으로 주민등록 번호를 저장하는 필드가 있고, 이 주민등록 번호 필드에서 80년생 이하만 저장하는 뷰를 만든다고 하자.

데이타가 버킷에 저장될 때마다, 생성된 뷰에 같이 저장되는데, 이때, 뷰코드(View Code)라는 로직을 통해서 뷰에 저장된다. 뷰코드는 자바스크립트로 작성된 코드이다. 뷰코드에서 주민등록 번호가 80년생 이하일 경우에만 뷰에 저장하도록 정의한다.

 


결과적으로 데이타를 저장하거나 업데이트할때, 이 뷰코드가 매번 수행되게 되고 (마치 RDBMS의 트리거 처럼), 뷰코드에 정의된 알고리즘에 따라서 뷰에 데이타를 업데이트하게 된다.

이렇게 데이타가 저장/업데이트될때 마다 뷰를 증분적(Incremental)하게 업데이트 하기 때문에, 인크리멘탈 뷰라고 하며, 실제로 저장된 데이타가 많다고 하더라도 뷰에는 데이타가 업데이트 될때 하나만 추가/수정 되기 때문에 실제로 카우치베이스가 받는 로드는 그리 크지 않기 때문에, Indexing, grouping, sorting등에 사용한다 하더라도 성능상에 큰 문제를 가지지 않고 사용할 수 있는 것이다.


카우치베이스 시작하기


대략적인 개념을 잡았으면, 이제 카우치베이스를 직접 사용해보도록 하자. 


버킷 생성하기


버킷을 생성하기 위해서는 카우치베이스 웹콘솔에서 상단 “Data Buckets”를 선택한후 “Create New Data Bucket”을 선택한다.

 


버킷 생성을 선택하면 아래와 같이 버킷 생성 창이 나오는데, 버킷 이름을 “mybucket”이라고  지정하고,  개발 테스트용으로만 사용할 것이기 때문에, 이 버킷에서 사용할 메모리를 최소 사이즈인 100메가로 설정한후 버킷을 생성한다.

 



데이타 핸들링


버킷이 생성되었으면, 해당 버킷에 직접 데이타를 저장,조회,수정,삭제를 해보도록 하자.

앞에서 생성한 버킷의 우측 부분을 보면 “Documents”라는 버튼이 나온다. 이 버튼을 누르면, 현재 저장되어 있는 도큐먼트들을 보거나 또는 생성,수정,삭제 등이 가능하다.

“Create Document” 버튼을 누른후, 

Document ID에 “user0001”이라고 입력한다.

그리고 아래 그림과 같이 JSON 도큐먼트를 입력하고 Save 버튼을 누른다.


 

이때 주의할점은 카우치베이스에서 JSON 도큐먼트를 정의할때, 문자열은 “로 감싸야 한다. 일반 자바스크립트처럼 ‘로 감쌀 경우 에러가 나온다.

 


조회는 위의 보이는 Documents 메뉴창에서 Lookup Id를 선택하고, 도큐먼트 ID를 넣으면 해당 도큐먼트를 조회할 수 있고, 위의 도큐먼트 좌측에 보이는 “Edit Document”와 “Delete” 버튼을 이용하면, 수정 및 삭제를 할 수 있다.



저작자 표시
신고

Couchbase Server

#1 소개 및 설치

조대협 http://bcho.tistory.com


근래에 여러 NoSQL이 소개되었지만 그중에서 좋은 솔루션인데도 불구하고 그다지 국내에서는 널리 알려지지 않은 카우치베이스에 대해서 소개하고자한다. 모바일 게임중에 유명한 쿠키런의 경우 카우치베이스를 백엔드로 사용하고 있는데, 안정성이나 성능등이 매우 뛰어나고, 사용하기 또한 매우 쉽다. 오늘은 고성능 NoSQL 서버인 카우치베이스(CouchBase) 에 대해서 소개하고자 한다.


소개


예전에 메모리 캐쉬 솔루션인 memcached에 디스크 persistence 기능을 추가하여 membase라는 솔루션이 있었는데, 이 제품에 Apache의 카우치디비(CouchDB)를 기반으로 새롭게 만든 솔루션이 카우치베이스 Server 라는 NoSQL 솔루션이다.

카우치베이스는 mongoDB나, Riak과 같이 JSON document를 직접 저장할 수 있는 Document DB 형태를 가지며, NoSQL의 분산 이론인 CAP theorem에서 CP (Consistency & Partition tolerance) 의 부분에 해당하여 데이타에 대한 일관성과, 노드간의 네트워크 장애시에도 서비스를 제공할 수 있다. 근래에 들어서 600억원의 투자를 유치하는 등 가치를 인정 받고 있는데, mongoDB나 Cassandra에 가려서 그다지 주목을 받지 못하는 것 같아서, 이번 글을 통해서 소개하고자한다.


특장점


카우치 베이스는 다른 NoSQL에 비해서 다음과 같은 추가적인 특징을 더 가지고 있다.


Memcached 기반의 Level 2 캐쉬를 내장하여 빠름

카우치베이스는 앞에서도 설명하였듯이 membase를 기반으로 하였기 때문에, memcached를 자체적으로 Level 2 캐쉬로 사용하고 있다. 즉 자체적으로 메모리 캐쉬 기능을 가지고 있기 때문에 성능이 대단히 빠르다. 이번에 카우치베이스 社에서 발표한 자료에 따르면 mongoDB대비 약 6배 이상의 성능을 낸다고 한다. 


(http://info.couchbase.com/2014-Benchmark-Showdown-Results-LP.html)


모바일 디바이스와 Sync

카우치베이스 뿐만 아니라, 카우치디비 계열 DB들은 iPhone이나 Android와 같은 모바일 디바이스에 탑재 할 수 있고, 서버에 설치되 카우치디비 계열들과 Sync가 가능하다. 카우치베이스도 역시, 카우치디비 계열이기 때문에, 모바일 디바이스에 탑재할 수 있고, 서버와 Sync할 수 가 있다.


데이타 센터간 복제 가능

카우치베이스는 XACR(Cross Data Center Replication)이라는 기능을 이용하여, 물리적으로 떨어진 데이타 센터간에 데이타 복제가 가능하다.


Indexing, Grouping ,Ordering,Join 가능

아주 중요한 특징중의 하나인데, 대부분의 NoSQL은 Key/Value Store 형식으로, 개별 필드에 대한 Indexing이나, 필드별로 group by 를 해서 sum,count등을 하는 기능이나, 특정 필드별로 Sorting이 불가능하다. Indexing을 지원하는 경우도 있기는 하지만, 내부적으로 성능상 문제가 있는 경우가 많은데, 카우치베이스의 경우 이러한 성능상 문제를 해결 하면서도 RDBMS들이 지원하는 index, grouping, ordering 기능을 지원할 수 있다. 


확장이 쉬움

보통 분산 구조의 NoSQL의 경우, 노드를 확장하거나 특정 노드가 장애가 났을때의 처리가 어려운데, 카우치베이스는 장애가 손쉽게 장애 처리를 하고,새로운 노드를 추가할때 도 매우 쉽게 노드 추가가 가능하다. 이러한 장점은 운영 관점에서 큰 이점이 된다.


Built in 관리 도구 제공

마지막으로 카우치베이스는 웹 기반의 GUI 관리 도구를 기본으로 제공한다. 많은 NoSQL들이 별도의 관리, 모니터링 도구를 지원하지 않는데 반하여, 기본적으로 강력한 관리 도구를 제공하는 것은 큰 장점이 될 수 있다.


Memcached 프로토콜 지원

캐쉬 솔루션으로 유명한 Memcached 프로토콜을 그대로 지원하기 때문에, 기존의 Memcached 클라이언트를 그대로 사용할 수 있고, 기존에 사용하던 Memcached 인프라를 그대로 대체 할 수 있다.


스키마가 없는 유연한 저장 구조 (Scheme-less)

 스키마가 없는 구조는 카우치베이스뿐만 아니라 대부분의 NoSQL이 갖는 공통적인 특성이다. 스키마가 없기 때문에 하나의 테이블에 컬럼 형식이 다른 데이타를 넣을 수 있다. 즉 하나의 데이타 버켓에 데이타 구조가 다른 JSON 문서들을 넣을 수 있다는 이야기이다.

데이타 타입이 다름에도 불구하고, 공통되는 필드에 대해서, Indexing, grouping 등을 제공할 수 있다. JSON 도큐먼트에, county 라는 앨리먼트가 있는 도큐먼트들을 대상으로 grouping등을 할 수 있다는 이야기이다.

다양한 클라이언트 플랫폼 지원

자바,닷넷,PHP,루비,C,파이썬,node.js 등 다양한 클라이언트 라이브러리를 제공한다. 클라이언트 SDK는 http://www.couchbase.com/communities/all-client-libraries 에서 다운로드 받을 수 있다.


설치하기


카우치베이스를 설치하기 위해서는 www.couchbase.com에서 카우치베이스를 맞는 OS 플랫폼에 따라서 다운로드 받으면 된다. Enterprise Edition과 Community Edition이 있는데, Enterprise Edition은 별도의 상용 라이센스를 구입해야 하며 기술 지원등을 받을 수 있다. Community Edition은 무료로 개발이나 운영 환경에 사용할 수 있으나, 기술 지원등을 받을 수 없고,  Enterprise Edition에 비해서 버전이 낮다.

※ 참고로, 상용과 오픈소스 라이센스 정책을 함께 지원하는 솔루션의 경우에는 버전업이 되면서 라이센스 정책이 갑자기 바뀌는 경우가 많으니, 오픈소스의 경우 다운로드 전에 반드시 라이센스 정책을 확인하기를 바란다. 이 글을 쓰는 현재 Community Edition의 라이센스 정책 기준은 2.2.0을 기준으로 한다. 

여기서는 윈도우즈 환경을 기준으로 설명을 한다. 사이트에서 카우치베이스 server 를 다운로드 받고 실행을 하면 자동으로 설치 위자드가 실행되고, 설치가 진행된다.

 


설치가 다 끝나면, 자동으로 웹페이지가 열리면서, 카우치베이스에 대한 셋업이 시작된다.

 


설정 셋업을 시작하면 기본적인 서버 설정에 대해서 물어보는데

 


데이타 파일을 저장하는 경로와, 호스트명등을 물어본다.그리고 새로운 클러스터를 시작할지, 아니면 기존의 클러스터에 조인할지를 물어보는데, 여기서는 개인 개발 환경을 설정하는 것이기 때문에, “Start a new cluster”로 설정한다. 이때, 카우치베이스가 사용할 메모리 용량을 지정해야 한다. 개인 개발환경이기 때문에, 1G정도로 설정하자. 실제 운영환경에서는 최대한 크게 잡아줘야 한다. 카우치베이스에 저장되는 키와 데이타에 대한 메타 데이타는 모두 메모리로 로딩되기 때문에, 메모리 용량이 충분하지 않으면 제대로된 성능을 발휘할 수 없다.

인스톨이 완료된후에, 카우치베이스 웹 콘솔을 열어 보면, 다음과 같이 인스톨된 카우치베이스 서버의 상태를 볼 수 있다. 

 




저작자 표시
신고

빠르게 훝어보는 node.js

#5 - Express 2/2

조대협 (http://bcho.tistory.com

File upload download 처리

Express는 파일 업로드 기능을 제공한다. Express 의 경우, 파일을 tmp directory에 업로드한후, 업로드가 끝나면 이벤트를 주는 형태이다. 그래서, 파일 업로드가 끝나면 파일 저장 디렉토리로 옮겨 줘야 한다. 그러면 간단하게 코드를 살펴보자.

express에서 업로드되는 file stream multipart 형태로 업로드가 된다. multi part request stream을 인식하려면, express세팅에 bodyParser 미들웨어를 사용함을 명시해줘야 한다.

var app = express();

app.use(express.bodyParser());

http://expressjs.com/3x/api.html#req.files

다른 미들웨어도 이 bodyParser() 미들웨어를 사용하기 때문에, 다른 미들웨어 선언전에 앞쪽에 선언을 해줘야 한다.

다음으로 file 업로드를 해줄 HTML 파일을 정의하자

<form action="/upload" method="post" enctype="multipart/form-data">

    <input type="file" name="myfile" />

    <input type="submit" name="upload" />

</form>

HTTP Post 형태로 multipart 형태로 데이터를 보내며, 파일은 “myfile”이라는 폼 이름으로 전송된다. 이를 받는 코드는 아래와 같다.

var fs = require('fs');

 

exports.upload = function(req, res){

    fs.readFile(req.files.myfile.path,function(error,data){

        var destination = __dirname + '\\..\\uploaded\\'+ req.files.myfile.name;

        fs.writeFile(destination,data,function(error){

            if(error){

                console.log(error);

                throw error;

            }else{

                res.redirect('back');

            }

        });

    });

 

};

파일은 req.files.{폼이름}.path에 업로드 된다. 위의 예제는 파일 컴포넌트의 폼명을 “myfile”로 했기 때문에 파일의 경로는 req.files.myfile.path가 되낟. 다음 fs.readFile을 이용해서 업로드된 파일이 tmp 디렉토리에 모두 업로드가 되면 destination 디렉토리로 복사해주는 예제이다.

tmp 디렉토리의 경우 bodyParser 미들웨어 적용시 적용할 수 있다.

조금 더 효율적인 코드를 구성해보면, 파일을 tmp 디렉토리에 써지지는 것을 바로 읽어서 write destination에 쓸 수 있도록 Stream을 이용할 수 있다. tmp에서 읽어서 destination 디렉토리에 쓰는 것은 위의 예제와 똑같지만, 나중에 설명하겠지만 Stream을 사용하면, 파일을 읽을 때, 쓸 수 있는 만큼만 (버퍼크기만큼만) 읽은 후 쓰기 때문에, 훨씬 효율적인 IO를 할 수 있다.

exports.uploadstream = function(req, res){

    var destination = __dirname + '\\..\\uploaded\\'+ req.files.myfile.name;

    var ws =  fs.createWriteStream(destination);

    fs.createReadStream(req.files.myfile.path).pipe(ws);

    res.redirect('back');

};

아쉬운 점은 Express의 특성상 바로 destination 디렉토리에 write하는 것은 안되고, tmp 디렉토리를 거쳐서 write해야 한다.


JSON REST API

Express JSON 기반의 REST API 구현도 지원하는데, Spring/Java를 알고 있는 개발자라면, 아주 짜증이 날(?) 정도로 express를 이용한 REST API 구현은 매우 간단하다. 설명은 생략하고 먼저 코드부터 보자

app.use(express.json());

app.post('/rest',function(request,response){

    request.accepts('application/json');

 

    // input message handling

    json = request.body;

    console.log('name is :'+json.name);

    console.log('address is :'+json.address);

 

    // output message

    response.json({result:'success'});

 

});

위의 코드는

{

   "name":"Terry",

   "address":"seoul"

}

와 같은 JSON 메시지를 받은 후에, 내용을 파싱하고, { ‘result’:’success’} 라는 리턴을 보내는 코드이다. 먼저 exress.json 미들웨어를 적용하고, request.accept application/json 타입으로 해서 JSON request를 받음을 명시한다.

다음으로는 request.body.{JSON 필드명} 을 사용하면 된다. 위의 예의 경우 JSON 필드명이 name address이기 때문에 그 값에 대한 경로는 body.name body.address가 된다.

Response를 보낼 때에는 위의 예제와 같이 response.json({key:value,…}) 형태로 지정하면 된다. 만약에 HTTP response code를 보내고 싶으면 response,json(HTTP_CODE,{key:value…}) 형태로 지정한다.

예를 들어 response.json(500,{error:’error message’});  형태로 지정할 수 있다.

또한 response.jsonp 메서드를 이용해서 JSONP 를 지원하는데, JSONP는 간단하게 말하면 Cross Site Scripting을 지원할 수 있는 방법이다. 자세한 설명은

http://beebole.com/blog/general/sandbox-your-cross-domain-jsonp-to-improve-mashup-security/

를 참고하기 바란다.


Connect Module pipe line

지금까지 Express의 기능에 대해서 간략하게 살펴보았는데, 에러 처리 방식에 앞서서 Express의 근간이 되는 Connect framework에 대해서 짚고 넘어가고자 한다.

Connect Framework Javascript 를 기반으로 한 웹/서버 개발용 프레임웍이다. Javascript 기반의 서버를 만들기 위해서, 개발되었으며, Ruby Rack Framework을 기반으로 하였다.

Connect에서는 Middleware라는 개념을 사용하는데, reusable한 컴포넌트를 middleware라고 한다. Request, response 파이프라인상에 middle ware를 넣어서 기능을 추가 및 처리 하는 개념인데, Java Servlet Filter Servlet Chaining과 같은 개념과 유사하다고 보면 된다. 아래 그림과 같이 request가 들어와서 서버에서 처리되고 reponse로 나가는 형태라고 할 때,



아래 그림과 같이 처리 과정에 middleware를 추가하여 기능을 처리하도록 할 수 있다.



우리가 지금까지 express를 사용하면서 app.use라고 했던것들이 middleware 모듈을 추가하는 기능이었다.

app.use(express.logger('dev'));

app.use(express.json());

app.use(express.urlencoded());

app.use(express.methodOverride());

app.use(express.cookieParser('your secret here'));

app.use(express.session());

app.use(app.router);

app.use(express.static(path.join(__dirname, 'public')));

 

app.use(function(req,res,next){

   console.log('custom log :'+req.path) ;

   next();

});

 

app.post('/upload', upload.fileupload);

위의 코드를 분석해 보면



와 같은 순서로 middleware가 적용된 것이다.

static 파일의 경우 위에서부터 순차적으로 logger 모듈부터 적용이 되다가 express.static 모듈에서 적용후에, static file response한 다음에 바로 리턴이 된다.

static 파일이 아닌 경우는 모두 아래 함수를 수행하게 되는데

app.use(function(req,res,next){

   console.log('custom log :'+req.path) ;

   next();

});

Middleware로 넘어오는 parameter HTTP request,response 뿐만 아니라 next라는 함수 포인터를 넘겨주는데, middleware를 수행한 다음에 다음 middleware를 실행하기 위한 포인터이다. 위의 예에서는 콘솔에서 로그를 출력한 후에, next()를 호출하여 다음 미들웨어를 호출하도록 하였다.

HTTP/POST /upload request의 경우에는 app.post('/upload', upload.fileupload); 미들웨어에 의해서 처리된다.

이렇게 middleware들은 순차에 의한 chaining 개념을 가지고 있기 때문에, middleware use를 이용해서 불러드릴 경우 순서가 매우 중요함을 알 수 있다.


Error Handling

다음으로 Express에서 에러처리에 대해서 알아보자 Express에서 별도의 에러처리를 하지 않으면, 404의 경우 한줄로 없는 페이지라는 메시지가 나오거나 500 에러의 경우 아래와 같이 에러스택이 바로 표시되어 버린다. (보안상의 이유라도 이런식으로 내부 스택이 나오는 것은 좋지 않다.)



그러면 어떻게 에러 처리를 하는지 알아보도록 하자. 먼저 코드를 보면

app.use(express.static(path.join(__dirname, 'public')));

 

app.get('/error',function(req,res,next){

   // this will make a error

    var err = new Error('custom error');

    err.type = 'my error';

    next(err);

 

});

app.use(function(err,req,res,next){

   console.log(err.type);

   console.log(err.stack);

 

   res.format({

       html: function(){

            res.send(500,'internal server error');

        },

       json:function(){

           res.send(500,{code:err.type,description:'error detail'});

       }

    });

 

});

app.use(function(req,res){

    res.send(404,"I cannot find the page");

} );

 

http.createServer(app).listen(app.get('port'), function(){

  console.log('Express server listening on port ' + app.get('port'));

});

 

먼저 404 에러의 경우 앞에 Connect에서 살펴본 middlewarechaining 개념을 이용하면 된다. 간단하게 다른 middleware에 의해서 처리되지 않은 URL 404로 처리하면 된다. 그래서 middleware를 불러드리는 맨 마지막에 404 에러 처리 로직을 구현하였다.

app.use(function(req,res){

    res.send(404,"I cannot find the page");

} );

 

다음은 500이나 503 같은 에러 처리 방식을 알아보자, 인위적으로 에러를 만들기 위해서 HTTP GET/error 시에 인위적으로 에러를 발생시키는 코드를 구현하였다.

app.get('/error',function(req,res,next){

   // this will make a error

    var err = new Error('custom error');

    err.type = 'my error';

    next(err);

 

});

 

여기서 주의 할점은 node.js의 일반적인 에러 처리 방식 처럼 throw를 통해서 에러를 던지는 것이 아니라 next()를 통해서 에러 메시지를 다음 middleware로 넘기는 형태를 사용한다.next 호출시 인자에 error가 있을 경우 미리 정의된 error handler를 부르게 된다.error handler는 다른 middleware와는 총 4개 인자를 받으며, 다르게 첫번째 인자가 err로 정의 된다.

app.use(function(err,req,res,next){

가 에러 핸들러를 구현한것이며, res.format을 이용하여, 브라우져가 선호하는 포맷 (content/accept에 정의된) 포맷으로 html이나 json으로 메시지를 보내주도록 구현하였다. 예제라서 간단하게 구현했지만, err.type에 에러가 발생할 때 타입을 정해놓으면 error handler에서 이 err.type에 따른 다양한 에러 핸들링 로직을 구현할 수 있고 (예를 들어 Nagios 기반의 모니터링 시스템에 이벤트를 날리거나, IT Admin에게 SMS 메시지를 보내는 것등), 500 error의 경우에는 template을 미리 만들어놓고 잘 디자인된 에러페이지를 출력할 수 있다.

이 밖에도 HTTP Basic Auth를 이용한 인증, 압축 모듈, CSRF (Cross Site Request Forgery) 등을 방어 하는 모듈등 다양한 기능을 지원하는 API 및 모듈이 있다. 자세한 내용은 http://expressjs.com/api.html 을 참고하기 바란다.

저작자 표시
신고

빠르게 훝어보는 node.js

#2 - 설치와 개발환경 구축

조대협 (http://bcho.tistory.com

Node.js 설치하고 개발환경 설정하기

다운로드 하기

http://www.nodejs.org 페이지에서 install 버튼을 누르면 OS에 맞는 인스톨러를 다운로드 해준다.



다음으로 installer를 실행한다.



설치가 되었으면, 설치된 디렉토리를 PATH에 추가한다.

set PATH=%PATH%;c:\dev\was\nodejs

자아 이제 node.js가 설치되었는지 확인하자. node.js는 대화형 cli를 제공한다.



설치를 끝냈으면 이제 간단한 웹서버를 만들어보자

var http = require('http');

http.createServer(function(request, response) {

response.writeHead(200);

response.write("Hello, this is dog.");

response.end();

}).listen(3000);

console.log('Listening on port 3000...');

이 코드를 app.js로 저장한다.

다음으로 다음과 같이 해당 파일을 실행한다.



이제 웹브라우져로 확인해보면 다음과 같이 메세지가 출력되는 것을 확인할 수 있다.



다음으로 개발환경을 설정해보자, 개발툴은 eclipse 등 여러가지 툴이 있지만 개인적으로 IntelliJ를 만든 JetBrain社의 WebStorm (http://www.jetbrains.com/webstorm/) 을 추천한다. 유료이긴 하지만, 30 Trial로 사용할 수 있고, 가격은 개인용 버전의 경우 49$이다. (좋은 소프트웨어는 구매하자)

자바스크립트와 웹개발에 최적화 되어 있고, 빠르고 매우 직관적이다. 그리고 Bootstrap과 같은 자바스크립트 프로젝트나, mocha와 같은 자바스크립트 테스트 프레임웍들도 잘 지원한다.REST API를 테스트하기 위한 기능이나 디버깅 기능도 상당히 직관적이라서 어렵지 않게 사용이 가능하다.

  오픈소스를 사용하고 있거나 강의에서 사용할 경우에는 무료 라이센스를 신청할 수 있다.

 



Figure 1. JetBrain社의 자바스크립트, node.js 개발환경인 WebStorm 7


#1 – node.js의 소개와 내부 구조 http://bcho.tistory.com/881

#2 - 설치와 개발환경 구축 http://bcho.tistory.com/884

#3 - Event,Module,NPM  http://bcho.tistory.com/885

#4 - 웹 개발 프레임웍 Express 1/2 - http://bcho.tistory.com/887



저작자 표시
신고

maven nexus 설치

ALM/Build Automation (빌드 자동화) | 2013.09.05 23:47 | Posted by 조대협

Nexus 설치 및 Maven 연동

조대협

Nexus maven에서 사용할 수 있는 가장 널리 사용되는 무료 repository 중의 하나이다. www.sonatype.com 에서 다운로드 받아서 설치할 수 있다.

Local nexus를 설치하게 되면, 외부로 부터 dependency를 끌어 오는 수고를 덜고, local nexus proxy (cache)로 사용함으로써 빠르게 라이브러리들을 끌어 올 수 도 있고, 반대로 개발팀내에서 사용하는 공통 라이브러리들을 local nexus에 배포해서 팀간에 공유할 수 있다.

또한 사용자 계정 지정을 통해서 repository에 대한 접근 정책을 정의할 수 도 있다.

Nexus repository의 용도와 목적에 따라서 몇 가지로 나눌 수 있는데, 대표적으로 다음과 같은 종류 들이 있다.

   Snapshots : 빌드등 수시로 릴리즈 되는 바이너리를 배포 하는 장소

   Releases : 정식 릴리즈를 통해서 배포되는 바이너리를 저장하는 저장소

   3rd party : 벤더등에서 배포하는 (Oracle,IBM) 바이너리를 저장해놓는 장소로 특정 솔루션등을 사용할때, 딸려 오는 라이브러리등을 여기에 놓고 사용한다

   Proxy Repository : 원격에 원본 repository가 있는 경우, Local에 캐쉬 용도로 사용한다.

   Virtual Repository : Repository Group은 몇 개의 repository를 하나의 repository로 묶어서 단일 접근 URL을 제공한다.

 

여기서는 가장 널리 사용하는 local repository로 설정 하는 시나리오와 함께, 외부 repository에 대한 proxy 시나리오로 사용하는 설정을 소개한다.

설치

http://www.sonatype.com 에서 nexus 무료 버전을 다운로드 받아서 설치한다. 초기 디폴트 로그인 계정과 비밀번호는 "admin/admin123"이다.


  

Public Repositories라는 repository 그룹에 local repository (Releases Snapshots, 3rd party) proxy repository를 포함시킨다.




 

다음으로 Proxy Repository Remote Repository의 내용들에 대한 라이브러리 목록(Index) Local Caching할 수 있도록 되어 있다. 이렇게 하면, nexus proxy repository에 실제 바이너리가 내려와 있지 않더라도 목록이 미리 내려와 있기 때문에, nexus search 기능을 통해서 검색이 가능하다.

"Maven Central Repository" "Central" repository 에 설정을 해보자 "Central repository"를 선택한 후, 메뉴에서 "Download Remote Indexes" 라는 Option "True"로 변경한다. 다음 SAVE 버튼으로 저장한 후, 상단 테이블 메뉴에서 "Central" repository를 선택한 후 오른쪽 버튼을 눌러서 팝업 메뉴에서 "update index"를 실행하면, 원격 maven repository에서 라이브러리 목록을 읽어서 업데이트가 된다.

 



 

업데이트가 끝나면 "Browse Index" 메뉴에서 라이브러리 목록이 새롭게 업데이트 되어 있는 것을 확인할 수 있다.

 



Maven에서 local nexus Proxy (Cache) repository로 설정하기

Nexus 설정이 끝났으면 다음으로 maven nexus rmirroring repository 설정해보자.

$MAVEN_HOME/.m2/setting.xml

파일에서 <mirrors> section에 아래 내용을 추가하자

 

<mirror>

      <id>nexus</id>

      <mirrorOf>*</mirrorOf>

      <name>Local nexus repository.</name>

      <url>http://localhost:8081/nexus/content/groups/public/</url>

    </mirror>

  </mirrors>

 

설정이 끝난후, maven 빌드를 수행하면 maven script가 원격지가 아닌 local에 있는 nexus repository를 통해서 라이브러리를 다운로드 하는 것을 확인할 수 있다.

 



또한 nexus console을 통해서 "Browse Storage" 메뉴를 통해서 "Central" repository storage 를 보면 빌드에 사용되었던 모든 라이브러리들이 local nexus에 다운로드 받아져 있음을 확인할 수 있다.

 


 



저작자 표시
신고

 OpenLdap install in Windows


1. 설치 및 구동

http://sourceforge.net/projects/openldapwindows/ 에서 바이너리를 받아서 위자드를 이용하여 설치

${OPENLDAP 설치 디렉토리}/etc/openldap/sldpd.conf 파일에서 root 비밀번호를 다음과 같이 수정

 

#######################################################################

# BDB database definitions

#######################################################################

 

database            bdb

suffix                  "dc=my-domain,dc=com"

rootdn                 "cn=Manager,dc=my-domain,dc=com"

# Cleartext passwords, especially for the rootdn, should

# be avoid.  See slappasswd(8) and slapd.conf(5) for details.

# Use of strong authentication encouraged.

rootpw                asdf1234

# The database directory MUST exist prior to running slapd AND

# should only be accessible by the slapd and slap tools.

# Mode 700 recommended.

directory       ../var/openldap-data

# Indices to maintain

 

C:\dev\solutions\openldap\libexec\StartLDAP.cmd 를 실행

 

2. Sample 데이타 로딩하기

테스트를 위해서 샘플 그룹과, 사용자들을 생성해보자. 샘플 데이타는

${OPENLDAP 설치 디렉토리}\etc\ldif에 있다.

${OPENLDAP 설치 디렉토리}\bin 디렉토리에서 다음과 같은 명령들을 실행한다.

ldapadd.exe -v -x -D "cn=Manager,dc=my-domain,dc=com" -f ..\etc\ldif\base.ldif -W

ldapadd.exe -v -x -D "cn=Manager,dc=my-domain,dc=com" -f ..\etc\ldif\users.ldif -W

 

※ 패스워드를 물어보는데, 패스워드는 앞에 slpd.conf에서 입력한 패스워드를 사용한다.

 

3. 클라이언트를 이용해서 연결하기

http://www.ldapadministrator.com/ 에서 ldap administrator라는 툴을 다운 받는다. (30일 무료 사용 가능)

File > New > New Profile을 선택하여, 새로운 서버를 등록한다.

Step 1. Profile명을 등록한다.

Step 2. Host 주소를 등록한다. Local 에 깔았다면, Host localhost, Port Default 389를 지정한다. 


 

Step 3. 다음으로 log in id/password를 넣는데, 앞에 slapd.conf에서 지정한 id,passwd "Principal Password" 필드에 다음과 같이 넣는다.


 

모든 작업이 다 끝났으면 아래와 같이 LDAP에 접속해서 내용을 볼 수 있다.




2013.5.18 추가 - LDAP에 대한 설명과 Open LDAP에 대한 설명이 잘 나온 글 

http://w.nya.kr/lib/exe/fetch.php?media=%EB%8B%A8%EC%96%B4:ldap:ldap.doc



저작자 표시
신고

Python Fabric Install

프로그래밍/Python | 2013.01.28 18:55 | Posted by 조대협

AWS EC2 (Amazon Linux 기준)


1. Python install (dev package로 설치)

(반드시 dev package가 설치되어 있어야지, pycrypto 설치시 에러가 나지 않음. pycrptyo는 encryption 관련 라이브러리로 C 라이브러리를 사용하는데, 컴파일중, python.h를 사용한다. 이 헤더 파일은 dev package안에 포함되어 있음)


- yum install python-devel 


2. pip install

$ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py

$ [sudo] python get-pip.py


3. gcc가 인스톨 (pycrypto 설치를 위해서 필요함) 

yum install gcc


4. fabric install


pip install pycrypto fabric


5. 설치 확인


from fabric.api import run


def host_type():

    run('uname -s')


저작자 표시
신고

Python 공부 노트 7. - Django 설치

프로그래밍/Python | 2013.01.22 00:26 | Posted by 조대협

설치

Python 설치 후, Django 다운로드 https://www.djangoproject.com/download/ 

후에, 압축 풀고

 > python setup.py install


설치 확인

>>> import django
>>> print(django.get_version())
1.6

웹사이트 생성

django-admin.py startproject mysite

dajngo-admin.py는 C:\dev\Python27\Scripts 에 있음

해당 디렉토리에 웹사이트 관련 디렉토리 생성됨 (일종의 Tomcat Home, WebLogic Domain Home 디렉토리 같은 개념, 바이너리는 python 디렉토리 아래에 있음)


웹사이트 실행

python manage.py runserver


참고 자료 - https://docs.djangoproject.com/en/dev/intro/tutorial01/


저작자 표시
신고