본문 바로가기

프로젝트/대학생 커뮤니티

[유지 보수성 개선] 기본키로 TSID를 사용해보자

TSID

1. 기본키로 TSID를 사용한 이유?

MSA 환경에서 기본키를 채번 할 때 각 서비스에서 사용하는 데이터베이스에서 기본적으로 사용하는 전략을 사용했다.

그러면 어떤 기본키 채번 전략을 사용했었는지 하나씩 살펴보겠다.

 

MySQL 데이터베이스를 사용하면서 auto increment 전략을 사용했다.

아이디는 숫자형으로 1부터 시작해서 데이터가 삽입될 때마다 1씩 증가한다.

외부로 노출되는 API에서 auto increment 되는 기본키를 사용할 경우 보안적으로 좋지 않다.

 

MongoDB 데이터베이스를 사용하면서 ObjectId를 사용했다.

ObjectId는 12바이트로 처음 4바이트는 timestamp를 나타내고

다음 5바이트는 머신과 process마다 고유한 값을 나타내고 다음 3바이트는 counter를 나타낸다.

 

모든 서비스에서 편리성을 위해 기본키의 형식을 통일하도록 하고

분산환경에서 유일성을 보장하면서 보안적으로 안전하고 시간순으로 정렬도 가능한 특징을 고려해서

생성전략으로 TSID를 사용하기로 했다. 

 

2. TSID

TSID는 시간순으로 정렬가능한 고유 식별자로 아래와 같은 라이브러리를 사용했다.

dependencies {
	implementation("com.github.f4b6a3:tsid-creator:5.2.6")
}

 

TSID는 64비트로 42비트는 timestamp를 나타내고 10비트는 node를 나타내고 12비트는 counter를 나타낸다.

reentrant lock을 사용해서 lock을 잡고 생성한다.

 

node는 tsidcreator.node가 명시되어있으면 명시된 숫자 문자열을 사용하고 없으면 랜덤값을 사용한다.

node는 서버마다 고유한 값을 가지도록 하는 것이 좋으므로 고유한 값으로 명시하는 것이 좋다.

 

tsid는 64bit 정수형으로 생성되는데 문자열로 변환해서 사용할 수 있다.

base32 인코딩 방식으로 5비트마다 문자로 변환한다.

 

3. Reentrant Lock

java의 java.util.concurrent.locks 패키지에서 동기화를 위해 제공하는 lock의 구현체이다.

 

이름에서 알 수 있듯이 동일한 스레드가 동일한 lock을 여러번 획득할 수 있다는 것이 특징이다.

lock을 획득한 개수는 내부적으로 holdCount라는 변수로 관리되고 holdCount가 0이 될때 lock을 반환할 수 있다.

하나의 스레드가 lock을 획득한 상태에서 다른 스레드가 lock을 획득하려고하면

해당 스레드는 대기 상태로 전환되며 대기열에 등록이 된다.