앞의 포스팅에서 언급했듯이 NoSQL은 생겨난 이유는 비슷하지만 각각 접근 방법은 다르기 때문에 수많은 NoSQL들을 다양한 기준에 따라 분류할 수 있습니다.

CAP 이론
Consistent - Available : Postgres, MySQL같은 전통적인 RBMS
Consistent - Partition Tolerant : BitTable , Hypertable , HBase , MongoDB , Terrastore , Redis , Scalaris , MemcacheDB , BerkeleyDB
Available - Partition Tolerant : Amazon Dynamo , Cassandra , CouchDB , Amazon SimpleDB , Riak



분산형과 비분산형
분산형 : Amazon Dynamo, Amazon S3, Scalaris, Voldemort, CouchDB, Riak, MongoDB, BigTable, Cassandra, HyperTable, HBase
비분산형 : Redis, Tokyo Tyrant, MemcacheDB, Amazon SimpleDB

분산형 데이터베이스는 확장성을 위한 Data Partitioning과 Availability를 위한 복제에 대한 책임을 가지고 있고 비 분산형은 클라이언트가 이 책임들을 가지고 있습니다. 주목할만한 분산모델은 Dynamo에서 사용되었지만 Voldemort, Riak, Cassandra에서 이 모델을 카피해서 사용하고 있으며 이질적인 하드웨어간에도 효과적입니다.



데이터 모델의 풍부함(Richness)
Key-Value Store : Amazon Dynamo, Amazon S3, Redis, Scalaris, Voldemort
Document Store :
Amazon SimpleDB, Apache CouchDB, MongoDB, Riak
Column Store :
Scssandra, Google BigTable, HBase, Hypertable

이 분류에서 한쪽 끝은 Key-Value Store이고 반대쪽은 가장 부유한 Column Store입니다. 이 두 사이에는 관계형데이터베이스의 사촌정도가 되는 Document Store가 위치하고 있고 Key-Value보다는 풍부하고 이해하기가 쉽습니다.


Disk와 Memory
Memory : Scalaris, Redis
Configurable :
BigTable, Cassandra, HBase, HyperTable
Disk : CouchDB, MongoDB, Riak, Voldemort

Scalaris는 완전한 메모리 기반이고 Redis는 메모리주도적입니다. Configurable에 분류에 포함된 데이터베이스들은 많은 컨트롤을 제공하기 위해 얼마나 큰 메모리를 얻을 것인지를 설정할 수 있으며 Disk의 범주에 있는 CouchDB, MongoDB, Riak은 on-disk B+ Tree를 사용하며 Voldemort는 BDB와 MySQL을 사용하고 있습니다.






데이터 모델의 방식에 따라 주요한  NoSQL위주로 특징들을 정리했습니다.

Key-Value Store
Key-Value Store는 가장 간단하게 가능한 데이터 모델을 제공합니다. 범위쿼리는 데이터베이스에서 명백하게 지원하지 않는다면 쉽지 않습니다. 그리고 Key-Value Store상에서의 애플리케이션 모델링은 복잡성을 가질 수 있습니다.

Amazon Dynamo

  • 분산형 Key-Value Store로 값이 시스템에 불투명합니다. 타겟 오브젝트는 보통 1MB 미만으로 Amazon내부에서 사용되고 있고 외부에서는 직접 이용할 수 없습니다.
  • 일관성 해싱을 사용해서 Partitioning을 합니다.
  • 복제 - 데이터는 다중호스트에 복제됩니다.
  • 일관성 - 업데이트는 비동기적으로 복제는 전파하기 때문에 모델은 결국 일관성을 가집니다.



Amazon S3

  • 분산형 Key-Object Store로 오브젝트는 시스템에 불투명합니다. 각 오브젝트의 사이즈는 1byte ~ 5GB의 범위내에 있으며 오브젝트의 갯수는 제한이 없는 무제한 스토리지 입니다. 오브젝트는 Amazon 데이터센터 내에서 유지가 되며 오브젝트의 위치에 대한 GEO를 결정하며 저장되는 오브젝트가 크면 유용합니다.
  • 일관성 : 새로운 PUT에서 Read Your Write1를 이루고 PUT과 DELETE를 덮어써서 결과적인 일관성을 가집니다.





Document Store
Document Store는 Key-Value Store보다 한걸음 더 나아간 구조입니다. 스키마가 테이블의 형태보다 먼저 정의되어야 하는 관계형 데이터베이스와는 달라서 각 도큐먼트는 다른 스키마를 가질 수 있습니다. 그러면서도 관계형 데이터베이스처럼 레코드간의 관계를 설명하는 것이 가능합니다. 이 먼저 정의해야하는 스키마를 제외하고는 개념적으로 관계형 데이터베이스와 아주 유사합니다.

Amazon SimpleDB

  • Erlang으로 작성되었습니다.
  • 데이터는 관계된 데이터를 함께 보관하기 위한 컨테이너로써의 도메인과 도메인으로 연결하기 위한 엔티티, 아이템의 프로퍼티로써 속성과 그 값으로 모델되었습니다.
  • 기본적으로 각 아이템은 속성을 언제나 추가/삭제 가능한 Dictionary입니다.
  • 아이템이 추가될 때 속성에 기반하여 인덱스됩니다.
  • 결과적인 일관성을 갖습니다.
  • 파티셔닝 : 도메인 - 아이템 - 어트리뷰트 모델은 각 도메인의 사이즈와 도메딩당 속성의 갯수 및 도메인의 갯수에 대한 제한을 갖는다. 그러므로 확장을 위해서는 데이터를 수동으로 파티션해야 합니다.



Apache CouchDB

  • Erlang로 작성되었습니다.
  • 데이터와 스토리지 모델 :
    • 레코드는 JSON스트링(도큐먼트)의 형식으로 직렬화됩며 각 도큐먼트는 유니크한 DocId를 같습니다.
    • B+트리 를 사용하면 커밋된 데이터는 결코 덮어써지지 않고 오직 오퍼레이션만 추가합니다.
    • Append only 모델로 Read가 다중버전의 동시성 제어를 사용해서 수행됩니다.
      쓰기는 동시에 작성가능한 Blob외에는 직렬화됩니다.
    • 같은 데이터를 위한 다중 뷰를 가질 수 있습니다.
    • Design Document라고 부르는 도큐먼트의 특별한 타입에서 갑에 키를 매핑하는 Javascript함수를 사용하도록 정의되었습니다.
  • View함수는 View를 쿼리했을 때 실행되며 기본적으로 Map 함수와 Reduce 함수가 존재합니다.
  • 복제 : 다중마스터를 지원하는 마스터 슬레이브를 갖으며 오직 최신 리비전만 복제가 됩니다.
  • 멀티마스터에서의 충돌(Conflict) 핸들링 : 충돌을 탐지하고 winner를 선택하기 위해 결정론적인 알고리즘을 사용하며 여기서 winner는 기대한 것일수도 아닐 수도 있기 때문에 아닐 경우에는 애플리케이션에서 스스로 고쳐야 합니다.
  • Partitioning과 로드 밸런싱 - CouchDB Lounge 에 의해서 제공됩니다.
  • Apache 2.0 라이센스를 따릅니다.



MongoDB

  • C++로 작성되었습니다.
  • 데이터 모델
    • 컬렉션 - Amazon SimpleDB의 도메인과 유사하며 비슷한 도큐먼트들을 함께 두기 위한 Bucket입니다.
    • Key-Value는 바이너리 직렬화된 JSON(BSON - Binary Serialized JSON )입니다.
    • 한 BSON 객체는 4MB 제한이 있습니다.
    • 큰 객체는 GridFS 를 통해 지원하고 있습니다.
    • 인덱스를 위해서 B-Tree가 사용되며 필드를 파라미터로 받는 db.things.ensureIndex()함수를 사용해서 인덱스에서 필드를 열거합니다.
  • 스토리지
    • in-Place 업데이트입니다.
    • 부분적인 업데이트를 제공하기 때문에 전체 로우를 보내지 않고 값을 업데이트 할 수 있습니다.
    • Forward-only 커서를 지원합니다.
    • 단일 도큐먼트 원자적 업데이트를 지원합니다. 원자적인 배치 업데이트는 db.eval()을 통해서 가능하지만 파티션된 데이터는 지원안할 수도 있습니다.
  • 쿼리
    • 도큐먼트 내부에서 값을 선택하기 위한 Syntax기반의 JSON 스타일을 제공합니다.
    • 상황적인 Operator와 정규식 등을 지원합니다.
    • Forward-only 커서를 지원합니다.
    • 쿼리 옵티마이징은 다중 쿼리플랜을 시도하고 가장 잘 동작하는 것을 선택하는 형식입니다.
  • 배치 오퍼레이션 : 컬렉션에 Map-Reduce를 지원합니다.
  • 복제 : 마스터-슬레이브 보델로 자동적으로 마스터와 슬레이브의 역할을 이해하는 복제쌍(replica pair)입니다.
  • Partitioning
    • 알파스테이지에서 파티셔닝 됩니다.
    • 파편(Shards)는 Chunk라고 불리는 유닛에서 데이터를 다루며 Chunk는 최대 50MB의 컬렉션으루부터 인접하는 범위의 데이터입니다.
    • 데이터는 하나의 Shard에서 Chunk안의 다른 Shard로 마이그레이션 됩니다.
  • AGPL 3.0 라이센스를 따릅니다.





