티스토리 뷰
개요
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, |
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 | ||
- 생성되는 크기는 12 바이트로 snowflake 보다 크고, UUID 보다 작다 - Base32 hex 로 인코드 될 수 있다. (여기서 왜 20 바이트가 아니라 16 바이트라고 나올까?) - 설정이 필요없고, 특정 머신이나 데이터 센터 아이디도 필요 없다. - K-ordered 란 진짜 정렬된 것과의 값의 차이가 K 이내로 차이가 나는 것을 말한다. - https://www.quora.com/What-is-a-k-ordered-array
- 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이 된다.
'golang' 카테고리의 다른 글
Slack Slash Command - timezone current time 2/2 (0) | 2019.09.19 |
---|---|
Slack Slash Command - timezone current time 1/2 (0) | 2019.09.17 |
Go runtime AND goroutine (0) | 2019.07.23 |
Golang 의 동시성을 이용한 소수 찾기 (0) | 2019.07.22 |
Don't communicate by sharing memory, share memory by communicating (0) | 2019.07.19 |
- Total
- Today
- Yesterday
- strange
- API
- 체호프
- github
- Shortcut
- Bug
- ChatGPT
- OpenAI
- pool
- 2023
- 영화
- golang
- postgres
- websocket
- 잡학툰
- JIRA
- 독서
- 클린 애자일
- 제이펍
- bun
- intellij
- 독서후기
- notion
- 노션
- Gin
- go
- agile
- folklore
- 인텔리제이
- solid
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |