왜 기본키 채번에 대해서 알아보는 것일까?

현재 실무에서 새 프로젝트를 진행하게 되었고 기존 프로젝트에서의 불편함을 개선하고자 고민했던 경험을 공유한다.

일반적인 프로젝트에서는 PK자동증가 값을 활용한 기본키 생성 전략을 사용하며 이전 프로젝트에서도 활용중이다.

아래와 같은 이슈로 인해 결론부터 논하자면 TSID를 사용하기로 결정했고 기본키 채번 사례와 장단점에 대해서 알아본다.

첫번째 이슈

프로젝트는 AWS에서 멀티 리전으로 구성되어 있으며 MSA 아키텍처를 활용중이다. 따라서 국가별 도메인별 디비가 독립적으로 존재한다.

이때 매출 등으로 인한 통계자료를 전체 데이터베이스에서 추출해야 되는 상황에 놓였다.

스노우플레이크를 활용하여 전체 디비를 하나로 데이터레이크를 구축할때 자주 문제가 되는 부분이 있다.

예를 들면 각 나라별 회원디비를 하나의 테이블로 통합할 경우 TABLE의 아이디값의  중복이슈가 발생하게 된다.

두번째 이슈

현재 이커머스 프로젝트에서 각 도메인 (정산, 주문) 등에서 스프링 배치를 활용하여 데이터 정합성 체크 및 데이터갱신을 진행중이다.

이때 대량데이터 등록을 위해 벌크연산(Bulk insert)를 사용중인데 Spring Data JPA를 사용중인 경우 save는 Insert 합치기가 적용되지 않는다.

따라서 JdbcTemplate와 같이 문자열 기반 네이티브 쿼리 방식으로 벌크연산을 사용중인 도메인 프로젝트가 대부분이다.


일반적으로 사용하는 Auto Increment 채번이 뭘까?

Auto Increment

다수의 클라이언트에서 디비에 유일성을 보장하는 PK(프라이머리 키)를 값을 동시에 삽입할 경우 중복 된 값에 대해서는 사용할 수 없다.
따라서 중복 체크가 필요하게 되고 이는 성능 저하의 원인이 된다.
이를 해결하기 위해 DBMS에서 관리하는 자동증가값인 AUTO INCREMENT를 사용한다.

Primary Key

보통 프로젝트에서의 모든 데이터의 저장공간은 RDB를 활용하게 된다.
그리고 DB TABLE의 특정 레코드를 식별하기 위해 모든 컬럼의 값을 결정하는 프라이머리키를 사용한다.

그런데 왜 이런 PK 사용을 하는 것일까?

관계형 데이터베이스의 각 테이블 주문, 주문상품이 있다면 외래키를 사용해서 유일성을 보장하고 서로를 참조한다. 이때 외래키가 바로 PK인 것이다.
이는 DBMS에서 not null, unique 사용을 강제하기때문에 관리상 큰 이점이 있다.

분산환경 채번 사례는 어떤것이 있을까?

위 이슈를 해소할 방법이 있을까?
기본키 채번 전략 4가지를 통해 알아보고자 한다.

1. DB별로 PK생성 규칙을 나누기

DB서버 증설 및 삭제작업이 쉽지 않고 관리가 어렵다는 단점이 있다.
  • PK시작값을 디비별로 다르게 사용하는 방법
  • 갈레라 클러스터 처럼 PK증분 기준을 디비별로 다르게 가져가는 방법

2. 중앙화된 PK관리 서버 사용

SPOF를 일으킬 수 있는 단점이 있다.
  • 플리커처럼 자동증가값을 티켓 서버에서 채번하여 중앙화된 서버를 두고 사용

3. 대체키 생성 규칙 사용

채번 규칙 설계 및 유지보수가 필요하다.
  • 문자열로 된 대체키로 중복되지 않는 식별자를 수동으로 생성해서 사용

4. 랜덤생성 키 사용

어플리케이션에서 유일키를 생성하기 때문에 확장과 성능적 이점이 있음

UUID,  KUSID

  • ID가 숫자형에 비해 데이터가 크고 ID를 시간순으로 정렬할 수 없어 DBMS검색 성능저하의 단점이 있음

ULID, 인스타그램ID, 스노우플레이크, 타임플레이크

  • 타임스탬프 기반으로, 대체키를 시간순으로 정렬하기 용이함

TSID (Time-Sorted Unique Identifier)

Twitter의 Snowflake](https://github.com/twitter-archive/snowflake/tree/snowflake-2010) 및 ULID Spec 의 아이디어를 결합
  • 세대 시간별로 정렬
  • 64비트의 정수로 저장
  • 13자의 문자열로 저장
  • 문자열 형식은 Crockford의 base32 로 인코딩
  • 문자열 형식은 URL 안전하고 대소문자를 구분하지 않으며 하이픈이 없음
  • UUID, ULID, KSUID보다 짧음

이슈를 해결하기 위한 결론은?

이슈와 아래 조건을 만족하는 채번전략인 TSID를 채택하였고 분산환경에서 중복없이 사용됨을 확인하였고 아직까지는 큰 문제없이 사용중이다.

  • 기존 소스코드 수정 영향도 최소화
  • 단일 시스템에서도 활용가능
  • 분산환경(각 리전별 도메인별 디비)에서 중복없이 사용 가능
  • Spring Batch 에서 JPA사용시 대량 삽입 수행가능
  • 키 생성 속도가 200(miliis) 내외
  • DBMS에서의 정렬이점 활용 가능
  • 병렬처리 및 동시성 보장

레퍼런스