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


Archive»


 
 


Auto-Sharding

이번 MySQL의 Enhancement 중 재미있는 기능중의 하나가 Auto Sharding이라는 기능이다. 

Sharding에 대한 개념은 http://bcho.tistory.com/670 를 참고하면 되고.

보통 Sharding이라 하면 Application 에서 작성해서 컨트롤해야 하기 때문에, 데이타 저장 용량을 늘릴 수 있을지 몰라도, 전체적으로 Application의 구현 복잡도를 올리는 문제가 있었다.

이번 MySQL에서는 Auto-Sharding이라는 기능을 제공하는데, 요는 MySQL이 알아서 데이타를 여러 데이타 노드에 분산 저장함으로써 전체 저장 용량을 늘리고, 데이타를 분산 배치 함으로써, 처리 능력을 향상 시킬 수 있다.



위의 그림은 Auto-Sharding 아키텍쳐이다. Primary Key에 의해서 홀수는 좌측 클러스터에, 짝수는 우측 클러스터에 자동으로 나눠서 저장이 되게 된다.


Data Replication

또한 특정 노드 장애에 대비해서 데이타 노드에 저장된 데이타에 대해서 다른 노드에 복제본을 저장한다.


위의 하나의 좋은 예가 있는데, 두개의 클러스터 노드 그룹이 있고, 4개의 데이타 노드가 있다고 가정하자, 하나의 테이블은 데이타 노드 수인 4개만큼 Sharding으로 나뉘어서 각 노드에 저장되고, 각 노드 그룹안에서는 상대방 서버에 대한 Sharding 파티션에 대한 복제본을 저장한다. 이렇게 함으로써, 특정 노드가 장애가 나더라도, 정지 없고, 데이타 유실 없이 서비스가 가능한 구조가 된다.



대용량 시스템을 위한 데이타베이스 아키텍쳐
Sharding & Query Off Loading

RDBMS는 크게 request를 바로 처리하는 트렌젝션 처리용의 OLTP(On-Line Transaction Processing)성과, 데이타를 모아서 분석하고 리포팅하는 OLAP(On-Line Analytical Processing) 두가지로 분리된다. 여기서 설명하는 RDBMS OLTP성의 데이타 베이스 이다.

RDBMS 2차원 테이블 구조의 데이타를 KEY 값을 중심으로 여러개의 컬럼으로 저장되며, 저장된 각각의 로우()은 다른 테이블의 로우와 관계를 가질 수 있다.

RDBMS를 이용한 설계를 하는데, 고려할만한 아키텍쳐는 성능 향상을 위한 Query Off Loading, Sharding이라는 기법이 있다.


Query Off Loading

 Query Off Loading DB의 성능 향상을 위한 기법이다. (정확하게 이야기 하면, 처리량을 증가 시키기 위한 설계 기법이다.) DB 트렌젝션의 70~90%는 대부분 READ 성이 많다. 나머지 10~30% Create/Delete/Update와 같은 트렌젝션인데, Update 성 트렌젝션과 Read 트렌젝션을 분리하는 기법이다.



먼저 Master DB에는 쓰기(Update)만을 허용하고, Master DB의 내용을 중간의 Staging DB라는 곳으로 복사한다. Staging DB는 복제된 내용은 N개의 Slave DB로 복제한다.

애플리케이션은 Master DB에만 쓰기를 하고, 읽기는 Slave DB에서만 수행한다. 이를 위해서 Application DB에 대한 쓰기 로직과 읽기 로직을 분리해서 구현해야 하며, 이 분리된 로직은 쓰기 DB로 접근하기 위한 DB Connection과 읽기 DB로 접근하기 위한 DB Connection을 이용해서 접근한다. 일반적으로 application server에서는 이러한 Connection Connection Pool 을 이용해서 관리 하는데, 읽기 DB의 경우에는 N개의 Slave DB로 부터 읽기 때문에, Application이 이 N개의 Slave DB에 대한 요청을 Load Balacing을 해야 한다. 또한 특정 Slave DB 장애시 다른 Slave DB 인스턴스에 접근을 할 수 있도록 HA (High Availability) 기능을 제공해야 하는데 Connection Pool 자체에 Load Balancing HA 기능을 가지고 있는 Connection Pool을 이용하거나 또는 JDBC Driver와 같이 DBMS Driver 자체에 Load Balancing HA 기능을 사용한다.