Column Store

BigTable

  • 구글에서 내부적으로 사용하면 Google App Engine를 통해서 공개됩니다.
    Block를 짓습니다.
    • Google File System 를 사용하여 분산 파일시스템과 Raw 스토리지를 제공합니다. 청크서버가 청크를 저장할 책임을 가지고 있으며 각 청크는 안전을 위해 3개의 머신에 복제가 됩니다. 데이터전송은 클라이언트와 청크서버 사이에서 직접 발생합니다.
    • 스토리지 파일 포맷은 정렬된 스트링 테이블로 SSTable로 불립니다.
    • 스케쥴러는 메선에서 스케쥴 잡으로 제공됩니다.
    • 분산된 Lock과 파일, 네임 매니저로 Chubby 서비스 를 사용한다.

  • 데이터 모델은 Map의 Map인 다차원 Map입니다. 데이터는 테이블로 조직화되고 테이블은 관계된 데이터를 가진 엔티티입니다.
  • Write : Write 요청이 타블렛 서버에 도달했을 때 잘 규격화 되었는지와 권한을 확인하며 유효한 변경은 커밋로그에 작성됩니다.
  • Read : Write요청과 비슷한 확인을 하며 SSTable의 순서와 Memtable의 합쳐진 View에서 실행됩니다.



Cassandra

  • BigTable의 컬럼패밀리(Column-family) 데이터 모델과 Dynamo의 분산 아키텍쳐를 합쳤습니다.
  • Java로 작성되었습니다.
  • 데이터 모델
    • BigTable같은 키에 의해 인덱스되는 다차원 맵을 사용하며 각 애클리케이션은 BigTable에서 테이블같은 Key-Space를 만듭니다. Key는 레코드를 위한 이름이고 Column은 레코드의 속성이며 타임스템프가 찍힙니다. Column-family는 컴럼의 그룹핑으로 관계형 테이블과 유사하고 Super-Column은 컬림들의 리스트입니다.
    • 소팅은 데이터의 쓰여진 시간으로 정렬되되며 컬럼들은 컬럼의 이름으로 Row내에서 정렬됩니다.
  • Partitioning : Dynamo와 유사하며 순서가 보장된 햄쉬함수를 사용하는 일관된 해시를 사용하고 Dynamo와는 다른 로드밸런싱을 위해소 Chord 접근을 사용합니다.
  • 복제 : Dynamo의 조정자 노트와 선호리스트의 건셉과 같으며 Datacenter aware Rack aware, Rack unaware같은 다양한 보제 정책들을 가지고 있습니다.
  • 퍼시스턴스 : 로컬파일 시스템에 의지하며 스토리지 구조와 접근방식은 BigTable과 유사합니다.
  • Write : Memtable에 대한 업데이트를 따르는 내구성과 복구를 위한 커밋로그를 쓰는 Bigtable의 접근과 유사하며 커밋로그를 위한 각 머신의 전용디스크는 Write를 순차적으로 만들어 쓰루풋을 최대화 합니다.
  • Read : 제공될 노드와 Read-repair를 찾는 Dynamo와 유사한 접근방식을 사용하며 스토리지 레벨에서의 접근은 BigTable과 유사한 Memtable + SSTable 시퀀스로부터 읽습니다.
    라이센스는 Apache 2를 따릅니다.
Footnote.
  1. Read-Your-Writes(RYW) 일관성은 레코드가 업데이트 되었을때 그 레코드에 대한 읽기시도는 업데이트된 값을 돌려주는 것을 보장해주는 것의 의미합니다. [Back]
2010/09/18 23:59 2010/09/18 23:59
크리에이티브 커먼즈 라이센스
Creative Commons License

'Database' 카테고리의 다른 글

DROP, DELETE, TRUNCATE의 차이점  (0) 2011.06.29
NoSQL에 대해서 #1  (0) 2011.06.09
웹이 점점 커지고 다양한 요구가 생겨나는 가운데 NoSQL이 커다란 이슈중에 하나로 떠오르고 있습니다. 제가 NoSQL에 대해서 처음 들은 것은 올 초정도로 기억하고 있습니다.

Google Trends에서 NoSQL로 검색한 결과

구글 트랜즈 에서 확인해보아도 NoSQL이라는 단어가 이슈화되기 시작한 것은 2009년 중순정도로 나타나고 있습니다.  위키피디아 에서 확인해 보면 NoSQL이라는 단어는 1998년 Carlo Strozzi이 SQL을 드러내지 않는 경량 데이터베이스로 이름지었고 2009년 초에 Last.fm 의 Johan Oskarsson이 오픈소스 분산데이터베이스에 대한 논의를 위한 이벤트를 원했을 때 Rackspace 의 직원인 Eric Evans가 NoSQL이라는 단어를 다시 소개했다고 합니다. 아틀란타에서 열린 no:sql conference 2009가 NoSQL논의에 큰 영향을 미쳤다고 합니다. (이 컨퍼런스의 모토인 "select fun, profit from real_world where relational=false;"가 상당히 센스넘치는군요)

올해 중에 NoSQL중 하나는 경험해 보자는 생각이었는데 마침 좀 만져볼 기회가 생겨서 좀 만져보고 있습니다. 개념자체가 개발자에게 기존에 익숙한 RDBMS와는 너무 달라서 튜토리얼 보고 단순한 사용정도는 할 수 있겠지만 관련해서 고민해 보려면 NoSQL에 대해서 좀 자세히 알아야 할 필요가 있게 느껴졌습니다. 사실 NoSQL에 대한 지식이 많다보니 고민 자체가 해결책이나 진도나 나가지 않고 계속 빙글빙글 도는 느낌이라 여기저기 자료를 좀 찾아서 정리해 보았습니다.





CAP Theorem
NoSQL에 대해서 이해하려면 먼저 CAP 이론에 대해서 알 필요가 있습니다. CAP이론은 Brewer's CAP Theorem 으로 알려져 있는데 분산 컴퓨팅 시스템에서 보장해야 하는 특징으로 아래 3가지를 정의하고 있습니다.

  • Consistency (일관성) : 모든 노드들은 동시에 같은 데이터를 보아야 합니다.
  • Availability (유효성) : 모든 노드는 항상 읽기와 쓰기를 할 수 있어야 합니다.
  • Partition Tolerance (파티션 허용차) : 시스템은 물리적인 네트워크 파티션을 넘어서도 잘 동작하여야 합니다

CAP 이론에 따르면 위 3가지 중에 동시에 2가지만 보장할수 있고 3개를 모두 보장하는 것이 불가능하다고 나와있습니다. 그래서 데이터를 관리할때 이 3가지 중에 어느 2가지에 중점을 두냐는 것은 아주 중요한 부분입니다. 이 부분을 이해하는데 Nathan Hurst 이 만든 아래의  Visual Guide to NoSQL Systems 는 큰 도움이 됩니다.

사용자 삽입 이미지

기존에 많이 사용하던 RDBMS는 3가지 중 CA에 집중하고 있습니다. 웹이 발전하면서 다양한 요구사항이 생겨나고 엄청난 양의 데이터를 처리해야 하게 되면서 RDBMS가 갖지 못한 P의 특성이 필요해졌고 그러면서 등장한 것이 NoSQL입니다. 좀더 풀어쓰면 데이터베이스에 대한 수평적 확장(Horizontal Scalability 즉 옆에 서버한대 더 배치해서 데이터베이스를 늘리고 싶다는 의미입니다.)에 대한 이슈가 발생했고 확장성이슈를 해결하기 위해서 P를 선택하다 보니 기존에 가지고 있던 C나 A의 특성중 하나를 포기해야 했습니다. 그래서 NoSQL에는 다양한 시도들이 있지만 가장 중요한 이슈는 확장성을 해결하려는 것으로 생각됩니다.

관계형 데이터베이스는 기본적으로 분산형을 고려해서 디자인 되지 않았습니다. 그래서 ACID(원자성, 일관성, 독립성, 지속성) 트랜잭션 같은 추상화와 고레벨 쿼리모델을 풍부하게 제공할 수 있지만 확장성이 좋지 못하기 때문에 모든 NoSQL 데이터베이스는 다양한 방법으로 확장성 이슈를 해결하기 위해 초점을 맞추고 있습니다. 각 NoSQL에는 여러가지 차이점들이 있지만 CAP의 범주에서만 보면 CP를 선택하거나 AP를 선택하게 됩니다.




왜 비관계형이어야 하는가?
NoSQL이 확장성 이슈를 해결하려고 CP나 AP의 특성을 선택했지만 구체적으로 어떤 특징을 선택하고 왜 그래야 했는지 이해할 필요가 있습니다. NoSQL은 많은 제품군들이 있는데 모두 같은 전략으로 접근하고 있지는 않고 각각에 제품에 따라 다양한 접근을 하고 있는데 아래 적힌 내용들은 비관계형으로 가기 위한 여러가지 특성들에 대한 이야기이고 제품군에 따라 아래의 특성들을 선택한 여부는 다른 것으로 보입니다. 아래의 내용은 상당부분 VINEET GUPTA가 작성한 NoSql Databases - Part 1 - Landscape 를 참고하였습니다. 잘 정리된 문서라서 참고하시면 도움이 될 것입니다.



관계형 데이터 베이스는 확장하기가 어렵습니다.

