README.md (6809B)
1 # Universally Unique Lexicographically Sortable Identifier 2 3 ![Project status](https://img.shields.io/badge/version-1.3.0-yellow.svg) 4 [![Build Status](https://secure.travis-ci.org/oklog/ulid.png)](http://travis-ci.org/oklog/ulid) 5 [![Go Report Card](https://goreportcard.com/badge/oklog/ulid?cache=0)](https://goreportcard.com/report/oklog/ulid) 6 [![Coverage Status](https://coveralls.io/repos/github/oklog/ulid/badge.svg?branch=master&cache=0)](https://coveralls.io/github/oklog/ulid?branch=master) 7 [![GoDoc](https://godoc.org/github.com/oklog/ulid?status.svg)](https://godoc.org/github.com/oklog/ulid) 8 [![Apache 2 licensed](https://img.shields.io/badge/license-Apache2-blue.svg)](https://raw.githubusercontent.com/oklog/ulid/master/LICENSE) 9 10 A Go port of [alizain/ulid](https://github.com/alizain/ulid) with binary format implemented. 11 12 ## Background 13 14 A GUID/UUID can be suboptimal for many use-cases because: 15 16 - It isn't the most character efficient way of encoding 128 bits 17 - UUID v1/v2 is impractical in many environments, as it requires access to a unique, stable MAC address 18 - UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures 19 - UUID v4 provides no other information than randomness which can cause fragmentation in many data structures 20 21 A ULID however: 22 23 - Is compatible with UUID/GUID's 24 - 1.21e+24 unique ULIDs per millisecond (1,208,925,819,614,629,174,706,176 to be exact) 25 - Lexicographically sortable 26 - Canonically encoded as a 26 character string, as opposed to the 36 character UUID 27 - Uses Crockford's base32 for better efficiency and readability (5 bits per character) 28 - Case insensitive 29 - No special characters (URL safe) 30 - Monotonic sort order (correctly detects and handles the same millisecond) 31 32 ## Install 33 34 ```shell 35 go get github.com/oklog/ulid 36 ``` 37 38 ## Usage 39 40 An ULID is constructed with a `time.Time` and an `io.Reader` entropy source. 41 This design allows for greater flexibility in choosing your trade-offs. 42 43 Please note that `rand.Rand` from the `math` package is *not* safe for concurrent use. 44 Instantiate one per long living go-routine or use a `sync.Pool` if you want to avoid the potential contention of a locked `rand.Source` as its been frequently observed in the package level functions. 45 46 47 ```go 48 func ExampleULID() { 49 t := time.Unix(1000000, 0) 50 entropy := ulid.Monotonic(rand.New(rand.NewSource(t.UnixNano())), 0) 51 fmt.Println(ulid.MustNew(ulid.Timestamp(t), entropy)) 52 // Output: 0000XSNJG0MQJHBF4QX1EFD6Y3 53 } 54 55 ``` 56 57 ## Specification 58 59 Below is the current specification of ULID as implemented in this repository. 60 61 ### Components 62 63 **Timestamp** 64 - 48 bits 65 - UNIX-time in milliseconds 66 - Won't run out of space till the year 10895 AD 67 68 **Entropy** 69 - 80 bits 70 - User defined entropy source. 71 - Monotonicity within the same millisecond with [`ulid.Monotonic`](https://godoc.org/github.com/oklog/ulid#Monotonic) 72 73 ### Encoding 74 75 [Crockford's Base32](http://www.crockford.com/wrmg/base32.html) is used as shown. 76 This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse. 77 78 ``` 79 0123456789ABCDEFGHJKMNPQRSTVWXYZ 80 ``` 81 82 ### Binary Layout and Byte Order 83 84 The components are encoded as 16 octets. Each component is encoded with the Most Significant Byte first (network byte order). 85 86 ``` 87 0 1 2 3 88 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 89 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 90 | 32_bit_uint_time_high | 91 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 92 | 16_bit_uint_time_low | 16_bit_uint_random | 93 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 94 | 32_bit_uint_random | 95 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 96 | 32_bit_uint_random | 97 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 98 ``` 99 100 ### String Representation 101 102 ``` 103 01AN4Z07BY 79KA1307SR9X4MV3 104 |----------| |----------------| 105 Timestamp Entropy 106 10 chars 16 chars 107 48bits 80bits 108 base32 base32 109 ``` 110 111 ## Test 112 113 ```shell 114 go test ./... 115 ``` 116 117 ## Benchmarks 118 119 On a Intel Core i7 Ivy Bridge 2.7 GHz, MacOS 10.12.1 and Go 1.8.0beta1 120 121 ``` 122 BenchmarkNew/WithCryptoEntropy-8 2000000 771 ns/op 20.73 MB/s 16 B/op 1 allocs/op 123 BenchmarkNew/WithEntropy-8 20000000 65.8 ns/op 243.01 MB/s 16 B/op 1 allocs/op 124 BenchmarkNew/WithoutEntropy-8 50000000 30.0 ns/op 534.06 MB/s 16 B/op 1 allocs/op 125 BenchmarkMustNew/WithCryptoEntropy-8 2000000 781 ns/op 20.48 MB/s 16 B/op 1 allocs/op 126 BenchmarkMustNew/WithEntropy-8 20000000 70.0 ns/op 228.51 MB/s 16 B/op 1 allocs/op 127 BenchmarkMustNew/WithoutEntropy-8 50000000 34.6 ns/op 462.98 MB/s 16 B/op 1 allocs/op 128 BenchmarkParse-8 50000000 30.0 ns/op 866.16 MB/s 0 B/op 0 allocs/op 129 BenchmarkMustParse-8 50000000 35.2 ns/op 738.94 MB/s 0 B/op 0 allocs/op 130 BenchmarkString-8 20000000 64.9 ns/op 246.40 MB/s 32 B/op 1 allocs/op 131 BenchmarkMarshal/Text-8 20000000 55.8 ns/op 286.84 MB/s 32 B/op 1 allocs/op 132 BenchmarkMarshal/TextTo-8 100000000 22.4 ns/op 714.91 MB/s 0 B/op 0 allocs/op 133 BenchmarkMarshal/Binary-8 300000000 4.02 ns/op 3981.77 MB/s 0 B/op 0 allocs/op 134 BenchmarkMarshal/BinaryTo-8 2000000000 1.18 ns/op 13551.75 MB/s 0 B/op 0 allocs/op 135 BenchmarkUnmarshal/Text-8 100000000 20.5 ns/op 1265.27 MB/s 0 B/op 0 allocs/op 136 BenchmarkUnmarshal/Binary-8 300000000 4.94 ns/op 3240.01 MB/s 0 B/op 0 allocs/op 137 BenchmarkNow-8 100000000 15.1 ns/op 528.09 MB/s 0 B/op 0 allocs/op 138 BenchmarkTimestamp-8 2000000000 0.29 ns/op 27271.59 MB/s 0 B/op 0 allocs/op 139 BenchmarkTime-8 2000000000 0.58 ns/op 13717.80 MB/s 0 B/op 0 allocs/op 140 BenchmarkSetTime-8 2000000000 0.89 ns/op 9023.95 MB/s 0 B/op 0 allocs/op 141 BenchmarkEntropy-8 200000000 7.62 ns/op 1311.66 MB/s 0 B/op 0 allocs/op 142 BenchmarkSetEntropy-8 2000000000 0.88 ns/op 11376.54 MB/s 0 B/op 0 allocs/op 143 BenchmarkCompare-8 200000000 7.34 ns/op 4359.23 MB/s 0 B/op 0 allocs/op 144 ``` 145 146 ## Prior Art 147 148 - [alizain/ulid](https://github.com/alizain/ulid) 149 - [RobThree/NUlid](https://github.com/RobThree/NUlid) 150 - [imdario/go-ulid](https://github.com/imdario/go-ulid)