Master DB Slave DB는 각각 쓰기와 읽기를 위해서 접근된다고 하지만 그렇다면 중간에 Staging DB의 역할은 무엇일까? Staging DB Slave DB로 복제하기 위한 중간 경유지 역할을 한다. 다수의 Slave DB로 복제를 해야 하기 때문에, 이에 대한 부하가 크다. 만약 Master DB에서 Slave DB로 바로 복제를 하게 되면, Master DB가 쓰기 트렌젝션 이외에 복제에 대한 부분을 처리해야 하기 때문에 성능 저하를 유발할 수 있다. 이를 방지 하기 위해서 중간에 Staging DB를 넣는 것이다.

그렇다면 Master à Staging à Slave DB로의 복제는 어떤 기술을 이용할까?

CDC (Change Data Capture)라는 기술을 이용한다. DBMS들은 공통적으로 Create/Update/Delete와 같은 쓰기 관련 작업을 수행할때, 데이타를 실제로 저장하기 전에 먼저 해당 작업에 대한 request BackLog라는 곳에 저장한다. (BackLog는 일반적으로 Local 파일이다.) 이는 실제로 데이타를 쓰기전에 장애가 났을때, restart하면서 이 BackLog를 읽어서 복구를 위한 용도로 사용이 된다. CDC는 이 Back Log를 이용해서 데이타를 복제하는데, Source DB로 부터 이 Back Log를 읽어서, 복제를 하고자하는 Target DB replay 하는 형식이다.

Source DB에서, insert A,B,C를 하면 이는 모두 Back Log에 기록되고, 이를 읽어서 Target DB에서 다시 replay – insert A,B,C를 순차적으로 수행하는 것이다.

대표적인 CDC 제품으로는 Oracle Golden Gate, Quest Share Flex가 있고, 오픈소스 제품으로는 Galera[1]라는 제품이 있다.


Sharding

Sharding은 데이타베이스의 용량 한계를 극복하기 위한 기술이다. 클러스터링 기술을 사용하더라도 데이타 베이스는 물리적인 용량 한계를 갖는 경우가 많다. 수년 전에만 해도, 하나의 서비스에 수천만명이 사용하는 서비스는 없었다. 인터넷의 발전등에 따라서 사용자가 급격하게 늘어나고 저장해야 하는 데이타의 양도 급격하게 늘어났다. 데이타 베이스 시스템은 이러한 용량 증가를 따라가지 못했다. 그래서 Sharding이라는 아키텍쳐가 유행하기 시작했는데, Sharding은 쉽게 말해서 데이타를 여러개의 데이타 베이스에 나눠 담는 방법이다.

하나의 데이타 베이스가 10억개의 레코드만 저장할 수 있다면, 100억개의 데이타를 저장하려면 10개의 데이타 베이스를 사용하여 분산 저장하는 방법이다. 이 각 10개의 데이타 베이스를 Shard라고 한다.

Sharding은 데이타를 분산 하는 방식에 따라서 Vertical(수직적) Sharding Horizontal(수평적) Sharding으로 나뉘어 진다.

Vertical Sharding은 연속된 데이타에 대해서 범위별로 데이타를 나누는 방법이다. 아래 예는 연령대 별로, 데이타를 나누는 예이다.



Figure 1 Vertical Sharding


다음으로는 Horizontal Sharding이 있는데, 이는 연속된 키가 아니라 “Category”와 같은 종류에 따라서 데이타를 수평적으로 분리하는 방법이다.



Figure 2 Horizontal Sharding


