관계형 데이터베이스에서 각 레코드를 식별해야 한다. 일반적으로 새로운 레코드가 생성될 때 마다 +1이 되는 'auto_increment' 속성을 사용해서 자동생성되게 하면 되지 않나 라고 생각하는데 이는 대규모 서비스 설계에서는 그닥 좋은 방법이 아니다 왜냐
대규모 시스템 설계에서는 여러대의 데이터베이스 서버를 사용할 수 있기 때문이다.
일반적으로 그렇다. 데이터를 분산 저장하기 위함도 있고, 데이터 베이스가 죽었을 때 서비스를 계속 이어 나가려면 당연히 2대 이상의 데이터베이스 서버가 필요하겠지..
그럼 여기서 문제는 여러 서버에 분산되어 있는 데이터의 유일성을 어떻게 챙겨야할까 여기서 사용되는 개념이 유일 ID 생성기이다.
이를 구현하기 위한 방법은 크게 4가지가 있다.
일반적으로 레코드 생성시 사용하는 auto_increment기능을 활용하는 것이다. 다만 다음 ID값을 구할 때 1만큼 증가 시키는게 아니다. 예를들어 사용하는 mysql 서버가 3대라고 하면,
그럼 결과적으로 순차적으로 모든 중복되지 않는 유일한 ID값이 생성되게 된다.
하지만 얘는 아래의 이유로 구리다.
아마 어디선가 자주 봤던 방식일 것이다. 128비트짜리 랜덤한 수이다. UUID 중복 가능성이 매우매우매우 낮다. 위키피디아에서는
"중복 UUID가 1개 생길 확율을 50%까지 끌어 올리려면 초당 10억 개의 UUID를 100년 동안 계속해서 만들어야 한다."
라고 한다.
이 방식의 장점은 단순하다는 점이다. 라이브러리도 많아서 보편적으로 꽤 많이 사용하는 방식이다. 그리고 중복되지 않으니 자기가 쓸 ID를 알아서 만들기 때문에 서버 확장이니 축소에 용이하다.
하지만 단점도 존재한다.
일단 ID값이 128비트로 길며, 다중 마스터 복제 방식과 마찬가지로 시간순으로 정렬할 수 없다.
쉽게 생각하면 모든 데이터베이스 쓰기 요청이 하나의 서버로 들어가서 순차적으로 id를 발급 받는 것이다.
장점은 어떻게든 유일성이 보장되는 숫자로만 구성된 ID를 만들기 쉽다. 그리고 순차적으로 만들어지니 시간순으로 나열하기도 쉽겠다.
하지만 티켓 서버가 SPOF(Single-Point-of-failure)가 될 가능성이 크다. 쉽게 말해서 이 티켓 서버가 다운되면 모든 시스템에 영향을 줄 가능성이 크다. 따라서 여러대의 티켓서버를 준비해야 한다.
각재 격파 전략(divide and conquer)를 사용해보자. 생성해야 하는 ID의 구조를 여러 절(section)으로 나누는 것이다. 각 절 마다 가지고 있는 정보를 달리한 후 하나로 뭉쳐 ID로 사용하는 것이다. 아래 그림을 보자.
이런 방식으로 아이디에서 사용할 절 들을 독립적으로 나누어 사용하면된다. UUID와 비슷하다.
이렇게 하면 앞 단의 타임 스템프로 시간순으로 정렬할 수 있다. 그리고 1/1000초까지 체크하기 때문에 정확하게 같은 시점에 들어와서 생성되는 ID는 "거의" 없을 것이다. 설사 있더라도 생성하는 데이터센터ID, 서버ID등이 다르고 일련번호를 랜덤하게 생성하게 된다면. 정확히 같은 아이디의 생성은 자연적으로 불가능하게 된다.