Replication - 복제에 의한 확장
Master-Slave 구조에서는 결과를 슬레이브의 갯수만큼 복제해야 하는데 N개의 슬레이브에서 읽을 수 있기 때문에 Read는 빠르지만 Write에서는 병목현상이 발생하게 기 때문에 확장성에 대한 제한을 가지게 됩니다.
다중 마스터구조에서는 마스터를 추가함으로써 쓰기의 성능을 향상시킬 수 있는데 대신에 충돌이 발생할 가능성이 생기게 됩니다.

Partitioning(Sharding) - 분할에 의한 확장
Read만큼 Write도 확장할 수 있지만 애플리케이션레이어에서 파티션된 것을 인지하고 있어야 합니다. RDBMS의 가치는 관계에 있다고 할 수 있는데 파티션을 하면 이 관계가 깨져버리고 각 파티션된 조각간에 조인을 할 수 없기 때문에 관계에 대한 부분은 애플리케이션 레이어에서 책임져야 합니다. 일반적으로  RDBMS에서 수동  Sharding 은 쉽지 않습니다.



필요없는 특성들

UPDATE와 DELETE
Update와 Delete는 전통적으로 정보의 손실이 발생하기 때문에 잘 사용되지 않으며 후에 데이터 검사 및 재활성화를 위해서 기록해둘 필요가 있습니다. 그리고 사용자가 커뮤니티를 탈퇴한다고 그들의 글을 지우지 않듯이 도메인 관점에서는 실제로 삭제되지 않습니다.  이런 접근을 하게 되면 Update / Delete를 모두 Insert로 모델할수 있고 과거 데이터는 버전을 붙혀서 기록할 수 있으며 이 데이터들은 비활성데이터들이 됩니다. 이 INSET-only 시스템에서는 2개의 문제가 있는데 데이터베이스에서 종속(cascade)에 대한 트리거를 이용할 수 없으며 Query가 비활성 데이터를 걸러내야 할 필요가 있습니다.

JOIN
데이터가 많을 때 JOIN은 많은 양의 데이터에 복잡한 연산을 수행해야 하기 때문에 비용이 많이 들며 파티션을 넘어서는 동작되지 않기 때문에 피해야 합니다. 정규화는 일관된 데이터를 가지기 쉽게 하고 스토리지의 양을 줄이기 위해서 하는건데 반정규화(De-normalization)를 하면 JOIN문제를 피할 수 있습니다. 반정규화로 일관성에 대한 책임을 디비에서 애플리케이션으로 이동시킬수 있는데 이는 INSERT-only라면 어렵지 않습니다.

ACID 트랜젝션
Atomic (원자성) : 여러 레코드를 수정할 때 원자성은 필요없으며 단일키 원자성이면 충분합니다.
Consistency (일관성) : 대부분의 시스템은 C보다는 P나 A를 필요로 하기 때문에 엄격한 일관성을 가질 필요는 없고 대신 결과의 일관성(Eventually Consistent )을 가질 수 있습니다.
Isolation (격리성) : 읽기에 최선을 다하는(Read-Committe) 것 이상의 격리성은 필요하지 않으며 단일키 원자성이 더 쉽습니다.
Durability (지속성) : 각 노드가 실패했을때도 이용되기 위해서는 메모리가 데이터를 충분히 보관할 수 있을정도로 저렴해지는 시점까지는 지속성이 필요합니다.

고정된 스키마
RDBMS에서는 데이터를 사용하기 전에 스키마를 정의해야하고 Index등을 정의해야 하는데 현재의 웹환경에서는 빠르게 새로운 피쳐를 추가하고 이미 존재하는 피쳐를 조정하기 위해서는 스키마 수정이 필수적으로 요구됩니다. 하지만 컬럼의 추가/수정/삭제는 row에 lock을 걸고 index의 수정은 테이블에 락을 걸기 때문에 스키마 수정이 어렵습니다.



어떤 특성들은 갖지 않습니다.
계층화 데이터나 그래프를 모델하는 것은 어렵습니다. 또한 빠른 응답을 위해서 디스크를 피하고 메인 메모리에서 데이터를 제공하는 것이 바람직한데 대부분의 관계형 데이터베이스는 디스크기반이기 때문에 쿼리들이 디스크에서 수행됩니다.





기대하는 특성들
NoSQL이 바라는 환경은 서버들이 다른 용량들을 가지고 수업이 퍼져나가는 것으로 이를 노드라고 부릅니다.

높은 확장성
점진적으로 노드를 추가할 수 있어야 하고 이는 파티셔닝을 통해서 가능합니다.

높은 Availability
실패의 단일포인트가 없으며 데이터는 복제되기 때문에 어떤 노드가 죽었을때도 데이터는 이용이 가능합니다.

높은 성능
디스크대신 메모리 기반으로 결과는 빠르게 리턴되어야 하며 이는 논블락킹 Write와 낮은 복잡성을 가진 알고리즘을 통해서 이룰수 있습니다.

원자성
각각의 쓰기는 원자성을 가질 필요가 있다.

일관성
강한 일관정은 필요없고 결과적인 일관성만 가지면 된다.(Read-Your-Writes1 일관성)

지속성
데이터는 휘말성 메모리만이 아닌 디스크에서 유지되어야 합니다.

배포의 유연함(Flexibility)
노드의 추가/삭제는 데이터를 분산하고 수동으로 중재할 필요없이 자동적으로 로드되어야 하며 분산 파일 시스템이나 공유스토리지 요구같은 제약이나 특수한 하드웨어같은 것이 필요없어야 합니다. 이기종간의 하드웨어에서 동작가능해야 합니다.

모델링의 유연함(Flexibility)
Key-Value쌍, 계층형 데이터, 그래프등 여러가지 타입의 데이터를 간단하게 모델할 수 있어야 합니다.

쿼리의 유연함(Flexibility)
하나의 호출에서 제공된 키에 대한 값이 묶음을 얻는 다중 GET과 키의 특정 범위에 기반한 데이터를 얻는 범위 쿼리가 필요합니다.


이 포스팅은 NoSQL에 대해서 #2로 이어집니다.
Footnote.
  1. Read-Your-Writes(RYW) 일관성은 레코드가 업데이트 되었을때 그 레코드에 대한 읽기시도는 업데이트된 값을 돌려주는 것을 보장해주는 것의 의미합니다. [Back]
2010/09/18 23:57 2010/09/18 23:57
크리에이티브 커먼즈 라이센스
Creative Commons License

'Database' 카테고리의 다른 글

DROP, DELETE, TRUNCATE의 차이점  (0) 2011.06.29
NoSQL에 대해서 #2  (0) 2011.06.09
Memcached 데몬
사이트 : http://www.danga.com/memcached/
다운로드 : http://memcached.googlecode.com/files/memcached-1.2.8.tar.gz

Memcached PHP Extension
사이트 : http://pecl.php.net/package/memcache
다운로드 : http://pecl.php.net/get/memcache-2.2.5.tgz

LibEvent
사이트 : http://monkey.org/~provos/libevent/
다운로드 : http://monkey.org/~provos/libevent-1.4.11-stable.tar.gz

 

Memcached 는 데이터를 메모리에 저장하여 이용할 수 있는 데몬이다. 분산처리가 가능하고 매우 빠른 성능을 지닌 캐시 이다.
(편의상 root로 작업)

 

1. Memcached 설치

우선 Memcached 를 적당한 디렉토리 (/usr/local/src) 등에 다운로드를 받는다.
# tar zxvf memcached-1.2.8.tar.gz
# cd memcached-1.2.8
# configure --prefix=/usr/local/memcached
* checking for libevent directory... configure: error: libevent is required 메세지가 나오면 libevent 라이블러리를 설치를 해줘야 한다.

# make
# make install

 

1-1 memcached 실행
# cd /usr/local/memcached (configure 에서 지정한 prefix로 이동)
# bin/memcached -u [실행될 사용자] &
* 실행될 사용자는 memcached 데몬이 -u 옵션으로 지정된 사용자로 실행이 된다 (root로 지정하면 안됨)
# netstat -na | grep 11211
->
tcp        0      0 0.0.0.0:11211               0.0.0.0:*                   LISTEN     
tcp        0      0 :::11211                          :::*                            LISTEN

포트를 확인한다.

 

2. Memcache PHP Extension
# tar zxvf memcache-2.2.5.tgz
# cd memcache-2.2.5
# phpize
# ./configure
# make
# cp .libs/memcache.so /(php 익스텐션 디렉토리) php.ini에서 지정한 extension_dir 에서 설정한 디렉토리
# php -m | grep memcache 로 모듈 확인
# /etc/init.d/httpd restart 또는 /usr/local/apache/bin/apachectl restart 로 Apache 재시작

PHP info 확인

 

3. Libevent 설치 (옵션)
* Memcache Configure 중 libevent 가 필요하다는 메세지를 보내고 중단이 되었을때 설치를 한다.

libevent 를 다운로드 받는다.
# tar zxvf libevent-1.4.11-stable.tar.gz
# cd libevent-1.4.11-stable
# ./configure
# make
# make install (/usr/local/lib 에 libevent.so 파일이 존재하는지 확인한다.)
# ldconfig (vi /etc/ld.so.conf 에 /usr/local/lib 추가를 한다.

PHP memcache 사용은 다음편에서 다루도록 하겠습니다 ^^


원본 : http://mcpicdtl.blogspot.com/2010/04/memcached.html

 