데이타를 분산 저장할때 위와 같이 meaningful한 데이타를 사용할 수 있는데, 이 경우에는 데이타의 몰림 현상이라는 것이 발생할 수 있다. 위의 Vertical Sharding을 예를 들어보면, 해당 서비스를 사용하는 연령층이 20대와 30대에 편중되어 있다면, 20,30 Shard에는 데이타가 몰리게 되고, 부하도 더 많이 받게 될 것이다. 그래서 이렇게 meaningful한 데이타를 KEY로 사용할 경우에는 데이타 몰림현상을 고려하여 각 Shard 서버의 성능을 비 대칭적으로 설계할 수 있다. 20,30대의 Shard에는 더 좋은 CPU와 메모리를 갖는 서버를 배치하는 방법이 대안이 된다.

만약에 데이타 편중 현상에 대한 예측이 어려운 경우에는, meaningful 하지 않은 KEY를 사용해서 Sharding을 할 수 있다. 10개의 Shard를 갖는 데이타 베이스에서, 사용자 레코드를 등록할때, KEY Sequence를 이용해서 순차적으로 부여한다. 첫번째 사용자는 1, 두번째는 2, 다음은 3,4,5,6.. 등으로.. 그리고 이 ID 10으로 나눈 나머지 값을 가지고 Shard를 결정하면, 데이타를 모든 Shard에 걸쳐서 골고루 분산 시켜 배치 할 수 있다. (Hash 방식)

Sharding을 구현하는 방법은 DBMS 단에서 Sharding을 지원 하는 방법과, OR Mapper와 같은 DB 접근용 프레임웍에서 Sharding을 제공하는 방법 그리고, Application Code 자체에서 지원하는 방법 세가지가 있다.

DBMS 단에서 제공하는 방법으로는 Microsoft SQL Server Azure federation model[2]이나 RDBMS는 아니지만 NoSQL MogoDB의 경우 1.6부터 Sharding DB단에서 지원한다.

프레임웍단에서는 자바의 Hibernate의 경우 Hibernate Shard[3]라는 기능을 통해서 Sharding을 지원한다프로그래밍 언어인 Grail의 경우에도 자체 프레임웍에서 “Grails Sharding Plug in”을 통한 Sharding 을 지원한다.

직접 Application에서 구현할 경우 Key에 따라서 DB Instance를 선택적으로 고를 수 있는 구조를 가져야 하며, 특히 다른 Shard간의 데이타 Join등은 불가능하기 때문에, 구현상에 이에 대한 고려가 필요하다.

Sharding 이라는 것이 데이타를 분산 저장함으로써 시스템의 전체 용량을 늘릴 수 는 있지만 Application의 복잡도가 올라가고, 데이타 편중 방지등 여러가지 요소를 고려한후에 설계, 반영해야 한다..


요즘 대용량 데이타 처리 때문에, NoSQL을 머릿속에만 올려놓고, 근래에나 되서 이래서는 안되겠다 해서 직접 자료를 찾아보고 있습니다.

NoSQL은 Cassandra, HBase, Mongo, Riak등을 후보군으로 뒀는데,

Cassandra는 FaceBook에서 Donation해서 만든 분산 DB로 개인적으로는 가장 신뢰가 가기는 했지만, 국내의 많은 블로그 포스팅등을 읽어보면, 안정성이나 사용성이 떨어진다는 것이다. 즉 제품은 좋은데 야생마처럼 잘 쓰지 못하면 모쓰는 제품이라는 이야기. 일단 후보로 남겨놓고 패스.

HBase는 Hadoop File System (HDFS)를 기반으로 설계되었는데, 검색해보니 생각보다 많이 사용이 안되는 것 같아서 패스
Riak도 신생이라서 패스

결국은 Mongo와 Cassandra에서 고민하게 되었는데,
신생 MongoDB가 얼마전부터 사람들 입에 많이 입에 오르내리고 있다. 검색을 해봐도 많이 나오고
이는 즉 사용이 쉽다는 것을 의미하고 또한 10gen이라는 회사에서 제품에 대한 Ownership을 지고 서포트와 컨설팅 그리고 라이센스를 제공하고 있다. 둘다 오픈소스(?)이긴 하지만 자기네들만이 사용하기 위해 만든 Cassandra와는 태생 자체가 다르다는 사실

