티스토리 뷰

golang

xid: golang GUID 생성 package 둘러보기

주먹불끈 2019. 8. 16. 19:21

개요

 

github.com/rs/xid 패키지의 GUID 생성 방법을 챙겨보자

 

관련링크

- GoDoc: https://godoc.org/github.com/rs/xid

- GitHub (sourcegraph) : https://sourcegraph.com/github.com/rs/xid

 

xid 대하여

 

GUID generator 이며 Mongo Object ID 알고리즘을 사용한다.

- 링크: https://docs.mongodb.org/manual/reference/object-id/

 

- 4-byte value representing the seconds since the Unix epoch,
- 3-byte machine identifier,
- 2-byte process id, and
- 3-byte counter, starting with a random value.

4바이트: Unix time 초를 의미

3바이트: 머신의 id

2바이트: process id

3바이트: 랜덤한 값의 카운터를 의미 

 

따라서

1) 초마다 다른 GUID 보장

2) 머신마다 다른 GUID 보장

3) 같은 머신 내에서 프로세스가 생성될때마다 다른 GUID 보장

4) 1 내에 최대 24bit 만큼의 다른 GUID 생성 보장

 

 

이렇게 12바이트의 bynary 표현되며

base32 패딩 없이 encoding 하여 string 으로 변환할 있다. 20 byte 된다.

- 사용하는 base32 hex 값은 sortable 하다.

- 사용하는 문자는 알파벳 소문자 a to v 그리고 숫자 0 to 9 이다. 정규식으로 표현하면 [`0-9a-v]{20}`] 이다.

base64 쓰지 않는 이유: 대소문자를 같이 쓰고, 알파벳과 숫자가 아닌 문자 (+, /) 다양한 시스템간의 전송에 문제가 있기 때문

base36 쓰지 않는 이유

- 표준이 아니다.

- 결과 size 예측할 없다.

- sortable 하지 않다

 

UUID 16 바이트이며, snowflake 8 바이트이다. xid 중간쯤인 12 바이트이다.

설정이나 중앙의 생성서버가 필요없다.

 

 

특징들을 다시 정리해보자.

 

- Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake
- Base32 hex encoded by default (16 bytes storage when transported as printable string)
- Non configured, you don't need set a unique machine and/or data center id
- K-ordered
- Embedded time with 1 second precision
- Unicity guaranteed for 16,777,216 (24 bits) unique ids per second and per host/process

- 생성되는 크기는 12 바이트로 snowflake 보다 크고, UUID 보다 작다

- Base32 hex 인코드 있다. (여기서 20 바이트가 아니라 16 바이트라고 나올까?)

- 설정이 필요없고, 특정 머신이나 데이터 센터 아이디도 필요 없다.

- K-ordered 진짜 정렬된 것과의 값의 차이가 K 이내로 차이가 나는 것을 말한다.

- https://www.quora.com/What-is-a-k-ordered-array

사진을 예로 들면 A 가 정렬되어 있으면 [1,2,3,4,5,6,7,8] 인데

위의 A 를 보면 [1, 4, 2, 6, 3, 7, 5, 8] 입니다.

각각의 인덱스에 제대로 정렬되었다면 있어야 할 숫자와의 차이가 2 이하이므로

이 경우 [1, 4, 2, 6, 3, 7, 5, 8] 는 2-ordered 라고 부릅니다.

- 1초의 precision 임베드 타임을 가진다. (무슨 말인지 모르겠음)

- 초당 24 bit ( 3바이트) unique id 가진다.

- 이것은 마지막 3 bytes 초당 최대 16,777,216 개까지 생성이 보장된다는 것이다.

- 아래에서 테스트해보니 nanosecond 까지도 생성이 되기는 하였다.

 

실제로 생성해보자

 



 

xid.New()

 

- xid.New() 라고 하면 12 바이트의 []byte 생성된다.

- 이것은 위에서 언급된 4바이트의 시간 + 3바이트의 machine id + 2바이트의 process id + 3바이트의 임의의 숫자에서 증가하는 숫자이다.

- 출력을 보면 처음 12개의 이진수가 보인다.

1) 처음 4바이트는 초단위의 Unix time 이다. 4번째 바이트를 보면 1 증가하는게 보일 것이다. (time.Sleep 1초씩 주었으므로)

2) 다음 3바이트는 machine id 이다. 같은 컴퓨터에서 돌린다면 값은 변하지 않을 것이다.

3) 세번째 2바이트는 process id 이므로 프로그램 실행시마다 값이 달라질 것으로 보인다.

4) 네번째 3바이트는 임의의 숫자에서 1 증가하는 값이다.

이렇게 보면 실제로 1 이내에 변화가 보장된 값은 4번째, 12번째 바이트가 것이다.

 

한번 실행해 보았다. 프로세스 아이디가 바뀐 것이 보일 것이다.

 


 

time.Sleep(1 * time.Millisecond)

이번에는 코드의 time.Sleep 1 Millisecond으로 코드 변경을 해보았다.

그래도 뒤의 3바이트는 바뀌는 것이 보인다. 호출될 때마다 증가하는 것이다.

 


 

time.Sleep(1 * time.Nanosecond)

마지막으로 1 Nanosecond 간격으로 호출하였음에도 문제없이 증가되는 것을 보여준다.

 


 

생성코드를 들여다보자

 

링크: https://sourcegraph.com/github.com/rs/xid/-/blob/id.go

 

xid.New() 라고 하면 12 바이트의 ID 생성되며

xid.New().String() 이라고 하면 20 바이트의 String 생성된다. base32hex 변환되는 것이다.

 

1) xid.New() 실행하면 현재 시간을 파라미터로 넣어서

- NewWithTime() 함수를 호출한다.

 

2) System Endian 문제가 없도록 BigEndian 으로 변경하여준다.

- id[0:3] 에는 시간정보 4바이트가 들어가게 된다.

 

3) machineID[] readMachineID() 함수를 통해

- OS 별로 machineID 생성해준다.

 

4) pid 역시 os.Getpid() 함수로 얻어내고

 

5) objectIDCounter randInt() 처음 생성되며

- 이후 atomic.AddUint32() 통해서 1 증가된다.

 

이렇게 12 바이트가 생성된다.

 

이걸 string 으로 만드는 것은 base32hex encoding 쓴다.

- 아래를 참고하면 된다.

* 여기서 굳이 unsafe.Pointer(&text) 쓰는 이유는 모르겠음

 

참고. base32hex

 

링크: https://www.wikiwand.com/en/Base32

 


 

base32hex 결국 아래의 왼쪽 이진수들을 5 비트씩 떼어내어 위의 대로 바꿔주는 것이다.

 

1) 위의 이진수를 5비트씩 둘로 떼어 보면 01011 = 11, 10101 = 21 이다.

2) 따라서 11번째인 b, 21번째인 l encoding 되는 것이다.

3) 오른쪽의 String bl 시작하는것이 보일 것이다.

 

하나만 덧붙여 이야기 하자면, 12바이트 = 12 x 8 = 96 비트 이므로 마지막 5비트는 10000 또는 00000 것이다. 따라서 g 또는 0 된다

반응형
반응형
잡학툰 뱃지
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함