[발 번역] Sharding your database

해당 글은 http://craigkerstiens.com/2012/11/30/sharding-your-database/ 라는 글을 발 번역한 것입니다. 오역에 주의하시길 바랍니다. 샤딩에 대해서 처음 접하시는 분들이나, 데이터베이스를 가지고 어떻게 샤딩을 해야할까에 대해서 처음 고민하시는 분들에게 좋은 글입니다.

 

Sharding your database

 

Heroku 에 사용자들이 점점 늘어나는 문제를 겪으면서, 사용자들의 데이터를 샤딩할 필요가 생겼습니다.(역자 주: 글쓴이가 Heroku에 근무중입니다.)  대부분의 유저들에게, 샤딩은 고민하기 전에,  정상적인 서비스가 가능한 한, 최대한 뒤로 미루는 작업입니다.  게다가 종종, 일찍 데이터베이스 스케일 업을 시도하는 것은 합리적이며, 데이터베이스에 대한 스케일 업은 쉽게 할 수 있으므로,  출발점으로 권장되어집니다. 그러나, 샤딩할 시점이 와서 샤딩이 필요한 1%의 유저들에게 어디서 시작해야 하는지는 궁금점으로 남아있습니다. 그래서 다음 가이드를 보시기 바랍니다.

What and Why

샤딩은 데이터를 나누는 작업입니다. 그래서 다른 테이블이나 종종 다른 물리 데이터베이스에도 있을 수 있습니다. 샤딩은 한대의 데이터베이스에서 합리적인 속도가 필요하거나,  스토리지를 용량을 초과한 특정한 데이터 셋을 가지고 있을 때 유용합니다.

Logical Shards

처음 샤딩을 구현하려고 할 때, 추상적인 논리적 샤드들을 만들기를 원하게 될 것입니다. 이것은 나중에 몇개의 샤드를 더 추가해야 할 때, 적은 코드의 변경만으로 가능하게 해줄 것입니다. 그리고 샤드를 2의 배수로 정의하기를 원할 것입니다. 일반적으로 대부분의 서비스에 1024가 적절한 값이라서, 추천합니다. Instagram의 경우 실제로 4096을 사용했는데, 둘 다 실제로 적절한 값이 될 수 있습니다.  간단하게 하기 위해서 예제에서는 4개의 논리적 샤드로 시작하겠습니다. 먼저 사용자들의 집합에 대한 예를 보겠습니다.

 id |           email           |      name       
----+---------------------------+-----------------
  1 | craig.kerstiens@gmail.com | Craig Kerstiens
  2 | john.doe@gmail.com        | John Doe
  3 | jane.doe@gmail.com        | Jane Doe
  4 | user4@gmail.com           | User 4
  5 | user5@gmail.com           | User 5
  6 | user6@gmail.com           | User 6
  7 | user7@gmail.com           | User 7
  8 | user8@gmail.com           | User 8

이것들을 논리적 샤드로 나누면, 다음과 같은 결과를 볼 수 있습니다.

sharding layout

  샤딩할 때, 요청시 특정 데이터베이스에 집중되지 않는 매커니즘을 발견하는 것은 중요합니다. 위의 예에서는 데이터베이스 안의 row의 ID 값을 이용했지만, email 과 같은 특정 값의 해시값에 기반해서 샤드를 결정하기를 원하게 될 것입니다.

logical_shard = hash(User.email) % 4

Physical Shards

여기서 부터, 논리적 샤드를 가지고 있고, 실제 물리 샤드를 생성할 것입니다. 만약 싱글 데이터베이스를 이용하고 있어서, 하나의 물리적 샤드만 가지고 있다고 하더라도, 어플리케이션 코드는 추가적인 샤드를 다룰 수 있도록 준비되어 있어야 합니다. 여기서, 두 개의 물리적 샤드를 가지는 예에서, 데이터를 나눈 최종 결과는 다음과 같습니다.

sharding layout

 접근 가능한 물리적 샤드는 존재하는 논리적 샤드와 존재하는 물리적 샤드의 모듈러 연산을 통해서 쉽게 찾을 수 있습니다.