요즘 분산 아키텍쳐를 보면 대부분 비슷한것이 앞단에 Load Balancing을 해주는 Proxy 를 두고, 뒤에 데이타 처리를 하는 Processing Node를 두는 것이 일반적인데, SWIFT도 글코, MogileFS도 글코, 분산 처리 환경인 Gearman이나 Hadoop도 결국은 비슷하다. 아니나 다를까, MongoDB도 유사한 구조를 갖는다.

일단 기능적인 특징을 보면

Indexing이 가능하다.
이말은 즉 빠른 Search가 가능하다는 이야기인데, 문서를 찾아보니, Index는 메모리에 저장되기 때문에, 메모리 크기에 영향을 많이 받는다. 즉 Deployment설계할때, 하드웨어의 Memory 사이즈가 중요한 Factor 라는 것

GridFS 기반의 Blob 데이타 저장 지원
GridFS라는 분산 파일 시스템을 사용하여 Binary 데이타 저장이 가능하다. 일반적인 아키텍쳐에서 meta 정보를 DBMS에, binary를 File System에 나눠서 저장할때, 이로 인해서 발생되는 데이타 일관성에 불일치를 방지할 수 있다는 점에서는 혁신적인데.. 문제는...
국내의 어느 블로거가 테스트한 데이타 http://symplog.tistory.com/entry/MongoDB-MongoDB-GridFS-%EB%B6%80%ED%95%98%ED%85%8C%EC%8A%A4%ED%8A%B8 를 보면, 파일 업로드 다운로드 성능이 그리 뛰어나지 않은 듯 하다.
큰 파일을 저장할때, 파일을 Chunk 단위로 나눠서 다운로드, 업로드 하는데 이는 메모리 사용면에서 효율성을 제공한다. (한꺼번에 다 읽거나 쓸때 한꺼번에 Flush를 하면 파일을 메모리에 가지고 있는 동안, 파일 사이즈가 크면 Out Of Memory를 유발할 수 있기 때문에..) 1.7 버전 이하에서는 4M, 1.7 이상에서는 16M의 Chunk Size를 제공하는 것 같은데.
문제는 Opendedup에서도 테스트해봤지만, 이 Chunk 단위로 파일을 나누는 작업이 보통 일이 아니라는, 일단 태생 자체가 작은 Blob 데이타를 저장하기 위함이지 대용량 파일을 저장하기 위함은 아닌 것 같은데,
http://blog.wordnik.com/12-months-with-mongodb 블로그를 보면 12billion (약 120억개)의 레코드를 저장하고, 여기에 음악 파일을 저장하는 것을 보면 가능하다고도 볼 수 있다. 보통 음악 파일이 4M 안팍인것을 감안하면 괜찮은 시나리오인 듯 하나 500GB가 넘어가는 비디오 파일을 저장할때는 어느정도 성능을 감당할 수 있을지는 미지수 이다.
만약에 안정적으로 GridFS가 대용량 파일을 저장할 수 있는 구조를 제공한다면 사람들이 SWIFT,MogileFS,GlusterFS를 사용하지 않고 모두 MongoDB를 사용해야 하지 않을까?
이 부분은 나름 테스트가 필요한 부분으로 남겨놓고 넘어간다.

Querying
아울러 RDBMS 와 같은 Query를 제공한다. (물론 RDBMS보다 한참 못 미치기는 하지만)
Key/Value Store만 지원하는 다른 NoSQL에 비하면 매력 적인 기능

Replication
http://www.mongodb.org/display/DOCS/Master+Slave
Master-Slave Replication도 지원하네, Query Off Loading 구현도 가능하겠다.

Sharding
그외에 자체적으로 데이타 Sharding 아키텍쳐를 지원한다. 요즘 이게 유행인지 MySQL 최신 버전도 자체적으로 Sharding을 지원한다. Sharding을 사용하면 1000개의 Shard까지는 거뜬히 지원할 수 있는 것 처럼 나오는데, 이건 테스트 하기는 어려울테고, 성능 데이타를 레퍼런스 하는 수 밖에

