레이블이 Database인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Database인 게시물을 표시합니다. 모든 게시물 표시

2016년 7월 14일 목요일

NoSQL과 MongoDB의 기본 개념

 안녕하세요? 김성중입니다.

 거의 모든 웹 앱은 정보를 (영속적으로) 유지하기 위해 데이터베이스에 의존합니다. 여기서 데이터베이스는 주로 관계형이거나 NoSQL입니다. NoSQL 데이터베이스는 이름이 의미하듯 SQL을 사용하지 않으며, 쉬운 사용법과 빠른 속도 덕분에 최근에 많이 사용되고 있습니다. NoSQL 데이터베이스는 문서 저장소, 객체 저장소, Key-Value 저장소로 구분할 수 있고, Redis, Memcached, Cassandra, MongoDB, Couchbase 등이 있습니다. NoSQL 데이터베이스가 일반적으로 관계형 데이터베이스보다 더 빠른 이유는 엄격한 데이터 일관성을 강제하거나 정해진 스키마를 따르지 않기 때문입니다.

 MongoDB란?

 몽고디비는 NoSQL 데이터베이스의 Document 저장소로 분류됩니다. 몽고디비는 데이터를 BSON(Binary JSON) 형태의 문서로 저장합니다. JSON을 기본 형식으로 사용하기 때문에 자바스크립트 앱을 위해 간편하고 편리한 인터페이스를 제공합니다. 몽고디비는 또한 상호 대화식 Shell, 데이터 불러오기/내보내기, 통계 보고용 앱과 같은 여러 도구도 함께 설치하여 사용할 수 있습니다.

 MongoDB 명령어

 몽고디비를 지역적으로 사용하려면 먼저 몽고디비 데몬인 mongod를 시작해야 합니다. mongod는 mongo 명령에서 비롯된 연결을 받아들입니다. 기본적으로 mongo는 localhost의 포트 27017에 연결을 시도하지만, --port와 --host 플래그를 사용해서 다르게 구성할 수 있습니다. 


 mongo로 몽고디비에 연결하면 아래 그림처럼 db 명령을 사용해서 현재 데이터베이스 이름을 볼 수 있습니다. 디폴트로 설정된 test 데이터베이스에 연결된 것이 보이시죠?


 다른 데이터베이스로 변경하려면 use 명령 뒤에 전환하고 싶은 데이터베이스 이름을 붙이면 됩니다. 예를 들어, yamiyami 데이터베이스로 전환하려면 다음과 같은 명령을 내립니다. 이 명령은 아직 yamiyami 데이터베이스를 생성하지 않았음에도 불구하고 동작합니다.



 새로운 데이터 삽입

 db는 현재 DB 이름을 출력하는 기능뿐만 아니라 데이터를 조작할 수 있는 DB의 최상위 객체이기도 합니다. 예를 들어 yamiyami 디비에 'sungjung'을 추가하고 싶다면, 먼저 `use yamiyami` 명령을 내려 yamiyami 디비로 전환합니다. 그 다음 아래 그림처럼 `sungjung`을 삽입합니다. 이 명령은 객체 {name:sungjung`}을 yamiyami 디비의 people 컬렉션에 추가합니다. yamiyami 디비는 아직 존재하지 않지만, 몽고디비는 이 디비를 바로 생성해 줍니다. 또한 show dbs와 show collections 명령을 사용해서 현재 yamiyami 디비와 people 컬렉션이 존재하는지 확인할 수 있습니다.


 또한, 아래와 같이 객체 배열을 전달하는 방법을 사용하면 insert() 호출 하나로 여러 항목을 추가할 수 있습니다.



 데이터 검색

 데이터를 디비에 추가했으므로 다시 읽을 수단이 필요합니다. 이를 위해 컬렉션의 find() 함수를 사용하면 됩니다. 아래 그림은 yamiyami 디비에서 컬렉션의 모든 항목을 검색한 결과입니다. 검색 결과에 보이는 _id 필드는 몽고디비에서 부여하는 객체에 대한 유일한 식별자입니다.


 아래 예제는 이름이 'sungjung'인 데이터를 검색하는 방법입니다. 검색 기준으로 name 필드에 /^sungjung/ (sungjung로 시작하는 문자열)이라는 정규표현식을 사용하였습니다. 더 정확한 질의를 원한다면 `db.people.find({name: 'sungjung}) 을 사용할 수 있습니다.



 데이터 갱신

 데이터는 컬렉션의 update() 함수를 사용해서 갱신합니다. 
  • @param1 : 질의 객체. 이 객체는 갱신해야 할 항목을 명시하여 find()와 동일 한 구문으로 사용
  • @param2 : 갱신되어야 하는 값.
  • @param3 : 옵션 객체.
  • 옵션1 - upsert : 값이 true로 설정될 경우, update()는 질의 기준에 맞는 기존 항목이 없을 경우 새로운 문서를 생성한다.(default: false)
  • 옵션2 - multi : 값이 true로 설정될 경우, updates()는 질의 기준과 일치하는 모든 문서를 변경한다.(default: false)
  • 옵션3 - writeConcern : 갱신의 쓰기 동작 방식을 정의.
 아래 명령어를 통해 'sungjung'은 'jeremy'로 바꼈고, 나이를 명시하기 위해 문서에 age라는 새로운 필드도 추가했습니다. 이는 RDB와 비교해서 NoSQL의 유연성을 보여주는 예임. 실행 시점에 NoSQL 디비는 개별 데이터에 새로운 필드를 정의할 수 있어요. 
 


 데이터 삭제

 마지막 CRUD 연산은 삭제입니다. remove() 함수를 사용하면 컬렉션에서 데이터를 삭제할 수 있습니다. 
  • @param1 : find() 형태의 질의 객체.
  • @param2 : 옵션 객체
  • 옵션1 - justOne : true로 설정하면 삭제가 하나의 문서로 제한된다.(default: false)
  • 옵션2 - writeConcern : update()의 writeConcern과 동일한 방식.
 아래 명령어를 통해 이름이 'sungjung'인 사람 중 한 명을 삭제하였습니다. name 필드가 'sungjung'인 데이터가 여러개 임에도 불구하고 한 명만 삭제되었습니다.



 컬렉션 삭제

 컬렉션의 drop() 함수를 사용해서 디비에서 전체 컬렉션을 삭제할 수 있습니다. 아래 명령어를 통해 yamiyami 디비 안에 있는 people 컬렉션을 삭제하였습니다.


 show collections 명령으로 해당 컬렉션이 더 이상 존재하지 않음을 확인하시면 됩니다.



 데이터베이스 삭제

 dropDatabase() 함수를 사용해서 현재 디비와 여기에 속한 모든 데이터를 삭제할 수 있습니다. 아래 명령어를 통해 yamiyami 디비를 삭제하였습니다.



2016년 7월 6일 수요일

NoSQL과 Couchbase에 대한 가이드

 안녕하세요? 김성중입니다.

 이전 글에서 보셨듯이 야미야미가 만들 모바일 게임 서버에 Node.js를 사용하기로 하였습니다. 처음 만들어보는 게임이고 사용자가 생각보다 많지 않을 수 있지만, 시스템에 대한 설계는 확실히 해야한다고 생각하였습니다. 프로젝트 초기에 확장성을 염두에 두고 시스템을 설계한다면, 추후 유사한 시스템을 설계할 때 매우 유용할 것입니다.

 모바일 게임 서버의 주 역할은 사용자의 요청에 응답을 해주고, 사용자와 관련된 게임 데이터를 관리하는 것입니다. 하지만 이 때, 요청에 따른 상태를 저장하는 구조는 Scalability를 고려하기 힘들 수 있습니다. 이전의 상태가 저장된 특정 인스턴스로 요청이 계속 전달된다면 단순히 AutoScaling을 하여도 트래픽이 골고루 분산되지 않기 때문입니다. 이러한 문제점이 발생하지 않도록 각 인스턴스는 상태가 없는 구조로 Scalability를 고려하여 설계해야 합니다.

 그래서 이번에는 대용량 입출력하면 빼놓을 수 없는 NoSQL, NoSQL 데이터베이스인 Couchbase 그리고 node.js 서버에 활용하는 방법까지 알아보겠습니다. Couchbase에 대해 알아보기 전에 먼저 NoSQL이 무엇이고, RDB와 무엇이 다른지 알아보겠습니다.


 NoSQL(Not Only SQL)은 관계형 데이터베이스가 맞으면 관계형 데이터베이스를, 그렇지 않으면 무리하게 관계형 데이터베이스에 얽매이지 말고 용도에 맞는 데이터 저장소를 사용하자 는 취지에서 시작한 데이터베이스입니다.


 일반적으로 관계형 데이터베이스는 데이터의 일관성을 보증할 수 있고(트랜잭션), 정규화를 전제로 하고 있기 때문에 갱신 시의 비용이 적게 든다, JOIN이나 복잡한 검색 조건으로 검색이 가능하다 등의 장점을 가지고 있지만, 대량의 데이터 입력 처리나 갱신이 발생한 테이블의 인덱스 생성이나 스키마 변경, 단순히 빨리 결과를 내놓아야 하는 상황에서는 약점을 가지고 있습니다.

 대용량 데이터에 대한 입력 처리

 예를 들어, 대용량 데이터 입력을 처리할 때 입력 성능을 높이는 방법으로 마스터를 1대에서 2대 늘려 서로 데이터 복제를 하는 듀얼마스터 구조를 생각할 수 있습니다. 하지만 같은 데이터를 양쪽 마스터가 동시에 서로 다른 값으로 갱신할 경우 문제가 발생할 수 있고, 이를 방지하기 위해 테이블에 매번 쿼리의 발행 대상을 할당시키는 작업을 해야하는데 만만치 않다는 것입니다. 이 외에도 서로 다른 서버에 DB를 분할하여 설치할 수 있는데, 서로 다른 서버에 설치된 테이블 사이에는 JOIN 연산이 불가능하기 때문에, 이러한 부분 또한 일이 복잡해집니다.

 단순히 빠른 결과를 위한 상황

 요즘 관계형 데이터베이스와는 약간 차이가 있는 이야기이지만(실제로 RDB만으로 구성하여 부하를 충분히 견디는 시스템이 많음), 관계형 데이터베이스는 단순히 결과를 빠르게 보여주는 경우에는 어울리지 않습니다. SQL이라는 것 자체가 가져오는 SQL 해석이나 테이블의 Lock/Unlock 과 같은 오버헤드 때문입니다.

 데이터 분산에 용이

 JOIN을 전제로 하며, JOIN을 하기 위해서는 같은 서버 안에 데이터가 존재해야 한다(DB Link 기능을 이용하면 할 수 있긴 함)는 제약이 있는 관계형 데이터베이스와 달리, NoSQL 데이터베이스는 각 데이터가 독립적으로 설계되어 있어 데이터를 여러 서버에 분산시키는 것이 용이합니다. 데이터를 여러 서버에 분산하는 것을 통해, 각 서버에서 다루는 데이터 양이 줄고 대용량 데이터에 대한 처리도 쉬워집니다.


 Couchbase

 Couchbase는 오픈소스이고, 분산 NoSQL 데이터베이스입니다. key-value 형식으로 데이터를 관리하고, 빠른 쿼리를 위해 미리 지정된 인덱서와 SQL과 같은 쿼리를 수행하기 위한 쿼리 엔진이 있습니다. Couchbase 서버는 low-latency 데이터 관리를 제공하는데 특화되어 있어서 규모가 큰 웹, 모바일 그리고 IoT 애플리케이션에 적합합니다. 따라서, 야미야미의 아키텍쳐에 Performance 뿐만 아니라 확장도 용이하도록 Couchbase를 도입하였습니다. (low-latency: 처리에 소요되는 시간을 줄이는 것)