Memcached 는 데이터를 메모리에 저장하며 분산처리가 가능하고 매우 빠른 성능을 지닌 캐시 입니다.

- libevent 설치
Memcached 는 libevent 를 필요로 하므로 먼저 설치를 진행하겠습니다.

http://monkey.org/~provos/libevent/

[root@yongobk ~]# cd /usr/local/src
[root@yongobk ~]# wget http://monkey.org/~provos/libevent-1.4.13-stable.tar.gz
[root@yongobk ~]# tar xzvf libevent-1.4.13-stable.tar.gz
[root@yongobk ~]# cd libevent-1.4.13-stable
[root@yongobk ~]# ./configure
[root@yongobk ~]# make ; make install


- Memcached 설치
아래 주소에서 최신버전을 다운로드 하고 설치를 진행합니다.

http://code.google.com/p/memcached/downloads/list

[root@yongobk ~]# cd /usr/local/src
[root@yongbok ~]# wget http://memcached.googlecode.com/files/memcached-1.4.4.tar.gz
[root@yongbok ~]# tar xzvf memcached-1.4.4.tar.gz
[root@yongbok ~]# cd memcached-1.4.4
[root@yongbok ~]# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local
[root@yongbok ~]# make ; make install

-> 추가

libevent 라이브러리를 memcached에 인식 시키기

[]# whereis libevent를 실행해서 라이브러리 위치 확인

[]# ldd /usr/local/memcached/bin/memcached

linux-gate.so.1 =>  (0x001b0000)
libevent-1.4.so.2 => /usr/local/lib/libevent-1.4.so.2 (0x007a3000) --이렇게 출력되어야 함. 만약 not found가 나오는 경우 아래 명령을 실행
libpthread.so.0 => /lib/libpthread.so.0 (0x00aa1000)
libc.so.6 => /lib/libc.so.6 (0x0092c000)
libnsl.so.1 => /lib/libnsl.so.1 (0x00c10000)
librt.so.1 => /lib/librt.so.1 (0x00b31000)
libresolv.so.2 => /lib/libresolv.so.2 (0x00c37000)
/lib/ld-linux.so.2 (0x0090e000)

[]# echo "/usr/local/lib" >> /etc/ld.so.conf

[]# ldconfig /etc/ld.so.con

[]# ldd /usr/local/memcached/bin/memcached를 실행해서 라이브러리 로드를 확인한다.

 

- Memcached 실행
[root@yongbok ~]# /usr/local/memcached/bin/memcached -u nobody &
- Memcached PHP Extension 설치

http://pecl.php.net/package/memcache

[root@yongobk ~]# cd /usr/local/src
[root@yongbok ~]# wget http://pecl.php.net/get/memcache-2.2.5.tgz
[root@yongbok ~]# tar xzvf memcache-2.2.5.tgz
[root@yongbok ~]# cd memcache-2.2.5
[root@yongbok ~]# /usr/local/php5/bin/phpize
[root@yongbok ~]# ./configure --with-php-config=/usr/local/php5/bin/php-config
[root@yongbok ~]# make ; make install

Installing shared extensions: /usr/local/php5/lib/php/extensions/no-debug-non-zts-20060613/


php.ini 파일에 아래 내용 추가 합니다.

[root@yongbok ~]# vi /usr/local/apache2/conf/php.ini

[memcache]
extension_dir=/usr/local/php5/lib/php/extensions/no-debug-non-zts-20060613/
extension=memcache.so
memcache.allow_failover=1
memcache.max_failover_attempts=100
memcache.chunk_size=32768
memcache.default_port=11211


- Apache 재시작

[root@yongbok ~]# /usr/local/apache2/bin/apachectl restart


- PHP 에 Memcached 가 적용 되어 있는지 확인

[root@yongbok ~]# echo '<?php phpinfo(); ?>' > /var/www/phpinfo.php





참고
http://www.ibm.com/developerworks/kr/library/os-php-fastapps3/

[세션을 메모리캐싱을 사용할 경우 주의 사항 ]
memcache를 사용하는 중 세션 정보가 유지되지 않아 그것을 해결하는데
많은 시간을 소비하였습니다. 저의 경우 모델자체를 세션에 저장하였었는데 그것의 데이터가 많아지면 저절로 기존 데이터가 사라지는 것이었습니다. 그래서 필요한 데이터만 저장하니까 그러한 문제는 발생되지 않았습니다

memcached + Session Database
- memcached의 원래 목적이 데이터베이스나 파일 데이터를 캐시하는 것임

- 세션 데이터를 데이터베이스로 만들어 넣고, session handler 부분에서 memcached를 호출하게 만들면 될 듯.

- 데이터베이스를 사용하는 안정성 + 세션 공유 문제 해결 + memcached에 의한 성능 향상까지 기대할 수 있지 않을까?

- 이 부분은, 좀더 생각해보면서, 방법을 찾아봐야 할 듯...
<- 곰곰히 생각해보니, 약간 부정적. 세션 데이터는 read보다는 update가 압도적으로 많음. 따라서, 캐시 효과는 작음.



Memcache & MySQL PHP Session Handler PHP code for session db + memcached
http://www.softwareprojects.com/resources/programming/t-php-sessionsave_handler-and-database-sessions-debu-1797.html
http://www.softwareprojects.com/resources/programming/t-memcached-for-php-sessions-1654.html



Cache사용을 자주 할 일이 없기에, 간혹 사용하더라도 ibatis 캐쉬를 쓰곤했다.

사용할 일이 있어 이참에 적극적(?)으로 사용하고자 memcache를 도입하려하다

linux 서버에 memcache deamon을 띄우는 설치/실행 절차를 정리해본다.


1) libevent 설치

 - memcached를 설치하기 위해선 기본적으로 libevent library가 필요하다.

 - http://monkey.org/~provos/libevent/ 에서 필요한 버젼을 받는다.

$ wget http://monkey.org/~provos/libevent-1.4.8-stable.tar.gz

$ tar -xvzf libevent-1.4.8-stable.tar.gz

$ cd libevent-1.4.8-stable

$ ./configure

$ make

$ make install

 - /usr/local/lib 하위에 library가 설치됨을 확인할 수 있다.



2) memcached 설치

 - http://memcached.org/latest 에서 최신 버젼을 다운 받아서 설치한다.

wget http://memcached.org/latest

$ tar -xvzf memcached-1.4.5.tar.gz 

$ cd memcached-1.4.5

$ ./configure (--prefix=/myprogram/memcached-1.4.5 --with-libevent=/usr/local/lib/  ) 생략가능

$ make

$ make install


 - configure 할때 위에서 설치된 libevent의 경로를 간혹 못 찾는 경우가 있는 듯하다.

   memcache 실행시 libevent를 못찾는다면 option을 추가한다.




3) 실행

$ ./memcached -p 11211 -d -u lkflower

 - configure 옵션을 주었지만 path를 못 찾는경우가 있는데;;; 아래 오류와 같이 뜨면서..

./memcached: error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory

$ ln -s /usr/local/lib/libevent-1.4.so.2 /usr/lib/ 

처럼 symbolic 으로 처리하면 되겠다.


4) 확인

memcache가 잘 되는지 확인하기 위해 telnet으로 접속하여 stats 명령으로 확인해 본다. 

접속 포트는 위의 memcache 데몬을 올린 포트와 동일하다.

$ telnet 127.0.0.1 11211

Trying 127.0.0.1...

Connected to localhost.localdomain (127.0.0.1).

Escape character is '^]'.

stats

STAT pid 16129

STAT uptime 166

STAT time 1297756494

STAT version 1.4.5

STAT pointer_size 32

STAT rusage_user 0.001999

STAT rusage_system 0.001999

STAT curr_connections 10

STAT total_connections 11

STAT connection_structures 11

STAT cmd_get 0

STAT cmd_set 0

STAT cmd_flush 0

STAT get_hits 0

STAT get_misses 0

STAT delete_misses 0

STAT delete_hits 0

STAT incr_misses 0

STAT incr_hits 0

STAT decr_misses 0

STAT decr_hits 0

STAT cas_misses 0

STAT cas_hits 0

STAT cas_badval 0

STAT auth_cmds 0

STAT auth_errors 0

STAT bytes_read 7

STAT bytes_written 0

STAT limit_maxbytes 67108864

STAT accepting_conns 1

STAT listen_disabled_num 0

STAT threads 4

STAT conn_yields 0

STAT bytes 0

STAT curr_items 0

STAT total_items 0

STAT evictions 0

STAT reclaimed 0

