
Global ID Generator글로벌 ID 생성기
글로벌 ID 생성기는 분산 환경에서 충돌 없이 전역적으로 고유한 ID를 생성하는 시스템이다. Twitter의 Snowflake ID가 업계 표준이 됐다.
요구사항
- 유일성: 전체 시스템에서 중복 없음
- 정렬 가능: 생성 시간 순 정렬
- 숫자형: 64비트 정수 (DB 인덱스 효율)
- 초당 수만 건 생성 가능
- 고가용성: 단일 장애점 없음Snowflake ID 구조 (64비트)
63 22 12 0
│ │ │ │
┌───────┬─────┬────┐
│타임스탬프│데이터센터│시퀀스│
│ 41bit │+머신ID│12bit│
│ │ 10bit│ │
└───────┴─────┴────┘
- 부호 비트 (1bit): 항상 0 (양수)
- 타임스탬프 (41bit): 밀리초, epoch부터 약 69년
- 데이터센터 ID (5bit): 32개
- 머신 ID (5bit): 데이터센터당 32개
- 시퀀스 (12bit): 밀리초당 4096개Snowflake ID 구현
python
import time
import threading
class SnowflakeIDGenerator:
EPOCH = 1288834974657 # 2010-11-04 (Twitter epoch)
WORKER_ID_BITS = 5
DATACENTER_ID_BITS = 5
SEQUENCE_BITS = 12
MAX_WORKER_ID = (1 << WORKER_ID_BITS) - 1 # 31
MAX_DATACENTER_ID = (1 << DATACENTER_ID_BITS) - 1 # 31
MAX_SEQUENCE = (1 << SEQUENCE_BITS) - 1 # 4095
WORKER_SHIFT = SEQUENCE_BITS # 12
DATACENTER_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS # 17
TIMESTAMP_SHIFT = DATACENTER_SHIFT + DATACENTER_ID_BITS # 22
def __init__(self, worker_id: int, datacenter_id: int):
assert 0 <= worker_id <= self.MAX_WORKER_ID
assert 0 <= datacenter_id <= self.MAX_DATACENTER_ID
self.worker_id = worker_id
self.datacenter_id = datacenter_id
self.sequence = 0
self.last_timestamp = -1
self.lock = threading.Lock()
def generate(self) -> int:
with self.lock:
ts = int(time.time() * 1000)
if ts < self.last_timestamp:
raise Exception("시계가 뒤로 갔습니다!")
if ts == self.last_timestamp:
self.sequence = (self.sequence + 1) & self.MAX_SEQUENCE
if self.sequence == 0:
while ts <= self.last_timestamp:
ts = int(time.time() * 1000)
else:
self.sequence = 0
self.last_timestamp = ts
return (((ts - self.EPOCH) << self.TIMESTAMP_SHIFT) |
(self.datacenter_id << self.DATACENTER_SHIFT) |
(self.worker_id << self.WORKER_SHIFT) |
self.sequence)
# 사용
gen = SnowflakeIDGenerator(worker_id=1, datacenter_id=1)
new_id = gen.generate()
print(new_id) # 예: 1757736463432491008ID에서 타임스탬프 역산
python
def extract_timestamp(snowflake_id: int) -> str:
ts_ms = (snowflake_id >> 22) + 1288834974657
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ts_ms / 1000))