DB야! 일어나!!
불과 몇 년전만해도 플렛폼을 만든다는건 굉장히 어려운 일이었습니다. 그러나 웹기술이 향상되면서 이제는 누구나 빠르게 플렛폼을 만들 수 있는 시대가 왔습니다. 정말 멋진 시대가 왔지만 안타깝게도 데이터베이스(이하 DB) 설계를 잘못해서 좋은 서비스가 망해버리는 경우도 생깁니다. 이번 글에선 플렛폼을 만들 때 고려해야할 DB 설계 방법에 대해서 이야기해보겠습니다.
유튜브를 예로 들어봅시다. 조회수는 계속 변화합니다. 사용자가 검색어를 입력해서 조회수를 확인할 때마다 DB가 연산을 한다면 어떨까요? COUNT함수를 이용해 본 사람들의 숫자를 하나하나 세면 어떨까요? 정말 끔찍한 일이 펼쳐질 겁니다. 처음의 몇 백명까진 감당할 수 있을지 몰라도, 이후에 몇 만, 몇 십만이 된다면... 어휴...
좋은 서비스는 사용자의 요청과 연산이 정비례하지 않아야 합니다. 쿼리를 비례해도 연산은 비례해선 안됩니다. 만약 사용자가 발생시키는 쿼리가 연산을 포함하면 y=x^n, 또는 그 이상으로 연산이 증가될 수도 있습니다.(x: 사용자 요청, y: 연산량)
예시를 하나 들어보겠습니다.
Youtube_View라는 테이블에 watch_user는 영상을 본 사람들의 목록으로 정합시다. DB가 조회수를 가져올 때마다 본 사람 숫자를 하나하나 세면 정확한 조회수는 알 수 있지만 조회수에 따라 기하급수적으로 느려지는 방식입니다. 반면 아래의 쿼리처럼 일정한 주기로 watch_user의 숫자를 카운트해서 view에 저장하고, 사용자는 view를 요청하게 된다면 연산은 조회수에 따라 늘어나지 않고, 일정 주기에 따라 한 번씩만 이뤄집니다.
그럼 view의 데이터는 어떻게 업데이트시켜줄 수 있을까요? MySQL 등의 데이터베이스라면 이벤트를 통해 일정주기로 데이터를 업데이트하도록 명령해줄 수 있습니다. 또는 서버에서 일정 주기마다 데이터를 업데이트하도록 쿼리를 쏴주는 방법도 있습니다.
만약 여러분이 1번처럼 사용자가 늘어감에 따라 컴퓨터를 혹사시키는 방법을 사용한다면, 서비스가 대성공하는 순간 망한다는 점을 기억해주세요.
관계형 데이터베이스는 플렛폼 서비스에 부적합한 경우가 많습니다. 이유는 플렛폼 서비스의 특성 때문입니다. 플렛폼 서비스는 I/O가 매우 높습니다. 대부분의 컨텐츠는 인스턴트하게 소모되고, 데이터 업데이트가 1초에도 수 만, 수 십만 회가 나타날 수 있습니다. 이런 구조를 관계형 데이터베이스로 만들게 되면 각각의 데이터가 키로 연결되어 동기화되는 과정에서 매우 느려질 수 있습니다. 결국 위의 이유에서 많은 플렛폼은 NoSQL을 사용하며, 선호합니다. 그렇다고 플렛폼의 모든 데이터를 NoSQL로 다룰 필요는 전혀 없습니다. 회원정보 같은 데이터는 관계형 데이터베이스에 저장하고, I/O가 빈번한 데이터만 NoSQL을 활용해 처리하는게 좋습니다.
NoSQL이 플렛폼에서 사랑받는 이유는 또 있습니다. 바로 스케일 변화입니다. 관계형 데이터베이스에서 스케일을 확장시키는 일은 매우 어려운 일입니다. 또한 관계형 데이터 베이스가 1개, 2개, 3개로 늘어감에 따라서 복잡도는 크게 늘어납니다. 반면 NoSQL은 스케일링에 있어서 훨씬 자유롭고, 편리하며, 안정적입니다. 이에 대한 좋은 글은 아래의 링크를 참조해보시길 바랍니다.
Big int라는 데이터 타입은 매우 큰 숫자를 저장할 수 있습니다.
반면 Small Int는 작은 숫자만 가능합니다. 어떤게 연산이 빠를까요?
최소한의 데이터로 저장하는건 성능 향상에 필수적입니다. 과도하게 큰 데이터형을 쓰게되면 불필요한 DB자원을 소모하고, 서비스를 느리게 만듭니다.
이상적인 경우엔 각각의 데이터가 예측할 수 있는 범위의 숫자를 담으면 좋을겁니다. 하지만 예측하지 못하는 경우가 생기곤 하죠. 초기엔 작은 정수 단위였다가 큰 정수로 늘어나는 경우를 생각해봅시다. 이런 경우엔 데이터 형태를 어떻게 잡아야할까요? 작게 잡을까요? 크게 잡을까요? 아니면 적당히 잡아야할까요?
제가 사용하는 방법은 데이터를 분할하는 방법입니다. 이를테면 만을 넘어가는 숫자인 경우 천의 단위 아래는 버림으로 처리하는 것이죠. 대신 0이 몇개인지 하나의 컬럼에 저장해주면 됩니다.
유튜브 조회수를 예로들면 1만이라는 숫자를 저장할 때 10,000이라고 하지말고, 1이라는 값과 4라는 값 2개로 저장하는 격이죠. 이러한 저장 방식을 사용하면 단위가 매우 커질 때에도 아주 작은 단위만 사용해서 저장할 수 있습니다. 가령 천억(100,000,000,000)이라면 1과 11이라는 두 개의 데이터로 저장이 가능합니다.
이런 방법은 게임에서도 사용됩니다. 롤플레잉 게임에서 데미지가 초기엔 1~100 사이로 시작합니다. 이런 데이터는 작은 정수값으로 저장할 수 있을겁니다. 하지만 점점 강해질수록 억단위 데미지가 들어가는 경우를 볼 수 있습니다. 억 단위 데미지를 저장하려면 어떨까요? 서버로 들어오는 데이터가 말도 안되게 엄청나질겁니다. 이럴때 데이터를 2개 이상의 데이터로 분리해서 관리할 수 있다면 억 단위 이상의 큰 숫자도 관리할 수 있습니다.