요구사항과 포기할 순서
ID 생성기는 만드는 것이 쉬워 보여서 요구사항을 건너뛰기 쉽습니다. 그런데 어떤 순서를 포기하는지에 따라 설계가 완전히 달라집니다.
| 항목 | 값 |
|---|---|
| 대상 | 공용 ID 발급 |
| ID 형식 | 64비트 정수 |
| 발급량 | 피크 초당 10만 |
| 발급기 | 64대 |
| 발급 지연 | 상위 1퍼센트가 1ms 이내 |
| 수명 | 최소 30년 |
| 정렬 | 대략 시간순으로 커진다 |
| 같은 밀리초 안 | 순서를 보장하지 않는다 |
| 중복 | 절대 허용하지 않는다 |
기능 요구사항과 범위 밖
| 구분 | 내용 |
|---|---|
| 이번에 만든다 | ID 발급, 여러 서비스가 함께 쓰기, 발급기 추가와 제거 |
| 범위 밖 | 빈틈 없는 연속 번호, ID로 발급 시각을 정확히 되돌리기, 문자열 ID, 발급 이력 조회 |
빈틈 없는 연속 번호를 뺀 것이 이 설계의 출발점입니다. 1, 2, 3처럼 빈틈이 없어야 한다면 모든 발급이 한 곳을 지나야 하고, 그러면 그곳이 처리량 상한이자 장애점이 됩니다. 빈틈을 허용하면 각 노드가 스스로 만들 수 있습니다.
왜 정렬이 필요한가
ID는 대개 저장소의 기본 키가 됩니다. 그 값이 시간순으로 커지면 새 행이 인덱스의 한쪽 끝에만 붙습니다. 그 부분만 메모리에 있으면 되므로 삽입이 값쌉니다.
무작위 값이면 삽입 위치가 전체에 흩어져 매번 다른 페이지를 건드립니다. 하루 86억 건 규모에서 이 차이가 디스크 접근 수를 정합니다.
정렬은 취향이 아니라 저장 비용 요구사항입니다. 이 이유를 말하지 못하면 왜 무작위 방식을 안 쓰는지 설명할 수 없습니다.
왜 64비트 인가
수명 30년 에 하루 86억 건이면 총 발급량이 약 9경 4천조입니다. 64비트 정수가 담는 범위가 그보다 훨씬 크므로 충분합니다.
| 크기 | 대가 |
|---|---|
| 64비트 | 정수 하나. 인덱스와 전송에 그대로 쓴다 |
| 128비트 | 저장과 인덱스가 두 배. 정수 연산으로 다루기 어렵다 |
크기가 두 배면 인덱스도 두 배이고, 인덱스가 메모리에 들어가는지가 조회 속도를 정합니다. ID 하나의 크기가 시스템 전체의 메모리 예산에 곱해집니다.
"대략" 시간순의 뜻
같은 밀리초 안에서는 순서를 보장하지 않습니다. 이 포기가 결정적입니다.
보장한다면: 같은 밀리초에 발급하는 노드들이 서로 조율해야 한다
포기하면: 각 노드가 혼자 만든다. 왕복이 0이 된다
지연 1ms 는 외부에 물어볼 시간이 없다는 뜻입니다. 조율을 없애야 지킬 수 있고, 조율을 없애려면 밀리초 안 순서를 포기해야 합니다.
무엇을 절대 포기하지 않는가
중복은 허용하지 않습니다. 같은 ID가 두 번 나오면 다른 두 데이터가 하나로 취급되고, 그 사실을 나중에 알아채기도 어렵습니다.
유일성은 확률이 아니라 구조로 보장해야 합니다. 뒤의 모든 판단에서 이 기준이 가장 앞섭니다.
- Q.ID 생성기의 요구사항을 어떻게 정리하시겠습니까
- Q.ID가 시간순으로 커져야 하는 이유가 무엇인가요
- Q.왜 64비트 로 정했나요