가상 면접 사례로 배우는 대규모 시스테 설계 기초 #7 (분산 시스템을 위한 유일 ID 생성기 설계)

박주진·2022년 5월 28일
0

그냥 관계형 디비의 auto increment 쓰면 어떨까?

  • 데이터베이스 서버 한대로는 요구를 감당할 수 없다. (분산 환경에서는 데이터 양이 많아서 한대로는 감당이 안된다는 뜻?)
  • 여러 데이터베이스 서버를 쓰는 경우에는 지연 시간을 낮추기 무척 힘들다. (어떤 지연 시간을 의미하는 거지?)

문제 이해 및 설계 범위 확정

  • ID는 유일해야 한다.
  • ID는 숫자로만 구성되어야 한다.
  • ID는 64비트로 표현될 수 있는 값이어야 한다.
  • ID는 발급 날짜에 따라 정렬 가능해야 한다.
  • 초당 10,000개의 ID를 만들 수 있어야 한다.

계략적 설계안 제시 및 동의 구하기

분산 시스템에서 유일성이 보장되는 ID를 만드는 방법은 여러 가지다.

다중 마스터 복제 (multi-master replication)

  • 여러 데이터베이스의 auto_increment를 활용하는 방안이다.
  • 현재 사용중인 데이터베이스 서버의 수 만큼 증가 시킨다.
  • 규모 확장성 문제 대응 가능
  • 데이터 베이스 수를 늘리면 초당 생산 가능 ID수도 늘릴 수 있다.
    하지만 중대한 단점
  • 여러 데이터 센터에 걸쳐 규모를 늘리기 어렵다.
  • ID의 유일성은 보장되겠지만 그 값이 시간 흐름에 맞춰 커지도록 보장할 수 없다. 예) 디비 서버가 두대 있을때 특정 한서버에서 계속 가져온다면 1->3->5->7 이렇게 커진다. 그리고 나서 다른 디비에서 가져오면 2가 나올것이다.
  • 서버를 추가하거나 삭제할 때도 잘 동작하도록 만들기 어렵다. 예) 중간에 추가 하거나 삭제하면 증가값을 중간에 바꿔야하는데 꼬이지는 않을까?

UUID (Universally Unique Identifier)

  • 컴퓨터 시스템에 저장되는 정보를 유일하게 식별하기 위한 128비트짜리 수
  • 충돌 가능성이 지극히 낮다.
    장점
  • 만드는 방법이 단순하다. 서버 사이에 조율이 필요 없으므로 동기화 이슈 없음
  • 각 서버가 자기가 쓸 ID를 알아서 만들기 때문에 서버 증설 삭제에 영향이 없어 쉽다.
    단점
  • ID가 128비트로 길다. 요구사항은 64 비트이기 때문에..
  • 시간순으로 정렬 불가능
  • ID에 숫자가 아닌 값이 포함될 수 있다.

티켓서버 (ticker server)

  • auto increment기능을 갖춘 데이터베이스 서버(ticket server)를 중앙 집중형으로 하나만 사용하는것
    장점
  • 유일성이 보장되는 오직 숫자로 구성된 ID를 쉽게 만들 수 있다.
  • 구현하기 쉽고, 중소 규모 어플리케이션에 적당하다.
    단점
  • 티켓 서버가 SPOF가 된다. 즉 장애가 나면 해당 서버에서 아이디를 발급받는 모든 서비스에 영향이 간다. 이런 이슈를 피하려면 티켓 서버를 여러대 준비해야하는데 그러면 데이터 동기화라는 또다른 문제를 해결해야 한다.

트위터 스노플레이크 (twitter snowflake)

sigin(1bit) | timestamp(41bit) | data center Id (5bit) | server Id (5bit) | 일련번호 (12bit)

  • sign: 현재는 쓰임새가 없고 나중을 위해 유보한다.(음수 양수 구분에 쓰일 수 있을듯)
  • timestamp : 기원 시각(epoch) 이후 몇 밀리초 경과했는지를 나타내는 값. (기준시각이 되는 epoch는 각자 원하는 시각으로 설정 가능함)
  • data-center-id: 데이터센터 아이디로 32(2^5)개 데이터센터를 지원 가능하다.
  • sever id: 데이터센터당 32(2^5)개 서버를 사용할 수 있다.
  • 일련번호: 각 서버에서 id를 생성할 때마다 이 일련번호를 1만큼 증가시킨다. 이 값은 1밀리초가 경과할 때마다 0으로 초기화 된다.
  • 깃 허브 지원종료로 비슷한 구현체인 ulid, timeflake 등으로 대체할 수 있을듯

상세 설계

  • snowflake를 채택한다.
  • 데이터 센터 ID와 서버 ID는 시스템이 시작할때 결정된다.
  • 데이터 센터 ID나 서버 ID를 잘못 변경하게 되면 충돌이 발생할 수 있으므로 신중해야한다.
  • 타임 스탬프나 일련번호는 ID 생성기가 돌고 있는 중에 만들어지는 값이다.

타임스탬프 섹션

  • 시간의 흐름에 따라 점점 큰 값을 갖게된다.
  • 41-bit으로 표현할 수 있는 최대값은 정해져 있고 이는 대략 69년에 해당한다. (69년이 지나면 id체계 변경 또는 기원 시각 변경을 고려해야함)

일련번호

  • 4096(2^12)개의 값을 가질 수 있다.
  • 밀리초 동안 하나 이상의 ID를 만들어 낸 경우에만 0보다 큰 값을 가지게 된다.

마무리

추가적으로 다음과 같은 부분을 논의하면 좋다.

  • 시계 동기화
    • 서버들이 모두 같은 시계를 사용한다고 가정하였다. 그래서 실제로는 여러 독립된 장비에서 실행되는 경우 NTP를 주로 사용한다.
  • 각 절의 길이 최적화
    • 동시성이 낮고 수명이 긴 애플리케이션이라면 일련번호 절의 길이를 줄이고 타임스탬프 절을 늘리는 것이 효과적일 수도 있다.
  • 고가용성
    • ID 생성기는 필수적인 컴포넌트이므로 아주 높은 가용성을 제공해야 한다.

질문

지연 시간을 낮추기 어렵다가 무슨 뜻? 아마 대규모 요청을 못견딘다?

다중 마스터 복제 여러 데이터 센터에 걸쳐 규모를 늘리기는 왜 어렵나?

  • 서버 추가 하기가 까다로워서?

다중 마스터 복제 서버 추가 삭제시 어떻게 대처?

티켓서버를 사용한 flickr

  • mysql 서버 두대를 이용해서 각각 짝수 홀수 id로 생성하게끔 하여 spof 해결
  • 각 도메인 별로 티켓 테이블을 따로 관리한다. (order_ticket, product_ticket)
  • 테이블 스키마
    CREATE TABLE `Tickets64` (
     `id` bigint(20) unsigned NOT NULL auto_increment,
     `stub` char(1) NOT NULL default '',
     PRIMARY KEY  (`id`),
     UNIQUE KEY `stub` (`stub`)
    ) ENGINE=InnoDB
  • 항상 하나의 row만 존재함
+-------------------+------+
| id                | stub |
+-------------------+------+
| 72157623227190423 |    a |
+-------------------+------+
  • 아래의 쿼리로 아이디를 생성한다는데.. 여러 서버에서 동시에 두 명령어가 atomic하게 실행이 되는가?
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();

Network Time Protocol

  • 시간 서버들로 부터 클라이언트가 시각을 동기화 하기 위해 사용하는 인터넷 프로토콜

0개의 댓글