total_physical_shards = 2
total_logical_shards = 4
logical_shard = hash(User.email) % total_logical_shards
physical_shard = logical_shard % total_physical_shards

Generating IDs (Primary Keys)

여러 대의 데이터베이스에 데이터를 분배하는 동안 primary key를 정수형으로 사용하는 것을 피하기를 원할 것입니다. 데이터베이스 내에 중복된 키를 만들 수 있고, 데이터에 대한 리포팅을 할 때, 골치 아픈 문제들을 만들 수 있습니다. UUID를 primary key 로 이용하는 것이 이상적입니다. UUID를 이용하고, 이를 생성하는 것은 어플리케이션 코드를 이용하거나, 데이터베이스의 기능을 이용해서 각각의 User ID가 실제로 유일하다는 것을 보장할 수 있습니다.

Adding Capacity

대부분의 웹 어플리케이션을 위한 최고의 예는, 초기 용량을 넘어서는 확장을 해야만 했던 Instagram 입니다. 이런 작업을 하기 위해서, 물리적 샤드를 간단하게 확장해 보겠습니다. 이를 위해, 하나의 물리적 샤드의 데이터를 다른 샤드로 옮기기를 원할 것입니다. 그리고 이전 물리 서버로 부터 데이터를 제거할 것입니다.  물리 샤드도 논리적 샤드처럼 동일하게 2의 배수로 증가시키는 것이 일반적으로 좋은 방법입니다. Heroku Postgres Service 를 이용해서 어떻게 확장을 할 수 있는지 명확한 예제를 보도록 하겠습니다.

첫번째로, 존재하는 각 물리적 샤드에 follower 를 추가합니다.(역자 주: 처음에 서비스를 위해서 데이터를 복제하는 녀석이라고 보시면 됩니다. 일단 모든 데이터를 리플리케이션 받게 되면, 코드를 수정해서, 각각의 샤드로 가게 하고, 리플리케이션을 끝는 것이 일반적인 방법입니다.)

Followers

 follower 를 Write 가 가능한 독립된 데이터베이스가 되도록 승격시킬 것입니다. 이것은 같은 데이터를   기록하는 두 개의 복제본을 가지는 것을 의미합니다.

Promotion

 이 시점에 새로운 물리 샤드의 수를 반영하도록 어플리케이션 코드를 수정할 수 있습니다. 이 작업은 적절한 샤드에 데이터를 쓰기 위해서 필요합니다. 또한,  데이터의 일부를 삭제하기를 원할 수도 있습니다. 적절한 샤드에 있지 않은 데이터를 지우기를 원할 것입니다. 예를 들어서, id 3은 더 이상 물리 샤드 1에 속하지 않습니다. 이런 데이터들을 정리하는 백그라운드 프로세스를 실행할 수 도 있습니다.(역자 주: 이때, 리플리케이션은 미리 끊어져 있어야 합니다. )

Cleanup

Conclusion

많은 어플리케이션이 자신의 데이터베이스를 스케일 아웃할 필요가 없을 것이지만, 필요하다면, 샤딩은 적합하고, 효과적인 방법이 될 수 있습니다. 많은 사람들에게 스케일 업이 시작하기에 쉬운 방법이라고 권장하고 있지만, 이 문서는 차후에 어떻게 스케일 아웃 할 것인지에 대한 지침을 제공합니다. 나중에 샤딩이 필요할 것이라고 미리 계획하고 있다면, 초반부터 Key를 UUID를 사용하는 식으로, 샤딩 작업을 덜 힘들게 할 수도 있습니다.( 역자 주: 처음에 아무 생각없이 key를 잡으면, 나중에 샤딩이 힘들어집니다. 예를 들어 mongodb의 경우 샤딩 key를 전체 서버에서 유일한 값으로 해두어야만 차후에 샤딩이 됩니다. 이걸 모르고, 아무렇게나 키를 정해두면, 차후에 샤딩을 도입하기 힘들어집니다.)

해당 문서는 단순히 겉핧기일 뿐입니다. 관심에 따라서, 실제적인 코드 예와 함께 따라야할 구체적 사례들이 많을 것입니다.