ホームページ >バックエンド開発 >Golang >Golang で Snowflake アルゴリズムを実装する方法

Golang で Snowflake アルゴリズムを実装する方法

PHPz
PHPzオリジナル
2023-04-13 14:56:551210ブラウズ

Snowflake は、Twitter によってオープンソース化された分散 ID 生成アルゴリズムです。次の方法を使用して、グローバルに一意の ID を生成します:

  1. 64 ビット ID (1 は符号ビット、41 は符号ビット)は時刻スタンプ、10は作業機ID、12はシリアル番号です。
  2. 分散システムの場合、グローバルな一意性は通常、タイムスタンプ、ワーカー マシン ID、シリアル番号を組み合わせることで保証できます。

この記事では、Golang で Snowflake を実装する方法を紹介します。

  1. 構造体と定数の定義

最初に、マシン ID、シリアル番号、最後に生成された ID などのデータを Snowflake アルゴリズムに保存するための構造体を定義する必要があります。タイムスタンプやその他の情報。

const (
    workerIdBits     = 10  // 机器ID位数
    sequenceBits     = 12  // 序列号位数
    workerIdMax      = -1 ^ (-1 << workerIdBits) // 最大机器ID
    sequenceMask     = -1 ^ (-1 << sequenceBits) // 序列号掩码
    timeShiftBits    = workerIdBits + sequenceBits // 时间戳左移位数
    workerIdShift    = sequenceBits               // 机器ID左移位数
)

type Snowflake struct {
    lastTimestamp uint64
    workerId      uint16
    sequence      uint16
}

その中で、後続の計算を容易にするために、各データの桁数、最大値、マスクなどの情報を表すために定数を使用します。

  1. ID 生成メソッドの実装

次に、グローバルに一意の ID を生成するメソッドを実装する必要があります。

  1. 現在のタイムスタンプを取得します。それが最後に生成された ID のタイムスタンプより小さい場合は、タイムスタンプが更新されて最後に生成された ID のタイムスタンプより大きくなるまで待ちます。 ID。
  2. 現在のタイムスタンプが最後に生成された ID のタイムスタンプと等しい場合は、シーケンス番号を増やします。シーケンス番号が最大値に達した場合は、次のタイムスタンプまで待機します。
  3. 現在のタイムスタンプが最後に生成された ID のタイムスタンプより大きい場合は、シーケンス番号をリセットして現在のタイムスタンプを記録し、ID を生成します。

具体的な実装は次のとおりです。

func (s *Snowflake) NextId() uint64 {
    var currTimestamp = uint64(time.Now().UnixNano() / 1e6)

    if currTimestamp < s.lastTimestamp {
        panic("Invalid timestamp")
    }

    if currTimestamp == s.lastTimestamp {
        s.sequence = (s.sequence + 1) & sequenceMask
        if s.sequence == 0 {
            currTimestamp = s.waitNextMillis(currTimestamp)
        }
    } else {
        s.sequence = 0
    }

    s.lastTimestamp = currTimestamp

    return ((currTimestamp - 1483228800000) << timeShiftBits) |
            (uint64(s.workerId) << workerIdShift) |
            uint64(s.sequence)
}

func (s *Snowflake) waitNextMillis(currTimestamp uint64) uint64 {
    for currTimestamp <= s.lastTimestamp {
        currTimestamp = uint64(time.Now().UnixNano() / 1e6)
    }
    return currTimestamp
}

実装では、時刻を表すために UNIX タイムスタンプを使用しますが、Snowflake アルゴリズムが ID を生成する時期が 2017 年から始まっているため、 need タイムスタンプから固定オフセット値 (1483228800000) を減算します。

  1. Snowflake オブジェクトを初期化する

最後に、Snowflake オブジェクトを初期化し、マシン ID を指定する必要があります。マシン ID は 0 ~ 1023 の整数である必要があり、異なるマシンの ID は異なることが保証されます。

func New(workerId int) *Snowflake {
    if workerId < 0 || workerId > workerIdMax {
        panic(fmt.Sprintf("Invalid worker ID, must be in [%d, %d]", 0, workerIdMax))
    }

    return &Snowflake{
        lastTimestamp: 0,
        workerId:      uint16(workerId),
        sequence:      0,
    }
}

上記の実装では、Golang のタイムスタンプ関数と二項演算子を使用して ID の一意性と連続性を確保し、下位のシーケンス番号によって ID の増加傾向を確保しました。タイムスタンプはミリ秒レベルまで正確であるため、Snowflake アルゴリズムは、同時実行性の高いシナリオで ID の競合を回避するのに十分な ID を生成できます。

以上がGolang で Snowflake アルゴリズムを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。