일단 완성도나 기능들이 높아 보이는 것 같은데..
깔아서 테스트해보고, 10gen 에서 컨설팅 불러서 직접 들여다 봐야 몬가 나오지 않을까?
=== 첨언 ===
구조를 살펴보니, 앞에서 언급했던 것처럼 SWIFT나 MogileFS와 상당히 유사하다
앞단에 Load Balancing 역할을 해주는 mongos 라는 프로세스들이 뜨고
뒷단에 실제 데이타를 저장하는 mongod라는 프로세스들이 뜨는데, 여기서 재미있는 것은 데이타 Replication을 하는데, 각 Shard당 3개의 인스턴스를 제공하도록 구성을 권장한다. Swift등에서 흔히 이야기 하는 3 Copy다. 데이타 안정성등을 위하는 건데. (딱 봐도, 하드웨어 비용이 장난 아니겠다.)

더불어서 MogoDB는 Cassandra나 HBase에 비해서 나은 성능을 갖는데 앞에서 설명한 바와 같이 Memory를 이용한 Indexing등으로, 반대로 이야기 하면 Memory가 충분히 있어야 한다는 이야기고, 비싸다는 이야기다.

큐브리드 블로그에 보면 재미있는 내용이 있는데 http://blog.cubrid.org/dev-platform/nosql-benchmarking/

Cassandra and HBase is for processing full-scale large amounts of data, while MongoDB can be used quickly, schema-free when using a certain amount of data.

MongoDB adopts a documented-oriented format, so it is more similar to RDBMS than a key-value or column oriented format.

MongoDB operates on a memory base and places high performance above data scalability. If reading and writing is conducted within the usable memory, then high-performance is possible. However, performance is not guaranteed if operations exceed the given memory. Therefore, MongoDB should be used as a medium or small-sized storage system.

한마디로, 성능은 좋지만 빅데이타는 Cassandra나 HBase를 쓰고 중소형에만 MongoDB를 쓰라는 것이다.
RDBMS에 유사하고 강력한 Feature, 사용의 편리성의 입장에서 MongoDB가 국내외에서 많은 사용층을 가지고 있는 것이 대강 이해는 된다. 한편으로는 MongoDB의 한계를 벗어날만한 데이타를 아직까지 사용해본 적이 없다는 반증도 될것이다. 10~20억 데이타는 내가 아는한에서는 RDBMS에서도 크게 문제가 없다. 문제는 10~20억을 넘는 100억, 1000억개의 데이타 핸들링에도 MongoDB가 버텨 줄것이냐인데.. 데이타 한건당 대략 10K만 잡아도 용량이 1Peta 이다. 3TB 노드를 300개 정도 연결해야 한다는 것인데... MongoDB에서 보통 1000개의 Instance를 이야기를 하니 이론상으로는 가능할것 같기는 한데
첫번째는 어렵지 않을까? 하는 생각이고, (그만한 레퍼런스가 있냐?) 두번째는 만약에 된다고 하더라도 돈이 엄청 들어갈것 같은 느낌이다. Swift도 MogileFS도 저가라고는 말하지만 소프트웨어가 저가인거지 3Copy로 하드웨어 구성을 벤더 제품으로 하면 마찬가지라는... (Commodity 하드웨어라면 몰라도..)
  이래 저래 자료를 찾아볼 필요가 있다.



Mongo DB

클라우드 컴퓨팅 & NoSQL/MongoDB | 2011.03.24 13:55 | Posted by 조대협
점심 시간에, 후욱 훝어봤는데, 생각보다 괴안은 듯.
주요 특징을 적어보면
  • Cassandra와 같은 NoSQL DB와 유사한 데이타 저장 구조를 가진다.
  • 무엇 보다 마음에 드는 건, Sharding과 Replication을 솔루션 차원에서 지원하고,
  • 자체 Map & Reduce 엔진을 가지고 있다.
  • 여기에 더해서, 가장 많은 레퍼런스를 가지고 있다는 것
  • C# 인터페이스가 없는 것이 아쉽기는 한데... C/C++이 있으니, COM으로 만들어서 재 사용해도 될듯.

시간 나면 한번 더 조사해봐야 쓰겄다.
특히 Geo Replication이 되는지가 젤 궁금하네.