non-blocking UUID generator
UUID
- UUID(Universally unique identifier) 는 이름 그대로 범용 고유 식별자 이다.
- random 한 문자열로 오해할 수 있으나, 특정 조건으로 생성한 난수열을 바탕으로 생성하는 128bit 길이의 수이다.
- 흔히 아는 88888888-4444-4444-4444-bbbbbbbbbbbb 같은 형태의 UUID string 은 128bit 수를 humanify 한 문자열의 불과하다.
Table of Contents
UUID 레코드 레이아웃
이름 | 길이 (byte) | 길이 (hex) | 길이 (bits) | 내용 |
---|---|---|---|---|
time_low | 4 | 8 | 32 | 시간의 low 32비트를 부여하는 정수 |
time_mid | 2 | 4 | 16 | 시간의 middle 16비트를 부여하는 정수 |
time_hi_and_version | 2 | 4 | 16 | 최상위 비트에서 4비트 “version”, 그리고 시간의 high 12비트 |
clock_seq_hi_and_res clock_seq_low | 2 | 4 | 16 | 최상위 비트에서 1-3비트는 UUID의 레이아웃형식, 그리고 13-15비트 클럭 시퀀스 |
node | 6 | 12 | 48 | 48비트 노드 id |
UUID.randomUUID vs ?
- Java 에서 UUID 값을 생성할 때에는 UUID.randomUUId() 메서드를 사용한다.
- WAS 형태의 application 은 multithread 환경에서 동작하는데, 이 때 contention 이 발생하면서 UUID 생성에 병목이 발생한다.
- 병목의 원인은
- UUID 내부에서 SecureRandom 클래스를 사용한다.
- 이 코드내에서 synchronized 블록이 있음.
- 동시에 여러 스레드에서 접근 시 blocking 이 되고 병목이 발생함.
synchronized (this) { secureRandomSpi.engineNextBytes(bytes); }
- JUG(Java UUID Generator) 같은 라이브러리 내에서도
- Generators → UUIDTimer → public synchronized long getTimestamp()
- 결국 현재의 timestamp 값을 가져오기 위해 blocking 이 발생함.
- BLOCKED 66.9% 70.3% com.fasterxml.uuid.UUIDTimer.getTimestamp
- 이를 해결하기 위한 방법으로 /dev/random -> /dev/urandom , /dev/.urandom 등이 존재하나
- 별도의 VM 옵션이 필요
- 시스템 별로 의존성이 달라짐
- 따라서 non-blocking 의 UUID generation 을 위해 ThreadLocalRandom 을 이용한다.
UUID Generator
public final class RandomGenerator {
private RandomGenerator() {
}
private static final ThreadLocalRandom random = ThreadLocalRandom.current();
public static UUID getUUID() {
// https://github.com/apache/openwhisk/issues/2747
return new UUID(random.nextLong(), random.nextLong());
}
public static String getUUIDString() {
return getUUID().toString();
}
public static long getLong() {
return random.nextLong();
}
}
Benchmark 결과
@Benchmark
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public void test1() {
String uuid = UUID.randomUUID().toString();
}
@Benchmark
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public void test3() {
String uuid = RandomGenerator.getUUIDString();
}
Benchmark | Mode | Score | Units | Comparison |
---|---|---|---|---|
RandomGeneratorBenchmarkTest.test1 | thrpt | 2143 | ops/ms | 1x |
RandomGeneratorBenchmarkTest.test3 | thrpt | 464856 | ops/ms | 198x |
Benchmark Mode Cnt Score Error Units
RandomGeneratorBenchmarkTest.test1 thrpt 2143.575 ops/ms
RandomGeneratorBenchmarkTest.test1:stack thrpt NaN ---
RandomGeneratorBenchmarkTest.test3 thrpt 464856.130 ops/ms
RandomGeneratorBenchmarkTest.test3:stack thrpt NaN ---
References
- 범용 고유 식별자 wikipedia
- Use non-blocking UUID generation in controller
- Performance of Random UUID generation with Java 7 or Java 6
- Java UUID generation – Performance impact
카테고리: 개발노트
0개의 댓글