NoSQL
1. 개요
단어 뜻 그 자체를 따지자면 "Not only SQL"로, SQL만을 사용하지 않는 데이터베이스 관리 시스템(DBMS)을 지칭하는 단어이다. 관계형 데이터베이스를 사용하지 않는다는 의미가 아닌, 여러 유형의 데이터베이스를 사용하는 것이다.
데이터를 조직하는 방법에는 리스트, 해시 테이블, 트리, 그래프 등의 다양한 방법이 있고 각각은 장점과 단점이 명확하기 때문에 단순히 NoSQL이라고만 해서는 너무 뜬구름 잡는 얘기가 된다. NoSQL이라는 단어는 RDBMS가 데이터베이스의 독점적인 지위를 차지하고 있는 현재 상황에 반발하는 정신을 담고 있다.
2. 정의
“Not Only SQL” : 데이터를 저장하는 데에는 SQL 외에 다른 방법들도 있다.
NoSQL이라고 하는 말은 No 'English'라고 하는 말과 마찬가지다. 세상에는 영어 말고도 수많은 언어가 존재한다. MongoDB에서 사용하는 쿼리 언어와 CouchDB에서 사용하는 쿼리 언어는 서로 전혀 다르다. 그럼에도 이 두 쿼리 언어는 같은 NoSQL 카테고리에 속한다. 어쨌거나 SQL이 아니기 때문이다. 또한 NoSQL이 No RDBMS를 의미하지는 않는다. BerkeleyDB같은 예외가 있기 때문이다. 그리고 No RDBMS가 NoSQL인 것도 아니다. SQL호환 레이어를 제공하는 KV-store라는 예외가 역시 존재한다. 물론 KV-store의 특징상 range query를 where절에 넣을 수 없으므로 완전한 SQL은 못 되고 SQL의 부분집합 정도를 제공한다.
사실 아직까지 NoSQL에 내려진 구체적인 정의는 없다. 하지만 NoSQL이라 불리는 데이터베이스들은 대체로 다음과 같은 공통적인 성향을 보인다.
- 대부분 클러스터에서 실행할 목적으로 만들어졌기 때문에 관계형 모델을 사용하지 않는다. 그러나 모든 NoSQL 데이터베이스가 클러스터에서 실행되도록 맞춰진 것은 아니다. 예를 들어 NoSQL 데이터 모델 중 하나인 그래프 데이터베이스는 관계형 데이터베이스와 비슷한 분산 모델을 사용한다.
- 오픈 소스이다. 비오픈 소스 프로젝트도 있긴 하지만, 대부분 그렇다.
- 보통 21세기 초반 웹 환경의 필요에 기초를 두고 있어서, 이 시기에 개발된 시스템만을 NoSQL이라고 부른다. 따라서 그 이전에 만들어진 ODBMS(Objective Database Management System)은 NoSQL에 해당하지 않는다.
- 스키마 없이 동작하며, 구조에 대한 정의를 변경할 필요 없이 데이터베이스 레코드에 자유롭게 필드를 추가할 수 있다.
3. 등장 배경
지난 20년간, 데이터를 저장하는 데에는 관계형 데이터베이스가 사용되었다. 트랜잭션을 통한 안정적인 데이터 관리가 가장 중요한 이슈였기 때문이다. 하지만 웹 2.0 환경과 빅데이터가 등장하면서 RDBMS는 난관에 부딪히게 되었는데, 바로 ‘데이터를 처리하는 데 필요한 비용의 증가’때문이다. 데이터와 트래픽의 양이 기하급수적으로 증가함에 따라 한 대에서 실행되도록 설계된 관계형 데이터베이스를 사용하는 것은 하드웨어적으로 큰 비용이 들게 되었다. 장비의 성능이 좋을수록, 성능을 향상시키는 데(Scale-up : 수직적 확장) 비용이 기하급수적으로 증가하기 때문이다.
NoSQL은 데이터의 일관성을 약간 포기한 대신 여러 대의 컴퓨터에 데이터를 분산하여 저장하는 것(Scale-out : 수평적 확장)을 목표로 등장하였다. NoSQL의 등장으로 작고 값싼 장비 여러 대로 대량의 데이터와 컴퓨팅 부하를 처리하는 것이 가능하게 되었다.
4. 특징
4.1. 일관성과 확장성 사이의 Trade-off
일관성(Consistency)이 데이터베이스의 절대적인 요소가 아님을 주장하는 움직임이 생기기 시작했다.[1] 이들은 비일관성이 다음과 같은 두 가지 이유로 감수할 만한 것이라고 주장했다.
- 다수가 동시에 읽고 쓰는(Read and write) 상황에서의 성능 향상을 위해서.
- 분산 환경에서 노드들이 잘 작동하고 있음에도, 시스템의 일부가 고장나면 데이터베이스를 사용할 수 없게 되는 문제를 해결하기 위해서.
4.2. 분산 저장
데이터와 트래픽이 증가함에 따라 기존의 장비로는 원활한 데이터의 처리가 어려워졌다. 이를 해결하기 위한 방법으로는 처리하는 장비의 성능을 키우는 수직적 확장(Scale-up)과 처리하는 장비의 수를 늘리는 수평적 확장(Scale-out)이 있다. 위에서 서술했듯이 수직적 확장은 비용적인 문제가 발생하므로 수평적 확장을 통해 성능을 올려야 한다. 하지만 문제는 관계형 데이터베이스가 클러스터 상에서 효율적으로 동작하도록 설계되지 않았다는 점이다.
물론 관계형 데이터베이스를 클러스터 상에서 돌리지 못하는 것은 아니다. 클러스터 상에서 동작하는 관계형 데이터베이스 솔루션도 존재한다.[2] 이러한 데이터베이스에서는 클러스터를 인식할 수 있는 파일 시스템을 사용해 고가용성 디스크 서브시스템에 데이터를 기록하는 공유 디스크 개념을 사용한다. 하지만 클러스터의 디스크 서브시스템이 단일 고장점이 되어, 디스크 서브시스템에 문제가 생길 경우 데이터베이스를 사용할 수 없게 된다.
샤딩(Sharding)은 샤드 키(Shard key)를 기준으로 하나의 테이블을 수평 분할하여 서로 다른 클러스터에 분산 저장하고 질의할 수 있는 기법이다. 이를 통해 관계형 데이터베이스에서도 부하를 분산할 수 있지만 어플리케이션 레벨에서 모든 샤딩을 제어해야 한다. (어떤 데이터를 어느 클러스터에서 처리해야 하는지 등) 또한 여러 샤드에 걸치는 쿼리나 참조 정합성, 트랜잭션, 일관성의 제어에 문제가 발생한다.
분산 저장을 지원하는 NoSQL 데이터베이스의 경우, 집합-지향(Aggregate-oriented) 모델을 사용하여 이러한 문제를 해결한다. 연관된 데이터들이 함께 분산되므로, 관계형 모델에서처럼 복잡한 제어가 필요하지 않게 된다.
4.3. 데이터 일치
RDBMS에서 관계형 튜플 안의 값은 단순해야 하며 중첩된 레코드나 리스트 등 다른 구조를 포함할 수 없는 반면, 메모리 내 데이터 구조에서는 이런 제약이 없어 훨씬 복잡한 구조를 사용한다. (ex : 리스트, 딕셔너리, 중첩된 객체 구조) 그 결과 복잡한 메모리 내 데이터 구조를 데이터베이스에 저장하려면 먼저 관계형 표현으로 변환해야 한다. 물론 이는 ORM(Objective-Relational Mapping : 객체-관계 매핑) 프레임워크를 통해 해결할 수 있지만, 여전히 관계형 모델과 메모리 내 데이터 구조 간에는 데이터 불일치는 존재한다. 이를 Impedance mismatch라 한다.
하지만 NoSQL은 그런 게 없다. 메모리 내의 데이터가 어떤 구조이든지 상관하지 않고 하나의 Aggregation으로 취급하여 저장해버리기 때문이다. 따라서 NoSQL에서는 ORM 프레임워크가 필요하지 않다.
4.4. Schema-less
NoSQL 데이터베이스의 공통적인 특징은 스키마 없이 동작한다는 점이다. 따라서 데이터 구조를 미리 정의할 필요가 없으며, 시간이 지나더라도 언제든지 바꿀 수 있기 때문에 비형식적인 데이터를 저장하는 데 용이하다. 하지만 이는 데이터베이스가 스키마를 직접 관리하지 않는 것을 의미할 뿐, 데이터 타입에 따른 암묵적인 스키마는 여전히 존재한다. 이 때문에 단일 값에 대한 데이터 타입에서 불일치가 발생할 수 있다.
예를 들어 필드의 이름을 “Quantity”라고 하기로 했다고 하자. 이것은 앞으로 저장할 때 반드시 필드의 이름을 “Quantity”라고 저장하겠다는 암묵적인 스키마가 된다. 암묵적인 스키마를 무시할 경우 Quantity를 quantity, qty, QUANTITY 등으로 저장할지도 모른다. 뜬금없이 qty, quantity같은 새로운 필드가 추가되는 것이나 마찬가지이다. 이는 NoSQL 데이터베이스가 암묵적인 스키마에 대해 전혀 알지 못하며, 이를 강제하지 않기 때문에 발생하는 일이다. 그렇게 때문에 NoSQL을 사용할 때에는 주의를 기울일 필요가 있다.
5. 종류
NoSQL 데이터베이스는 크게 네 가지 모델로 나눌 수 있다.
- Key-value
- Document
- Column-family
- Graph
5.1. 집합-지향 (Aggregate-oriented) 모델
집합(Aggregate)이란 연산의 한 단위로 취급되는 연관된 객체들의 집합이다. 집합 지향 데이터베이스는 집합 자료구조로 이루어져 있다. 관계형 모델처럼 하나의 엔티티에 대한 ACID 트랜잭션[3] 을 지원하지는 않지만, 하나의 집합에 대한 연산에서는 트랜잭션을 지원한다.
집합 지향 데이터베이스는 여러 대의 클러스터로 이루어진 시스템에서 사용하기 적합하다. 다시 말해 수평적 확장이 용이하다는 것이다. 이는 관계형 데이터베이스와는 달리 연관된 데이터들이 함께 움직이기 때문이다. 또한 메모리 내의 자료구조와 집합 간 데이터가 잘 일치하므로, 관계형 데이터베이스처럼 객체-관계 매핑 프레임워크가 필요하지 않다. 데이터의 검색도 아주 쉬운 편으로, 키나 ID를 사용하면 쉽게 집합 레코드를 찾아낼 수 있다.
집합 지향 데이터베이스는 조인 연산이 불가능한데, 이를 보완하기 위해 MongoDB나 Cassandra등의 데이터베이스에서는 맵 리듀스(MapReduce) 기능을 제공함으로써 조인과 유사한 연산을 가능하도록 설계했다. 이를 사용하여 데이터 분석도 가능하다. 하지만 사용법이 어렵고 Hadoop의 맵 리듀스에 비하면 속도도 매우 느리다.
5.1.1. Key-value
키 값(Key-value) 저장소는 가장 단순한 형태의 NoSQL으로, 수평적 확장이 용이하다. 또한 아주 간단한 API만을 제공하기 때문에 배우는 것이 어렵지 않다.[4] 하지만 값의 내용을 사용한 쿼리가 불가능하다는 단점이 있다. 사용자는 키를 사용해 값을 읽어들인 뒤, 어플리케이션 레벨에서 적절히 처리해야 한다.
키-값 저장소는 데이터가 키와 값의 쌍으로 저장된다. 키는 값에 접근하기 위한 용도로 사용되며, 값은 어떠한 형태의 데이터라도 담을 수 있다. 심지어는 이미지나 비디오도 가능하다. 또한 간단한 API를 제공하는 만큼 질의의 속도가 굉장히 빠른 편이다.
Key-value 모델을 사용하는 NoSQL 데이터베이스로는 Memcached, Riak, Redis, Amazon Dynamo DB, LevelDB 등이 있다.
5.1.2. Document
키-값 모델에서 한층 진화한 모델로 생각할 수 있다. 데이터는 키와 도큐먼트(Document)의 형태로 저장된다. 키-값 모델과 다른 점이라면 Value가 계층적인 형태인 도큐먼트로 저장된다는 것이다. 객체지향에서의 객체와 유사하며, 이들은 하나의 단위로 취급되어 저장된다. 다시 말해 하나의 객체를 여러 개의 테이블에 나눠 저장할 필요가 없어진다는 뜻이다. 또한 Document 모델에서는 도큐먼트 내의 item을 이용한 쿼리가 가능하다. 다만 이를 위해서는 Xquery나 다른 도큐먼트 질의 언어가 필요하다.
주요한 특징으로는 객체-관계 매핑이 필요하지 않다. 객체를 도큐먼트의 형태로 바로 저장 가능하기 때문이다. 또한 검색에 최적화되어 있는데, 이는 키-값 모델의 특징과 동일하다. 단점이라면 사용이 번거롭고 쿼리가 SQL과는 다르다는 점이다. 도큐먼트 모델에서는 질의의 결과가 JSON이나 xml 형태로 출력되기 때문에 그 사용 방법이 RDBMS에서의 질의 결과를 사용하는 방법과 다르다. 또한 질의 언어가 SQL과 다르기 때문에 사용에 익숙해지기까지 다소 어려움이 있을 수 있다.
Document 모델을 사용하는 NoSQL 데이터베이스로는 MongoDB, CouchDB, MarkLogic 등이 있다.
5.1.3. Column-Family
컬럼-패밀리(Column-family) 모델은 위의 두 모델[5] 과는 다소 차이가 있지만 집합-지향 모델로 간주된다. 이전의 모델들이 키-값 쌍 중 값을 이용해 필드를 결정했다면, 특이하게도 이 모델은 키에서 필드를 결정한다. 키는 Row(키 값)와 Column-family, Column-name을 가진다. 연관된 데이터들은 같은 Column-family 안에 속해 있으며, 각자의 Column-name을 가진다. 관계형 모델로 설명하자면 어트리뷰트가 계층적인 구조를 가지고 있는 셈이다. 이렇게 저장된 데이터는 하나의 커다란 테이블로 표현이 가능하며, 질의는 Row, Column-family, Column-name을 통해 수행된다.
이러한 특징 덕에 컬럼-패밀리 모델은 클러스터링이 쉽게 이뤄지며, Time stamp가 존재해 값이 수정된 히스토리를 알 수 있다. 또한 값들은 일련의 바이너리 데이터로 존재하기 때문에 어떤 형태의 데이터라도 저장될 수 있다.
다만 위의 두 모델들과는 다르게 Blob 단위의 쿼리가 불가능하며, Row와 Column의 초기 디자인이 중요하다. Schema-less이긴 하지만 새로운 필드를 만드는 데 드는 비용이 크기 때문에 사실상 결정된 스키마를 변경하는 것이 어렵다.
Column-family 모델을 사용하는 NoSQL 데이터베이스로는 HBase, Cassandra, Hypertable 등이 있다.
5.2. 그래프 (Graph) 모델
그래프(Graph) 모델은 상당히 독특한 디자인을 가진 모델로써 집합 지향 모델보다는 관계형 모델에 가깝다. 실제 세계의 데이타를 관계와 함께 표현하기 위해 디자인된 모델로써, 데이터는 연속적인 노드, 관계, 특성의 형태로 저장된다. 다시 말해 그래프 형태로 저장된다는 뜻이다. 따라서 그래프 모델에서의 질의는 그래프 순회를 통해 이루어진다.
개체와 관계를 그래프 형태로 표현한 것이므로 관계형 모델이라고 할 수 있으며, 데이터 간의 관계가 탐색의 키일 경우에 적합하다. 페이스북이나 트위터 같은 소셜 네트워크에서(내 친구의 친구를 찾는 질의 등) 적합하고, 연관된 데이터를 추천해주는 추천 엔진이나 패턴 인식 등의 데이터베이스로도 적합하다. 또한 집합 지향 모델과는 다르게 개체의 ACID 트랜잭션을 지원한다.
다만 그래프 모델은 클러스터링에는 적합하지 않다. 또한 질의 언어도 특화되어 있어 배우기 어렵다.
6. 의의
대부분의 사람들은 NoSQL이 RDBMS를 대체할 수 있을 것이라고는 생각하지 않는다. 그러기에는 RDBMS가 가진 장점이 너무나 명확하고, 또한 많은 사람들이 RDBMS을 사용하는 데 익숙해져 있기 때문이다. 그럼에도 불구하고 NoSQL이 각광받고 있는 까닭은 NoSQL만의 장점이 뚜렷하기 때문이다.
예를 들어 구매 내역이나 게임의 로그 같은 데이터들은 매 초마다 엄청난 양이 생성되지만 한번 저장되고 난 뒤에는 수정될 일이 거의 없다. 이런 데이터들을 저장하는 데 데이터의 일관성을 보장하기 위해 ACID 트랜잭션을 지원할 필요는 없을 것이다. 거기다 생성되는 데이터의 양도 많기 때문에 장비의 성능에도 상당한 영향을 미칠 것이다. NoSQL은 이러한 데이터들을 효율적으로 저장할 수 있다. 여러 대의 장비에 빠른 속도로 저장이 가능하며, 데이터의 양이 누적되더라도 얼마든지 수평적 확장이 가능하기 때문이다.
실제로 페이스북이나 트위터 같은 소셜 네트워크 서비스에서는 게시글들을 저장하는 데 NoSQL 데이터베이스를 사용하고 있다.[6] 매 초에 수백 기가~수 테라 바이트씩 생성되는 데이터들을 RDBMS를 사용해 저장한다면, 글 작성 버튼을 누른 후 글이 중앙 데이터베이스에 저장되기까지 한참을 기다려야 글을 성공적으로 게시할 수 있을 것이다. 하지만 NoSQL의 분산 데이터베이스를 사용한다면 부하가 분산되기 때문에 우리가 글쓰기 버튼을 누르고 한참을 기다릴 필요가 없게 된다. 또한 각종 검색 엔진에도 사용되는 것이 NoSQL인데, 웹 페이지 내의 텍스트들을 형태소 단위의 토큰으로 분리하여 토큰과 해당 토큰이 포함된 페이지들의 URL을 맵핑하는 Inverted Index(역 인덱스) 구조를 NoSQL을 통해 구현한다. 이런 기능을 일반적인 RDMBS로 구현했을 경우 검색 창에 단어를 입력했을 때마다 상당한 시간이 소요될 것이다.
하지만 데이터의 일관성이 보장되어야 하거나 여러번의 조인 연산이 필요한 데이터라면 NoSQL을 사용하는 것 보다 RDBMS를 사용하는 것이 좋을 것이다. NoSQL은 RDBMS를 대체하기 위한 데이터베이스가 아니라 상호 보완할 수 있는 데이터베이스이며, 따라서 목적에 맞게 사용하는 것이 중요하다.
C++, Java, Python 등 여러 언어를 사용해서 하나의 프로그램을 만들 수 있는 것처럼(Polyglot Programming) 데이터베이스 역시 다양한 저장소(Polyglot Persistance)를 사용할 수 있게 되었다는 점에서 NoSQL의 의의는 크다고 볼 수 있다.
7. 종류
- Redis
- Cassandra
- HBase
- Firebase의 실시간 데이터베이스와 Cloud Firestore
- MongoDB