[翻訳]Golangで良好な一意IDを生成する方法

4464 ワード

手帳アプリを開発していることを想像してみてください.各記事には一意のIDが必要です.調整できれば、一意のIDを生成するのは簡単です.最も簡単な方法は、データベースを使用することです.AUTOINCREMENTプロパティの列を使用して、新しい記事を挿入すると、データベースに一意のIDが生成されます.
しかし、もしあなたが調整できないなら?たとえば、Appがオフラインになったときに一意のIDを生成したい場合は、データベースに接続できません.
協調できない場合に一意のIDを生成する要求は、通常、分散システムから発生する.簡単な解決策はランダムIDを生成することである.16バイトの長さのランダム列を使用すると、同じランダム列を生成する確率はありません.これはよくある問題で、30年以上前にUUID/GUIDという標準を作成しました.
私たちはGUIDよりもっとよくすることができて、1つの良いランダムな一意IDは以下の原則に従います:1、一意性:基本原則、満たさなければなりません.2、並べ替え可能:ランダム一意ID文字列で並べ替え可能.3、時間属性を持つ:同じ時間内に、生成したIDは互いに近い.4、ランダム一意ID文字列は、エスケープすることなくURLの一部とする.5、短いほどいいです.
Goを使用して実装される類似コードは多くなく、1、使用時間をIDの一部とし、IDに時間属性を持たせるというルールに従っている.2、残りの部分をランダムデータで埋めます.3、符号化一意IDは文字列であり、並べ替え可能及びURL安全の条件を満たす.
次に、一意のIDを生成するGoパケットと、生成されたID文字列のフォーマットを示します.
Package
Id
Format
github.com/segmentio/ksuid
0pPKHjWprnVxGH7dEsAoXX2YQvU
4 bytes of time (seconds) + 16 random bytes
github.com/rs/xid
b50vl5e54p1000fo3gh0
4 bytes of time (seconds) + 3 byte machine id + 2 byte process id + 3 bytes random
github.com/kjk/betterguid
-Kmdih_fs4ZZccpx2Hl1
8 bytes of time (milliseconds) + 9 random bytes
github.com/sony/sonyflake
20f8707d6000108
~6 bytes of time (10 ms) + 1 byte sequence + 2 bytes machine id
github.com/oklog/ulid
01BJMVNPBBZC3E36FJTGVF0C4S
6 bytes of time (milliseconds) + 8 bytes random
github.com/chilts/sid
1JADkqpWxPx-4qaWY47~FqI
8 bytes of time (ns) + 8 random bytes
github.com/satori/go.uuid
5b52d72c-82b3-4f8e-beb5-437a974842c
UUIDv4 from
テストページをリフレッシュして、異なる時間IDフォーマットの変化を見ることができます.異なるパッケージを使用して、一意のIDのインスタンスコードを生成します.
import (
    "github.com/chilts/sid"
    "github.com/kjk/betterguid"
    "github.com/oklog/ulid"
    "github.com/rs/xid"
    "github.com/satori/go.uuid"
    "github.com/segmentio/ksuid"
    "github.com/sony/sonyflake"
)

// To run:
// go run main.go

func genXid() {
    id := xid.New()
    fmt.Printf("github.com/rs/xid:           %s
", id.String()) } func genKsuid() { id := ksuid.New() fmt.Printf("github.com/segmentio/ksuid: %s
", id.String()) } func genBetterGUID() { id := betterguid.New() fmt.Printf("github.com/kjk/betterguid: %s
", id) } func genUlid() { t := time.Now().UTC() entropy := rand.New(rand.NewSource(t.UnixNano())) id := ulid.MustNew(ulid.Timestamp(t), entropy) fmt.Printf("github.com/oklog/ulid: %s
", id.String()) } func genSonyflake() { flake := sonyflake.NewSonyflake(sonyflake.Settings{}) id, err := flake.NextID() if err != nil { log.Fatalf("flake.NextID() failed with %s
", err) } // Note: this is base16, could shorten by encoding as base62 string fmt.Printf("github.com/sony/sonyflake: %x
", id) } func genSid() { id := sid.Id() fmt.Printf("github.com/chilts/sid: %s
", id) } func genUUIDv4() { id := uuid.NewV4() fmt.Printf("github.com/satori/go.uuid: %s
", id) } func main() { genXid() genKsuid() genBetterGUID() genUlid() genSonyflake() genSid() genUUIDv4() }

完全なインスタンスコードはgenerate-unique-id/mainを参照してください.go
どのバッグを使えばいいですか?
上に列挙されているすべてのバッグはとてもいいです.しかし、個人的にはrs/xidsegmentio/ksuidの2つのバッグが好きです.oklog / ulidは、カスタムエントロピーの使用を可能にする(ランダム)ソースですが、複雑なAPIを使用する必要があります.sony / sonyflakeは最小ですが最もランダムです.Twitterの設計に基づいて、推文のIDを生成します.簡単にするために、サンプルコードはbase 16のsony / snoflakeをシーケンス化しています.他のライブラリで使用されているbase 62符号化では短くなりますが、他のライブラリではsony / snoflakeに対して開梱即用の機能を提供しています.自分でそれを実現しなければならない.最後の1つは、比較のためにRFC 4112からのUUID v 4である.
詳細:
  • https://segment.com/blog/a-brief-history-of-the-uuid/:ksuidの発展の歴史
  • https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html:Betterguidデザインのインスピレーション
  • http://antoniomo.com/blog/2017/05/21/unique-ids-in-golang-part-1/
  • http://antoniomo.com/blog/2017/05/28/unique-ids-in-golang-part-2/
  • http://antoniomo.com/blog/2017/06/03/unique-ids-in-golang-part-3/
  • https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake.html : details of Twitter’s snowflake on which sonyflake is based

  • 本明細書のコード:https://github.com/kjk/go-cookbook/tree/master/generate-unique-idGenerating good unique ids in Go