END





 

   기업에 있어서 4C분석 등의 환경분석을 통해 강점(strength)과 약점(weakness), 기회(opportunity)와 위협(threat) 요인을 찾아내고 이를 토대로 마케팅 전략을 수립하는 경영기법을 말합니다. 즉 어떤 기업의 내부환경을 분석하여 강점과 약점을 발견하고, 외부환경을 분석하여 기회와 위협을 찾아내어 이를 토대로 강점은 살리고 약점은 없애거나 줄이고, 기회는 적극 활용하고 위협은 억제하거나 피하는 마케팅 전략을 수립하는 것을 말합니다.

 

   여기서 사용되는 4요소를 강점·약점·기회·위협(SWOT)이라고 하는데, 강점은 경쟁기업과 비교하여 소비자로부터 강점으로 인식되는 것은 무엇인지, 약점은 경쟁기업과 비교하여 소비자로부터 약점으로 인식되는 것은 무엇인지, 기회는 외부환경에서 유리한 기회요인은 무엇인지, 위협은 외부환경에서 불리한 위협요인은 무엇인지를 찾아냅니다. 기업 내부의 강점과 약점을, 기업 외부의 기회와 위협을 대응시켜 기업의 목표를 달성하려는 SWOT 분석에 의한 마케팅 전략의 특성은 다음과 같이 활용할 수 있습니다.


   ① SO전략(강점-기회전략)은 시장의 기회를 활용하기 위해 강점을 적극 활용하는 전략 ② ST전략(강점-위협전략)은 시장의 위협을 회피하기 위해 강점을 사용하는 전략 ③ WO전략(약점-기회전략)은 약점을 극복하거나 제거함으로써 시장의 기회를 활용하는 전략 그리고 ④ WT전략(약점-위협전략)은 시장의 위협을 회피하고 약점을 최소화하거나 없애는 전략을 수립하는 것을 말합니다.


   이 SWOT 기법은 기업에 국한하지 않고 개인이 특정한 문제에 부딪혔을 때 SWOT 매트릭스를 세워보고 이를 슬기롭게 풀어가는 경우에도 이용할 수 있습니다.

[출처] SWOT분석이란|작성자 sistol


박용우

이클립스는 앞으로 다가올 대변혁의 시대를 준비하고 있다. 지금까지 진행해왔고, 앞으로 진행할 이클립스 프로젝트들은 엔터프라이즈 개발, 임베디드 및 모바일 개발, 리치 클라이언트 플랫폼, 애플리케이션 프레임워크, 개발 언어 IDE 등으로 세분화되고 있다. 그러나 우리는 과거의 이클립스 IDE만을 생각하며 마냥 시간을 보내고 있는 것 같다. 필자 역시 이번 기고를 진행하면서 까맣게 잊고 있던 무언가를 다시금 떠올릴 만한 계기를 마련한 것 같다. 지금부터 RCP와 함께 새로운 각오를 다져보자.



1990년대 중반부터 두드러진 인터넷과 웹 브라우저의 보급으로 현대인들의 생활 패턴이 완전히 달라졌다. 이제는 모든 생활이 인터넷에서 이뤄질 수 있다고 해도 과언이 아닐 것이다. 그러나 최초의 웹 브라우저인 넷스케이프와 마이크로소프트의 인터넷 익스플로러가 펼친 웹 브라우저 전쟁에서 인터넷 익스플로러가 승리한 이후부터는, 많은 웹 기반 개발자들과 사용자들은 더 이상의 새로운 웹 기술의 발전을 경험하지 못했고, 점점 더 웹의 한계를 느끼기 시작했다. 그나마 리눅스나 파이어폭스와 같은 도전자들이 존재하고 있어 마이크로소프트가 장악하다시피 한 웹 환경에서 다소나마 발전이 이뤄지고 있다고 할 수 있다.



리치 클라이언트의 귀환

웹브라우저를 필두로 하여 웹 페이지, 웹 서버, CGI, 웹 애플리케이션으로 이어지는 씬(thin) 클라이언트가 클라이언트 PC의 기본 플랫폼이 되었고, 많은 유지보수(특히 버그 수정과 버전 갱신) 문제와 무거운 동작성이라는 약점을 안고 있는 리치 클라이언트가 점차 사라지게 되었다.

21세기로 넘어오면서 이처럼 많은 시스템들이 웹으로 이동했고, 웹은 사용자가 처음 익히기에 쉽고 빠르며 이식도 편리한 환경을 제공했다. 그러나 사용자들이 모든 일을 웹 브라우저를 통해 수행하려다 보니, 빈약한 사용자 체험(user experience), 웹 엔트로피의 증가, 다양한 플랫폼 및 다중 웹 브라우저에 대한 지원 부족 등의 문제들이 하나둘 나타나기 시작했다. HTML의 단순한 사용자 인터페이스가 주는 제약을 뛰어넘기 위해 DHTML, 자바스크립트, 액티브X 컨트롤, 플래시가 범람하게 되었고, 이는 결국 웹 브라우저로 대표되는 씬 클라이언트가 다시금 무거워지는 계기로 작용했다. 이러한 혼란의 시대가 계속되자 어디론가 사라졌던 리치 클라이언트가 다시 귀환하게 되었다.

플래시 는 리치 클라이언트의 부활을 알리는 첫 신호탄이었다. 이는 기존의 웹에서 볼 수 없었던 풍부한 사용자 체험(user experience)을 제공했고 나아가 프로그래밍이 가능한 플렉스로 발전했다. 그러나 플렉스가 리치 인터넷 애플리케이션(Rich Internet Application, RIA)이라고 스스로 말하고 있듯이, 웹 브라우저 내에서 실행되는 특성 탓에 웹이라는 태생적인 한계는 벗어나지 못하고 있는 것 같다.

또한 웹2.0을 구현할 기술의 하나로 주목받고 있는 AJAX(Asynchronous JavaScript and XML) 역시 기존의 웹과 HTML이 지닌 웹 엔트로피 과다 생산의 문제점을 보완하기 위해 생겨난 하나의 웹 기술에 불과하다. 이러한 상황에서 이클립스 리치 클라이언트 플랫폼(Rich Client Platform, RCP)은 신선한 충격으로 다가왔다. 다중 크로스 플랫폼 환경에서 성공적으로 상호작용하는 비즈니스 애플리케이션 생성에 필요한 모든 요구사항들을 충분히 만족시키고 있다고 생각한다. 물론, 웹 애플리케이션은 여전히 큰 장점을 갖추고 있고 AJAX나 웹2.0 등의 기술과 함께 진일보하고 있다. 동시에 리치 클라이언트 애플리케이션은 일부 애플리케이션에 훨씬 더 부합한다. 그 예로, 은행 창구(Bank Teller) 애플리케이션이나 콜센터(Call Center) 애플리케이션 등을 꼽을 수 있다. 이 경우의 애플리케이션들은 일반적으로 다음과 같은 특징을 지닌다.

- 대부분 수 백, 수 천명의 사용자들을 타깃으로 한 내부 인트라넷 애플리케이션이다.
- 폰트, 컬러, 위젯 등 UI에 대한 엄격한 룩앤필 요구사항이 적용된다.
- 파워유저가 사용하는 것이므로 단축키를 사용한 빠른 반응을 필요로 한다.
- 매우 큰 데이터 세트를 가지고 있고 스크린에 많은 정보를 디스플레이 한다. 클라이언트 측에 큰 세션 데이터를 관리하여 퍼포먼스를 높인다.
- 데스크탑 및 다른 데스크탑 애플리케이션과 통합한다.
- 일반적으로 워크플로우 유형 또는 협업 유형의 애플리케이션이고 오프라인에서 작업할 수 있는 기능과 태스크 변환 기능이 매우 중요하다.

이 세상에서 인간이 만든 그 어떤 것도 완벽할 수는 없다. 따라서 지금부터는 리치 클라이언트와 씬 클라이언트가 서로의 역할을 명확히 구분하고, 서로를 존중하며 공존해야 할 것이다.



리치 클라이언트 플랫폼

자바를 잘 알지 못하는 주변의 친구들이나 혹은 함께 작업하는 이들에게 이클립스 IDE 프로그램을 보여주고, 그것이 어떤 언어로 개발되었다고 생각하는 지를 물어보길 바란다. 아마 대부분의 사람들은 VB(비주얼 베이직), C++, 혹은 C# 등의 언어로 개발되었다고 답할 것이다. 이들에게 이클립스는 자바로 개발된 애플리케이션임을 알려주면 대다수가 무척 놀랄 것이다.

이 는 자바를 잘 모르는 이들에게만 해당되는 반응은 아니다. 이클립스가 제공하는 리치 클라이언트 플랫폼을 써서 VB, C++, C#, 델파이 등을 이용해 개발한 것과 동일한 윈도우 프로그램을 개발할 수 있고, 더군다나 그 윈도우 프로그램을 윈도우, 리눅스, 맥 OSX 등에서 아무런 변경 없이 실행할 수 있다고 말한다면 자바를 충분히 알고 있는 독자들도 별반 다르지 않은 반응을 보일 것이다.

● 이클립스 RCP

