7장 분산 시스템을 위한 유일 ID 생성기 설계
분산 환경에서 관계형 데이터베이스의 기본키 설정인 auto_increment 를 사용하기 어렵다.
데이터베이스 서버 한 대로는 감당하기 어렵고, 여러 데이터베이스 서버를 쓸 경우 delay 를 낮추기 어렵기 때문이다.
문제 이해 및 설계 범위
- ID 는 유일할 것
- ID 는 숫자로 구성
- ID 는 64비트로 표현
- ID 는 발급 날짜 순으로 정렬 가능 해야 함
- 초당 10,000 개의 ID 생성 해야 함
개략적 설계안 제시 및 동의 구하기
유일성을 보장하는 ID 생성 방법
- 다중 마스터 복제 (multi-master replication)
- UUID (Universally Unique Identifier)
- 티켓 서버 (ticket server)
- 트위터 스노플레이크 (twiter snowflake) 접근법
다중 마스터 복제
데이터베이스의 auto_increment 를 활용하는 기법이다. 그러나 1씩 증가하는 것이 아닌 n(데이터 베이스 서버 수) 만큼
증가 하는 것이다.
데이터베이스 수를 늘리면 초당 생산 가능 ID를 늘릴 수 있다.
그러나 다음과 같은 단점이 있다.
- 여러 데이터 센터에 걸쳐 규모 늘리기 어려움
- ID 유일성 보장하나 그 값이 시간의 흐름에 맞추는 것을 보장하긴 어렵다.
- 서버 추가/삭제 시 잘 동작하도록 만들기 어렵다.
UUID
유일성이 보장되는 ID를 만드는 간단한 방법이다.
UUID 는 컴퓨터 시스템에 저장되는 정보를 식별하기 위한 128비트 수다.
충돌 가능성이 낮다. 또한 서버 간 조율 없이 독립적으로 생성 가능하다.
장점
- 만드는 방법이 단순하고 서버 사이 조율도 필요 없어 동기화 이슈가 없다.
- 각 서버가 ID를 만드는 구조라 규모 확장이 쉽다.
단점
- 128비트라서 길다.
- 시간순 정렬이 안 된다.
- 숫자가 아닌 다른 값이 포함될 수 있다.
티켓 서버
플리커는 분산 키본 키 (distributed primary key) 를 만들어 내기 위해 이 방법을 차용하였다.
하나의 티켓 서버에 여러 웹 서버가 붙는 방식으로 동작한다.
핵심은 auto_increment 기능을 갖춘 데이터베이스 서버 (티켓 서버)를 중앙 집중형으로 사용하는 것이다.
장점
- 유일성이 보장되고, 숫자로만 구성된 ID를 쉽게 만들 수 있다.
- 구현하기 쉽고, 중소 규모 애플리케이션에 적합하다.
단점
- 티켓 서버가 SPOF 가 된다. 만일 티켓 서버를 여러 대 만들게 되면 동기화 이슈가 발생할 것이다.
트위터 스노플레이크 접근법
ID 생성하기 전 생성해야 하는 ID 구조를 section 으로 분할해 보겠다.
- 사인 (sign) 비트: 1비트 할당. 음/양수를 구별하는 데 쓰일 수 있음
- 타임 스탬프: 41비트 할당. 기원 시각 (epoch) 이후로 몇밀리초가 경과했는지 나타낸다.
- 데이터 센터 ID: 5비트 할당. 25=32개 데이터 센터를 지원한다.
- 서버 ID: 5비트 할당. 데이터 센터 당 32개 서버 사용 가능
- 일련 번호: 12비트 할당. 각 서버에서 ID 생성할 때 1씩 증가시킨다. 1밀리초 경과 시 0으로 초기화 된다.
상세 설계
데이터 센터 ID 와 서버 ID 는 시스템 시작 시 결정되며, 운영 중에는 바뀌지 않는다. ID 충돌이 일어나기 때문이다.
타임 스탬프나 일련 번호는 ID 생성기 돌고 있는 중에 만들어지는 값이다.
타임 스탬프
시간이 흐를 수록 큰 값을 가지므로 ID 는 시간 순으로 정렬할 수 있다.
41비트로 표현할 수 있는 최댓값은 241-1=2199023255551밀리초이다.
대략 69년에 해당한다. 기원 시각을 현재에 가깝게 맞춰 오버 플로 시점을 늦추었다.
따라서 69년 지날 경우 기원 시각을 변경하거나 ID 체계를 변경하면 된다.
마무리
추가 논의 할 수 있는 부분
- 시계 동기화 (clock synchronization): 각 서버가 같은 시계를 사용한다고 생각했지만, 그러지 않을 수 있다.
NTP(Network Time Protocol)로 해결할 수 있다. - 각 section 동기화: 동시성(concurrency)이 낮고 수명이 긴 애플리케이션이라면 일련번호 섹션을 줄이고 타임 스탬프를 늘리
는 방식을 사용할 수도 있다. - 고가용성 (high availability): ID 생성기는 필수 불가결(mission critical) 컴포넌트 이므로 높은 가용성을 제공해야 한다.
8장 URL 단축기 설계
문제 설계 범위 설정
- URL 단축: 긴 URL 을 짧게 줄인다.
- URL redirection: 줄인 URL 로 HTTP 요청이 오면 원래 URL 로 연결
- 높은 가용성과 규모 확장성, 장애 감내 필요
개략적 추정
- 쓰기 연산: 매일 1억개 단축 URL 생성
- 초당 쓰기 연산: 1억/24/3600 = 1160
- 읽기 연산: 읽기 연산과 쓰기 연산의 비율을 10:1이라고 가정 (읽기 연산 11,600회 발생)
- URL 단축 서비스를 10년 운영한다 가정 시 1억x365x10 = 3650억 레코드 보관
- 축약 전 URL 평균 길이는 100이라 가정
- 10년 동안 36.5TB의 저장소가 필요
개략적 설계안 제시 및 동의 구하기
API 엔드포인트
클라이언트는 서버가 제공하는 API 엔드포인트를 이용하여 서버와 통신한다. 엔드포인트를 REST 스타일로 설계할 건데
URL 단축기는 두 개의 엔드포인트가 필요하다.
- URL 단축 엔드포인트: 클라이언트는 단축 URL 을 생성하고자 할 때 URL 을 인자로 실어 POST 요청 한다.
POST/api/v1/data/shorten
- 인자: {longUrl:longURLstring}
- 반환: 단축 URL
의 형태를 띤다.
- URL 리디렉션용 엔드포인트: 단축 URL 에 HTTP 요청이 오면 원래 URL 로 반환
GET/api/v1/shortUrl
- 반환: HTTP 리디렉션 목적지의 원래 URL
URL 리디렉션
단축 URL 을 받은 서버는 원래 URL 로 바꿔 301 응답 Location 헤더에 넣어 반환한다.
301과 302 응답의 차이가 있다
- 301 Permanently Moved: 해당 URL 에 대한 HTTP 요청의 처리 책임이 영구적으로 Location 헤더에 반환된 URL 로 이전되었다는 응답이다.
브라우저는 이 응답을 캐시한다. 추후 같은 URL 요청시 캐시된 원래 URL 로 요청을 보낸다. - 302 Found: 일시적으로 Location 헤더가 지정하는 URL 에 의해 처리한다는 응답이다.
따라서 항상 URL 단축 서버에 먼저 보내지고 원래 URL 로 리디렉션 되야 한다.
서버 부하를 줄이고 싶다면 301을 사용하는 것이 좋다. 트래픽 분석을 하고 싶으면 302를 쓰는 것이
클릭 발생률, 발생 위치 추적 등에 좋다.
URL 리디렉션은 해시 테이블로 구현하는 것이 가장 직관적이다.
- 원래 URL = hashTable.get(단축 URL)
- 301 or 302 응답 Location 헤더에 원래 URL 넣은 후 전송
URL 단축
긴 URL 을 해시 값으로 대응 시킬 때의 단축 URL 형태가 www.tinyURL.com/{hashValue} 라고 가정한다면
다음 요구사항을 충족해야 한다.
- 입력된 긴 URL 이 다른 값이면 해시 값도 달라야 한다.
- 계산된 해시 값은 원래 입력으로 주어졌던 긴 URL 로 복원 가능해야 한다.
상세 설계
데이터 모델
해시 테이블에 저장하는 것은 메모리가 유한하고 비싸기에 실제 시스템에서는 지양한다.
대신, 관계형 데이터베이스에 <단축 URL, 원래 URL>의 순서쌍을 저장하는 것이 좋다.
해시 값 길이
단축 URL 값을 hashValue 라고 가정한다. hashValue 는 [0-9, a-z, A-Z]의 문자들로 62개를 사용할 수 있다.
hashValue 길이를 정하기 위해서는 62n >= 3650억 인 n의 최소 값을 찾아야 한다.
n=7 이면 3.5조를 만들 수 있으므로 hashValue 는 7로 가정한다.
해시 함수 구현으로는 '해시 후 충돌 감소'와 'base-62 변환' 방법이 있다.
해시 후 충돌 해소
CRC32, MD5, SHA-1로 줄일 수 있지만 여전히 7보다 길다.
해시 함수 | 해시 결과 (16진수) |
---|---|
CRC32 | 5cb54054 |
MD5 | 5a62509a84df9ee03fe1230b9df8b94e |
SHA-1 | 0eeae7916c06853901d9ccbefbfcaf4de57ed85b |
첫 번째 해결 방법은 앞의 7 글자만 이용하는 것이다. 그러나 충돌 확률이 높아지는 단점이 있다.
따라서 충돌 시에는 longURL 뒤에 사전에 정한 문자열을 추가하여 다시 해시 값에 붙인다.
충돌은 해소하지만 단축 URL 을 쓸 때, 한 번 이상의 질의로 인해 오버헤드가 크다.
블룸필터를 사용하면 성능을 높일 수 있다.
블룸 필터는 어떤 집합에 특정 원소가 있는지 검사하는 기술로, 확률론에 기초했고 공간 효율에 좋다.
base-62 변환
진법 변환 (base conversion)은 URL 단축기 구현할 때 흔히 사용하는 접근법이다.
62진법을 쓰는 이유는 hashValue에 사용하는 문자 개수가 62개라서 이다.
10진수 11157을 62진수로 변경했을 때, 2TX62이다.
- 따라서 단축 URL은 https://tinyUrl.com/2TX 가 된다.
비교
해시 후 충돌 해소 전략 | base-62 변환 |
---|---|
단축 URL 길이 고정 | 단축 URL 길이 가변적, ID 값 커지면 같이 길어짐 |
유일성 보장되는 ID 생성기 필요 x | 유일성 보장 ID 생성기 필요 |
충돌 할 수 있기 때문에 해소 전략 필요 | ID 유일성 보장 후 적용 가능 전략이라 충돌 존재 x |
ID 로부터 단축 URL을 계산하는 방식이 x => 다음에 쓸 URL 알아내는 것 불가능 |
ID 가 1씩 증가하는 값이라 가정하면, 단축 URL 가늠 가능하기 때문에 보안상 문제 될 수 있음 |
URL 단축기 상세 설계
URL 단축기는 논리적으로 단순하고 기능적으로 언제나 동작하는 상태로 유지하는 것이 핵심이다.
- 입력으로 긴 URL 받음
- 데이터베이스에 해당 URL 있는지 검사
- 있으면 단축 URL 가져와 클라이언트에 반환
- 없으면 유일 ID 생성 (기본키)
- 62진법 변환 적용하여 단축 URL 만든다.
- ID, 단축 URL, 원래 URL로 새 데이터베이스 레코드 만둔 후 단축 URL 을 클라이언트에 전달
ID 생성기는 단축 URL 을 만들 때 사용 되고, 전역적 유일성 (globally unique)이 보장돼야 한다.
URL 리디렉션 상세 설계
- 사용자가 단축 URL 클릭
- 로드밸런서가 발생한 요청을 웹서버에 전달
- 캐시에 있는 경우, 원래 URL 클라이언트에 반환
- 캐시에 없는 경우, 데이터베이스에서 꺼낸다. (데이터 베이스에 없다면 잘못된 단축 URL을 입력한 경우)
- URL을 캐시에 넣은 후 클라이언트에 반환
마무리
- 처리율 제한장치 (rate limiter): 엄청 많은 양의 URL 요청이 들어올 경우를 감안한다.
처리율 제한장치를 두면, IP 주소를 비롯한 필터링 규칙 등을 이용해 요청을 거를 수 있다. - 웹 서버의 규모 확장: 웹 계층은 무상태 계층이므로 웹 서버를 자유로이 증설, 삭제 가능하다.
- 데이터베이스의 규모 확장: 데이터베이스를 다중화하거나 샤딩하여 규모 확장성을 달성 할 수 있다.
- 데이터 분석 솔루션 (analytics): URL 단축기에 데이터 분석 솔루션을 통합해 두면 클릭 수나 시간대 클릭 통계 정보 등을 알 수 있다.
- 가용성, 데이터 일관성, 안정성: 대규모 시스템 운영을 위한 필수 요소이다.
참조
- Alex Xu, (2021). 가상 면접 사례로 배우는 대규모 시스템 설계 기초, 인사이트
'Study > 대규모 시스템 설계 기초' 카테고리의 다른 글
5. 안정 해시 설계, 6. 키-값 저장소 설계 (0) | 2024.06.23 |
---|---|
2. 개략적인 규모 추정, 4. 처리율 제한 장치의 설계 (0) | 2024.06.15 |
1. 사용자 수에 따른 규모 확장성 (0) | 2024.06.06 |