물론 이클립스가 처음부터 그랬던 것은 아니다. 이클립스는 2001년 11월 7일 공식적으로 오픈 프로젝트가 된 후, 2002년 6월 처음으로 2.0 버전을 릴리즈했다. 가장 최근에는 2005년 11월에 3.2 M3 버전이 릴리즈되었다 (http://www.eclipse.org/ community/news/whatsnewhistory.html). 지난 몇 년 동안 이클립스 프로젝트는 극적으로 성장했고, 그 결과 강력한 개발 환경으로 성숙했다. 대다수의 독자들은 이클립스를 단순한 통합 개발 환경(IDE)으로 여길지 모르지만, 이클립스 3.0 버전 이후부터는 더 이상 단순한 IDE가 아니라 소프트웨어 라이프사이클 전반에 걸친 개발 플랫폼으로 자리매김하고 있다.

또한 이클립스 3.0에 와서는 비로소 이클립스 UI의 근간이 되는 핵심 기능들을 비IDE 애플리케이션에서도 쉽게 사용할 수 있도록 리팩토링 한 리치 클라이언트 플랫폼이라는 개념도 소개했다. 개발자들은 비즈니스 애플리케이션을 개발할 때 이클립스 플러그인 아키텍처에 기반해 이클립스 RCP가 제공하는 많은 고급 기능들(플랫폼 독립적인 네이티브 GUI 컴포넌트와 네이티브 룩앤필, 풍부한 사용자 인터페이스, 헬프 시스템 등)을 사용할 수 있게 되었다.

이처럼 많은 이클립스의 기능들은 이클립스 RCP라는 이름으로 비즈니스 애플리케이션 개발에 필요한 공통 프레임워크로 사용되었다. 이로써 개발자들은 코어 컴포넌트 셋을 만들기 위해 시간을 낭비하는 대신에, 각자가 만들고자 하는 애플리케이션의 요구사항 분석이나 실제 개발에 더 많은 시간과 정열을 쏟을 수 있게 되었다. 이클립스의 주요 컴포넌트와 이중에서 이클립스 RCP로 패키징된 컴포넌트들의 구성도를 살펴보면 <그림 1>과 같다.


<그림 1> 이클립스 아키텍처와 이클립스 RCP 구성 컴포넌트

이클립스를 구성하는 전체 컴포넌트 중에서 이클립스 RCP의 기본 구성 컴포넌트를 골라 제시하고 있는데, 그 각각을 살펴보면 다음과 같다.

- UI 워크벤치(Workbench) : 에디터(editors), 뷰(views), 퍼스펙티브(perspectives) 등으로 구성된 UI 워크벤치를 제공한다.
- SWT(Standard Widget Toolkit) : SWT는 운영체제의 네이티브 윈도우 환경과 긴밀하게 통합된 다양한 컴포넌트와 플랫폼 독립적인 API를 제공한다. SWT는 자바 개발자들로 하여금 네이티브 데스크탑 애플리케이션과 동일한 품질의 솔루션을 개발할 수 있게 해준다.
- JFace : JFace는 SWT를 이용해 사용자 인터페이스를 개발할 때 해야 하는 많은 공통 작업들을 간편화 해주는 컴포넌트와 헬퍼 유틸리티 셋을 제공한다. 데이터 뷰, 위자드, 다이얼로그 컴포넌트, 텍스트 관리, 이미지 및 폰트 컴포넌트 등을 제공하기 위해 SWT를 확장하는 많은 유틸리티 클래스들을 포함하고 있다.
- 플랫폼 런타임 : 플러그인과 JIT 레이지 로딩(just-in-time lazy loading) 및 초기화 간에 확장 포인트(extension-point) 모델 기반의 느슨한 결합을 정의하고 있다.
- OSGi(Open Services Gateway Initiative) : 플러그인 라이프사이클 관리 등을 위한 프레임워크이다. 이클립스에서의 플러그인 발견이나 애플리케이션의 재시작 없이 플러그인을 로딩 및 언로딩 하는 동작이 이에 해당된다.



리치 클라이언트 애플리케이션

지금부터는 이클립스 RCP를 써서 개발한 대표적인 리치 클라이언트 애플리케이션을 소개한다. 데모를 다운로드 하기 위한 사이트 주소는 다음과 같다.

http://udig.refractions.net/confluence/display/UDIG/Home

이 사이트에서 데모를 다운로드 해 실행하면, 애플리케이션에서 제공하는 사용자 인터페이스가 이클립스와 별반 다르지 않음을 알 수 있다. <화면 1>에 나타난 모습과 여러분이 현재 사용하고 있는 이클립스를 비교해보길 바란다.


<화면 1> 이클립스 RCP를 이용한 리치 클라이언트 애플리케이션(uDig)

상 단의 메뉴바와 툴바, 왼쪽의 프로젝트와 레이어 탐색기, 컨텐츠 편집기, 그리고 하단의 몇 개 탭으로 구성된 메시지 또는 상태 창 등이 이클립스의 UI와 무척 흡사한 것을 알 수 있다. 게다가 ‘Window’ 및 ‘Help’ 메뉴는 이클립스와 완전히 동일하다. <화면 1>에서 보여주고 있는 uDig(User-friendly Desktop Internet GIS) 프로젝트는 GeoSpatial 애플리케이션이자, 개발자들이 새롭게 혹은 상속해서 애플리케이션을 생성할 수 있는 플랫폼이다. uDig는 인터넷에서 인식할 수 있는 GIS(Geographic Information System)의 핵심 엘리먼트다. uDig와 같은 리치 클라이언트의 특징은 다음과 같다.

- 사용자 편의성을 높인 풍부한 사용자 체험(rich user experience) 제공
- 플랫폼 독립(윈도우, 리눅스, 맥 OSX 등의 운영체제와 무관하게 실행)
- 하부 운영체제의 네이티브 위젯을 사용함으로써 네이티브 룩앤필 제공
- 드래그 & 드롭 기능과 같은 고급 사용자 인터페이스 제공
- 통합된 업데이트 방식 제공
- 확장성 제공



이클립스 플러그인 아키텍처

이클립스의 전신이 IBM의 비주얼 에이지 포 자바(Visual Age for Java)였기 때문에, 이클립스는 플랫폼을 쉽게 확장할 수 있도록 만들어졌다. <그림 2>는 이클립스 플러그인 아키텍처의 주요 컴포넌트들을 보여주고 있는데, 이클립스 RCP의 핵심은 바로 이클립스 워크벤치, SWT, JFace, 헬프 컴포넌트 등이다.


<그림 2> 이클립스 플러그인 아키텍처

이 클립스 플랫폼 런타임을 구성하는 기본 파일들을 제외하면, 이클립스의 모든 기능들은 플러그인을 사용해 구현된다. 플러그인은 개발자들이 이클립스 환경에 새로운 기능과 동작을 추가하기 위해 사용할 수 있는 기본 빌딩 블록이라고 볼 수 있다. 따라서 이클립스 플랫폼 런타임은 워크벤치 내에서 플러그인의 라이프사이클을 관리하는 책임을 지닌다. 이클립스 RCP를 이용하여 개발한 리치 클라이언트 애플리케이션에서 사용하는 모든 플러그인들은 애플리케이션의 디렉토리 구조 내에 있는 plugin 폴더 내에 존재한다. 리치 클라이언트 애플리케이션의 실행 시에 이클립스 런타임은 모든 사용가능한 플러그인을 찾아내고 전역 플러그인 레지스트리를 생성하기 위해 이 정보를 사용한다.

따라서 이클립스 RCP를 이용하여 리치 클라이언트 애플리케이션을 개발하고자 한다면, 메인 프로그램으로서 이클립스 RCP에서 실행될 수 있는 플러그인을 생성해야 한다. 이클립스는 플러그인 개발을 쉽게 할 수 있도록 플러그인 개발환경(Plug-in Development Environment, PDE)도 제공하고 있다. 이클립스 PDE에는 플러그인 개발 과정을 단순화시켜주는 다양한 위자드(Wizard)와 에디터(Editor)들이 포함되어 있다. 따라서 이클립스 SDK에 기본적으로 내장된 PDE를 사용하면 이클립스 RCP를 이용하는 리치 클라이언트 애플리케이션을 더 쉽고 빠르게 개발할 수 있다. <화면 2>는 이클립스 PDE의 실행 화면이다. 이클립스 RCP나 PDE를 이용해 리치 클라이언트 애플리케이션을 개발하는 방법은 이 글이 의도하는 바가 아니라 여기서는 다루지 않기로 한다.


<화면 2> 이클립스 PDE

이클립스 RCP를 이용한 리치 클라이언트 애플리케이션의 개발에 대해서는 마소가 향후에 별도 지면을 통해 연재해주길 기대한다.



플러그인 vs. 제품

이클립스 RCP를 이용해 리치 클라이언트를 개발하고 배포하는 방법에는 두 가지가 있다. 앞에서 이미 언급했듯이 이클립스 RCP는 플러그인 아키텍처에 기반하고 있다. 따라서 이클립스 RCP를 이용해 개발한 리치 클라이언트 애플리케이션은 기본적으로 이클립스의 플러그인처럼 실행된다. 소프트웨어 라이프사이클을 위한 다양한 툴을 개발해 판매하는 것이 목적이라면 이클립스 내에서 플러그인 형태로 실행되더라도 아무런 문제가 없을 것이다. 그러나 회사에 따라서는 서버를 모니터링 하는 리치 클라이언트(윈도우 프로그램)를 만들어 상용화해야 하거나, 또는 콜센터나 일정관리의 경우처럼 이클립스 없이 실행되는 독립(stand-alone) 애플리케이션의 형태로 배포해야 할 수도 있다. 그럼 이런 경우에는 어떻게 해야 할까?

이런 문제에 대비해 이클립스 RCP를 이용해 개발한 리치 클라이언트 애플리케이션은 플러그인이나 독립 애플리케이션(product) 형태로 만들어져 배포될 수 있도록 하고 있다. 이런 두 가지 형태로 배포되는 대표적인 프로그램으로 Adobe사의 ‘플렉스 빌더’를 꼽을 수 있다. <화면 3>과 <화면 4>에서 차례로 소개되는 실행 화면은 각각 플렉스 빌더를 이클립스 플러그인 형태로 설치해 실행한 경우와 독립(stand-alone) 애플리케이션으로 설치해 실행한 경우이다.


<화면 3> 이클립스 플러그인으로 실행한 플레스 빌더


<화면 4> 독립 애플리케이션으로 실행한 플렉스 빌더

< 화면 3>과 <화면 4>가 보여주고 있는 플렉스 빌더의 실행 화면은 서로 별반 다를 게 없어 보인다. 그도 그럴 것이 두 가지 모두 이클립스 RCP를 이용해 개발되었고, 또한 이클립스 RCP의 런타임 환경에서 실행되기 때문이다. 그렇다면 대체 어떤 차이가 있는 것일까? 그렇다. 바로 플러그인(plug-in)과 제품(product)의 차이인 것이다. 지금까지 필자가 독립 애플리케이션(또는 stand-alone 애플리케이션)이라고 부르던 것을 이클립스 RCP에서는 제품이라고 부르고 있는 것이다. 이는 이클립스 RCP 입장에서 볼 때 이클립스 IDE 내에서 실행되는 플러그인이 아니라, 이클립스 IDE와는 별개로 배포되는 제품이라고 생각했기 때문일 것이다. 결국 이 두 화면이 보여주고 있는 것처럼 플러그인이나 제품의 형태로 실행되더라도 모두가 이클립스 RCP 상에서 실행되므로 그 외관상에는 큰 차이가 없다.

그러나 동작의 측면에서 볼 때 아주 큰 차이점이 있다. 플러그인은 이클립스 IDE 내에서 실행되므로 이클립스 IDE의 모든 기능과 퍼스펙티브를 사용할 수 있는 반면에, 제품 형태로 실행되는 경우에는 이클립스 RCP에서 정의하고 있는 기능만 쓸 수 있을 뿐 이클립스의 IDE적인 기능들은 사용할 수 없다는 점이다. 따라서 전체 화면 구성에서 볼 때 둘 모두가 플렉스 퍼스펙티브를 사용하고 있어 거의 동일하지만, 두 개의 실행화면을 자세히 살펴보면 메뉴, 툴바, 사용 가능한 퍼스펙티브 등의 유무에서 다소 차이가 있음을 알 수 있다.

이렇 듯, 이클립스는 이클립스 RCP를 이용해 개발한 리치 클라이언트 애플리케이션을 독립 실행이 가능한 프로그램 형태로 배포할 수 있는 제품(product)의 개념을 지원한다. 이클립스 RCP를 이용해 생성된 제품은 자신이 필요로 하는 다른 플러그인들을 모두 포함하고, 애플리케이션을 실행하기 위한 네이티브 실행 파일(launcher program)과 환경구성 파일(config files) 등을 생성해 포함한다. 또한 실행 윈도우의 타이틀과 여러 윈도우 및 데스크탑 아이콘, 프로그램 시작 화면(Splash Screen), 프로그램 실행 파일의 이름, 어바웃 다이얼로그 정보 등을 변경할 수 있는데, 이를 브랜딩이라 한다. 이렇게 생성한 제품은 InstallShield, NSIS, 인스톨 팩토리 등과 같은 유틸리티 프로그램을 써서 인스톨 프로그램으로 만들고 배포할 수 있다.



이클립스 SWT와 JFace

이클립스 SWT(Standard Widget Toolkit)는 JFace와 함께 다중 플랫폼에서 네이티브 리치 클라이언트 애플리케이션을 개발하기 위한 이클립스의 대표적인 컴포넌트로 일종의 라이브러리이다. 또한 이는 이클립스 RCP의 풍부한 사용자 경험을 제공하기 위한 핵심 컴포넌트라고 할 수 있다. 비록, SWT와 JFace가 같은 목적을 지녔다고는 하지만, 이 두 가지 기술은 사용자 인터페이스를 생성하는 데 있어서 다음과 같이 다른 철학을 가졌다.

먼저 SWT는 시스템 내부 자원에 대한 풍부한 제어와 액세스가 가능하도록 지원하지만, 개발자가 모든 고급 UI 작업을 해주어야 하므로 사용하기가 복잡하다. 반면에 JFace는 모든 GUI 작업을 자동으로 하지만, JFace에서 제공되는 GUI 컴포넌트를 사용해야 하므로 유연성(flexibility)이 부족하다고 할 수 있다.

즉, 이클립스 SWT에서는 GUI 프로그래밍을 위한 풍부한 컴포넌트들을 제공하고, JFace에서는 SWT에서 제공하는 기본 컴포넌트들을 조합해 복잡한 형태의 GUI(즉 마법사 형태의 컴포넌트)를 제공하므로, 두 가지 기술을 적절히 조합해 사용하는 것이 바람직하다(이클립스 SWT에 대한 보다 자세한 내용은 필자가 2006년 9월부터 12월까지 마소에 기고한 이클립스 SWT 관련 연재를 참고하길 바란다).

이클립스 SWT를 이용한 GUI 개발

모든 운영체제는 기본적인 사용자 인터페이스를 개발할 수 있는 수많은 그래픽 컴포넌트를 제공한다. 이러한 그래픽 컴포넌트에는 버튼, 윈도우, 메뉴를 비롯해 모니터 스크린에 나타나는 다른 모든 그래픽 컴포넌트들까지 포함된다.

SWT 의 목적은 자바 프로그래머가 이러한 컴포넌트를 직접 액세스할 수 있게 함으로써 그러한 컴포넌트들을 원하는 대로 구성 및 위치시키고, 이를 통해 GUI 화면을 개발할 수 있도록 하는 것이다. 이클립스 SWT를 이용해 애플리케이션에 SWT 버튼 객체를 사용하는 프로그램을 작성했다면, MS 윈도우 환경에서 실행될 때는 윈도우의 버튼처럼, 매킨토시에서는 매킨토시의 그것처럼 나타난다. 마찬가지로 리눅스나 유닉스 등에서도 그 각각의 버튼처럼 나타나고 동작한다. 이러한 그래픽 컴포넌트와 함께 SWT는 이벤트에 대한 액세스도 제공한다. 이는 사용자가 어떤 버튼을 클릭했고, 어떤 메뉴 아이템이 선택되었는지를 알 수 있게 한다(모든 형태의 사용자 입력 처리 가능). 마지막으로 애플리케이션에서 그래픽스 작업을 해야 하는 경우를 살펴보자. 이 경우에는 SWT가 이미지 생성과 폰트 이용, 그리고 다양한 도형 표현을 위한 방대한 그래픽 툴셋을 제공한다. 이러한 기능은 새로운 그래픽 작업이 가능하도록 할 뿐만 아니라 GUI 내에 언제, 어느 곳에, 어떻게 디스플레이할 지를 제어하도록 지원한다.

이처럼 SWT는 사용자 인터페이스를 생성하는 데 필요한 풍부한 기능들을 제공하지만, 모든 GUI 작업을 개발자가 직접 해야 하므로 프로그램이 길고 복잡해질 수 있다. 이런 까닭에 이클립스는 GUI 개발을 지원하는 복잡한 컴포넌트들을 만들어 JFace라는 이름의 라이브러리로 제공하게 되었다.



이클리스 JFace를 이용한 GUI 개발 단순화

동일한 SWT 코드를 반복 작성하는 수고를 줄여 이를 보다 간편화할 수 있도록 등장한 것이 바로 JFace이다. JFace는 SWT만을 이용해 작업할 때 많은 시간을 소모할 수 있는 다수의 작업들을 간단히 수행할 수 있도록 돕는다. 그러나 JFace가 단순히 SWT를 대체하는 것은 아니다. 대부분의 GUI 프로그램은 SWT와 JFace 두 가지 기능을 적절히 사용해야만 보다 나은 효과를 얻을 수 있다.

JFace의 중요한 예로 이벤트를 꼽을 수 있다. 일반적인 사용자 인터페이스에서는 버튼을 클릭했거나, 키를 눌렀거나, 혹은 메뉴가 선택되는 등의 서로 다른 이벤트를 받을 수 있고, 이 이벤트는 모두 똑같은 기능을 수행해야 한다. 이런 과정을 수행하는 데도 SWT와 JFace 간에는 차이가 있다. 먼저 SWT에서 각 이벤트는 별도로 받아 처리해야 한다. 그러나 JFace는 이 이벤트들을 하나의 객체로 조합해 그 이벤트를 발생시킨 컴포넌트보다 이벤트에 대해 어떤 응답을 할지 자체에 더 많은 관심을 가지도록 해준다. 이런 간단하면서도 강력한 개념 덕분으로 GUI 프로그램에 많은 양의 코드를 작성하지 않더라도 컨텍스트 메뉴, 툴바, 그리고 팔레트 등을 추가할 수 있는 것이다.

JFace 는 이뿐만 아니라 다중 윈도우나 그래픽스를 필요로 하는 방대한 GUI 프로그램을 개발하는 데도 매우 유용하다. SWT 컴포넌트들을 조직하고 컴포넌트들이 사용하는 메모리 할당(allocation)을 도와주는 레지스트리 클래스들도 제공한다. 예를 들면 SWT에서 애플리케이션이 사용할 많은 폰트와 이미지를 생성 및 해제(deallocate)하는 경우가 이에 해당한다. JFace를 이용하면 이런 지루한 작업을 대신하기 위해 빌트인 FontRegistry나 ImageRegistry 객체를 사용할 수 있다.



참고 자료
1. http://udig.refractions.net/confluence/display/UDIG/Home, 이클립스 RCP UDIG 프로젝트
2. http://www.foreflight.com/, 이클립스 RCP ForeFlight 프로젝트
3. http://www.eclipse.org/community/casestudies/RSSfinal.pdf, 이클립스 RCP RSS Solutions 프로젝트
4. http://www.eclipse.org/community/ casestudies/NASAfinal.pdf, 이클립스 RCP Maestro (NASA Space Mission Management)
5. http://www.zdnet.co.kr/builder/dev/java/0,39031622,39139542,00.htm, EJB와 리치 클라이언트 구축
6. http://www.eclipse.org/articles/Article-RCP-1/tutorial1.html, Rich Client Tutorial Part 1
7. http://wiki.eclipse.org/index.php/Rich_Client_Platform, Eclipse Rich Client Platform



제공 : DB포탈사이트 DBguide.net


'Dev > eclipse' 카테고리의 다른 글

이클립스 단축키  (0) 2011.04.30
이클립스 자동 가비지 컬렉션 플러그인  (0) 2011.04.30
이클립스 속도 올리기  (0) 2011.04.29
Boost Eclipse speed performances  (1) 2011.04.29

1. 데몬(daemon) 이란?
주기적인 서비스 요청을 처리하기 위해서 커널상에 백그라운드 모드로 실행되는 프로세스로, 메모리 관리 방법에 따라 단독 데몬과 xinetd로 분리된다.

  • 단독데몬
    항상 백그라운드 모드로 실행되고 메모리를 상대적으로 많이 소비한다. 그러나 서비스(응답속도)가 빠르다. httpd와 같은 웹서비스 데몬이 대표적.
  • xinetd(슈퍼데몬)
    요청이 있을때마다 xinetd가 서비스를 싱행시켜주므로 메모리 소비가 적다. 그러나 단독데몬에 비해 상대적으로 서비스 속도가 느리다.


2. 간단한 자바 데몬 만들기
nohup을 이용해서 java를 실행시킨다.

터미널이 종료될 때(쉘이 종료될 때) 프로세스가 죽는 이유는 해당 프로세스가 쉘의 자식 프로세스 이기 때문이다. 따라서, 부모 프로세스가 죽을대 던지는 SIGHUP을 자식 프로세스가 받게 된다.

nohup은 부모 프로세스가 죽을때 자식 프로세스에게 SIGHUP을 던지지 않는 프로세스를 말한다.

$ nohup java 클래스명 & 
 
사용하기 편한 장점은 있으나, 문제는 중지를 시킬수 없다. 즉, 해당 프로세스 ID를 찾아내 kill하는 수 밖에 없다. 물론 파일 체크 기법, 소켓을 이용한 제어 방법등을 사용할 수 있지만 스스로 구현해야 하는 번거로움이 있다.


3. apache commons daemon 이용하기
Java는 UNIX의 시그널 처리를 할수 없기때문에, 중지 신호(TERM signal)를 처리하기 위해서는 따로 구현을 해야한다. 이런 번거로움을 해결하기 위해 자카르타의 하위 프로젝트중의 commons daemon을 이용한다. commons daemon은 중지 신호를 받으면 미리 지정된 메소드를 실행한다.


UNIX용 Jsvc와 윈도우용 Procrun 있다.
여기서는 Jsvc를 이용해보도록 하겠다.


commons daemon을 다운로드해 압축을 해제하면 위 그림과 같다.
commons-daemon.jar 파일은 Java프로젝트 lib폴더에 복사해둔다.


bin폴더의 압축파일을 해제하면 jsvc-src라는 폴더가 나온다.
폴더의 내용은 위와 같다.
commons daemon을 사용하기 위해서는 바로 여기서 jsvc를 빌드해줘야 한다.
빌드환경은 다음과 같다.(리눅스에서 빌드해야한다.)

  • GNU AutoConf(at least 2.53)
  • ANSI-C compliant compiler(GCC is good)
  • GNU Make
  • A Java Platform 2 compliant SDK

여기서부터는 ubuntu 8.10 환경에서 진행하도록 한다.

먼저 JDK가 설치되어 있지 않다면 JDK를 설치한다.

 $ sudo apt-get install sun-java6-jdk

JDK가 설치되는 경로는 /usr/lib/jvm/java-6-sun 이다.

gcc 및 make 가 설치되있지 않다면 아래 명령를 이용해 한방에 설치한다.

 $ sudo apt-get install build-essential

AutoConf가 설치되있지 않다면 AutoConf를 설치한다.

 $ sudo apt-get install autoconf

Jsvc를 빌드하는 방법은 다음과 같다.

  • support/buildconf.sh
  • ./configure --with-java=/usr/lib/jvm/java-6-sun
  • make


빌드가 성공적으로 이루어졌다면 위 그림과 같이 jsvc가 만들어진것을 확인할 수 있다. 이후 이 파일을 가지고 Java 데몬을 실행한다.

Java 데몬을 만들려면 org.apache.commons.daemon.Daemon 인터페이스의 init, start, stop, destory 메소드를 구현해야 한다.

샘플 코드는 아래와 같다.
  1. import org.apache.commons.daemon.Daemon;   
  2. import org.apache.commons.daemon.DaemonContext;   
  3.   
  4. public class DaemonTest implements Daemon {   
  5.   
  6.     Thread t = null;   
  7.        
  8.     @Override  
  9.     public void init(DaemonContext arg0) throws Exception {   
  10.         System.err.println("daemonTest init");   
  11.         t = new DaemonThread();   
  12.     }   
  13.   
  14.     @Override  
  15.     public void start() throws Exception {   
  16.         System.err.println("daemonTest start");   
  17.         t.start();   
  18.     }   
  19.   
  20.     @Override  
  21.     public void stop() throws Exception {   
  22.         System.err.println("daemonTest stop");   
  23.         t.interrupt();   
  24.     }   
  25.        
  26.     @Override  
  27.     public void destroy() {   
  28.         System.err.println("daemonTest destroy");   
  29.     }   
  30. }  
  1. public class DaemonThread extends Thread {   
  2.   
  3.     @Override  
  4.     public void run() {   
  5.         while( Thread.interrupted() ) {   
  6.             System.err.println("run");   
  7.             try {   
  8.                 Thread.sleep(5000);   
  9.             } catch (InterruptedException e) {   
  10.                 Thread.currentThread().interrupt();   
  11.                 return;   
  12.             }   
  13.         }   
  14.     }      
  15. }  
init에서 초기화, start에서 처리할 작업을 별도의 쓰레드로 생성해서 실행한다. start 메소드 호출후 반드시 return 되어야 데몬이 시그널 처리를 제대로 할 수 있다.
stop, destroy 는 중지 신호가 오면 차례되로 호출된다.

이제 실행/중지 스크립트를 작성한다.
Jsvc를 싱행하는데 필요한것은 실행하는 계정(user), JAVA_HOME(-home), 프로세스ID 파일(-pidfile), 출력지정(-outfile, -errfile), 클래스파일(-cp) 등이 있다.
  1. #!/bin/sh   
  2. JAVA_HOME=/usr/lib/jvm/java-6-sun   
  3. DAEMON_HOME=/home/lyb1495/commons-daemon-1.0.1/bin/jsvc-src   
  4. DAEMON_USER=lyb1495   
  5. DAEMONTEST_HOME=/home/lyb1495/workspace/Daemon   
  6. PID_FILE=$DAEMONTEST_HOME/daemon_test.pid   
  7.   
  8. CLASSPATH=\   
  9. $DAEMONTEST_HOME/bin:\   
  10. $DAEMONTEST_HOME/lib/commons-daemon.jar   
  11.   
  12. case "$1" in   
  13.   
  14.     start)   
  15.     #   
  16.     # Start Daemon   
  17.     #   
  18.     $DAEMON_HOME/jsvc \   
  19.     -user $DAEMON_USER \   
  20.     -home $JAVA_HOME \   
  21.     -wait 10 \   
  22.     -pidfile $PID_FILE \   
  23. -errfile '&1' \   
  24.     -cp $CLASSPATH \   
  25.     DaemonTest   
  26.     #   
  27.     # To get a verbose JVM   
  28.     #-verbose \   
  29.     # To get a debug of jsvc.   
  30.     #-debug \   
  31.     exit $?   
  32.     ;;   
  33.   
  34.   stop)   
  35.     #   
  36.     # Stop PostMan   
  37.     #   
  38.     $DAEMON_HOME/jsvc \   
  39.     -stop \   
  40.     -pidfile $PID_FILE \   
  41.     DaemonTest   
  42.     exit $?   
  43.     ;;   
  44. #   
  45.   *)   
  46.     echo "Usage DaemonTest.sh start/stop"  
  47.     exit 1;;   
  48. esac  
이제 Java 데몬을 실행하기 위한 모든 준비를 마쳤다.


위에서 작성한 스크립트 파일을 이용해 Java 데몬을 실핸한다.
정상적으로 데몬이 시작된다면 PID_FILE에 지정한 파일이 생성된것을 확인할 수 있다.


데몬을 중지하려면 start 대신 stop을 입력으로 스크립트를 실행하면 된다.

'Dev > JAVA' 카테고리의 다른 글

Spring framework 설치  (0) 2012.11.25
Java Simple Daemon  (0) 2011.06.05
자바 이미지 사이즈 추출 예제  (0) 2011.04.23
자바 이미지 리사이즈(썸네일)  (0) 2011.04.06

+ Recent posts