Snowflake ID とは
Snowflake ID は、分散システム上で中央集権的な調整機構なしに一意の識別子を生成するために用いられる 63 ビットの整数です。Twitter は 2010 年にこの形式を開発し、シャーディングされた MySQL クラスタに書き込む数十台のアプリケーションサーバーではスケールしきれなかった、データベースの自動採番シーケンスを置き換えました。各 Snowflake ID は符号付き 64 ビット整数であり、最上位ビットは常にゼロ、残る 63 ビットのペイロードは 4 つのフィールドに分割されます。すなわち、41 ビットのタイムスタンプオフセット、5 ビットのデータセンター識別子、5 ビットのマシン識別子、そして 12 ビットのシーケンス番号です。このレイアウトにより、単一の Snowflake サービスノードは 1 ミリ秒あたり最大 4,096 個の一意な ID を生成でき、数百のワーカープロセスにわたるデプロイでは、理論上毎秒数百万 ID のスループットを達成します。
Snowflake ID は単調増加します。同一エポック内では、新しい ID は常にそれ以前の ID より大きくなります。ただし、ノード間で厳密に順序付けられるわけではありません。同じミリ秒内に動作する 2 台のマシンは、互いに交錯する ID を生成します。これは意図的なトレードオフであり、この方式は完全な順序付けを犠牲にして、絶対的な運用上の独立性を獲得しています。各ワーカーは、自身のデータセンター番号とマシン番号、および現在時刻さえ把握していれば、ピアやロックサービスに一切問い合わせることなく、グローバルに一意な識別子を生成できます。
63 ビット識別子の構造
Snowflake ID は 63 ビットの整数であり、最上位ビットから最下位ビットに向かって次のフィールドで構成されます。
- 41 ビットのタイムスタンプ — カスタムエポックからの経過ミリ秒。
- 5 ビットのデータセンター ID — ワーカーをホストする物理データセンターを識別します。
- 5 ビットのマシン ID — そのデータセンター内の個々のホストまたはプロセスを識別します。
- 12 ビットのシーケンス番号 — ミリ秒単位のカウンターで、クロックが進むたびにゼロにリセットされます。
このレイアウトを正確に表現するならば、「41 ビットのタイムスタンプ、5 ビットのデータセンター、5 ビットのマシン、12 ビットのシーケンス」となります。これらのフィールドは合計で 63 ビットを占有し、先頭の符号ビットはゼロに設定されるため、Java や C# などの言語において符号付き 64 ビット整数に無理なく収まります。
Twitter エポックとタイムスタンプコンポーネント
すべての Snowflake ID は、カスタムエポックから計測されたタイムスタンプオフセットを保持します。その値は 1288834974657 ミリ秒です。この値はおおよそ 2010-11-04T04:42:54.657Z に相当し、Twitter 内部での Snowflake デプロイ開始時期に合わせて選定されました。Unix エポックではなくカスタムエポックを使用することで、41 ビットのタイムスタンプフィールドはオーバーフローするまで約 69 年分の範囲を表現できます。このフィールドが保持できる最大タイムスタンプ値は 2^41 − 1、すなわち 2,199,023,255,551 ミリ秒であり、エポックから約 69.7 年後、つまり 2080 年代にロールオーバー時期を迎えます。
タイムスタンプをエンコードするには、現在の Unix エポックミリ秒からエポック値を減算し、その結果を 22 ビット左シフトして、下位 3 つのフィールドのための領域を確保します。エポックより前のタイムスタンプが入力された場合は無効であり、拒否しなければなりません。
データセンターとマシンのノード識別
5 ビットのデータセンターフィールドと 5 ビットのマシンフィールドは、それぞれ 0 から 31 までの値を受け付け、デプロイ全体で合計 1,024 個の一意なノード識別子を提供します。ワーカーは起動時にデータセンター ID とマシン ID を割り当てられます。通常は設定ファイル、ZooKeeper のようなコーディネーションサービス、またはコマンドライン引数を通じて行われます。割り当てはフリート全体で一意でなければなりません。同じ (データセンター, マシン) の組を共有する 2 つのワーカーは、クロックがずれていない限り、衝突する ID を生成してしまいます。
これらのフィールドは、データセンター値を 17 ビット左シフト、マシン値を 12 ビット左シフトし、シフト後の値を 63 ビット整数に OR 演算で挿入することで ID に組み込まれます。合計 1,024 ノードという数は、ほとんどの実環境のデプロイには十分ですが、1,024 を超えるワーカーを必要とする環境では、スループットまたはエポック範囲を犠牲にして、シーケンスフィールドまたはタイムスタンプフィールドからビットを借用することが可能です。
シーケンスカウンターとクロック境界
12 ビットのシーケンスフィールドは、Snowflake 設計の中核を担う機構です。これは 0 から 4,095 まで動作し、同一ミリ秒内に ID が生成されるたびに 1 ずつインクリメントされます。シーケンスが 4,095 に達すると、ワーカーはシステムクロックが次のミリ秒に進むまでビジーループで待機し、進んだ時点でシーケンスはゼロにリセットされて生成が再開されます。これにより、単一ノードは 1 ミリ秒あたり最大 4,096 ID のバーストレートを得ます。
クロックのドリフトとクロックの巻き戻しは、Snowflake アルゴリズムにおける最も重大な 2 つの故障モードです。システムクロックが逆行した場合 — それが NTP 補正、仮想マシンの移行、あるいは手動変更のいずれによるものであれ — ワーカーは、以前に生成した ID よりも小さいタイムスタンプを持つ ID を生成する可能性があり、一意性の保証が破綻します。標準的な対策は、クロックの巻き戻しが検出された時点で ID 生成を停止し、エラーを発生させ、クロックが最後に観測されたタイムスタンプに追いつくまでリクエストの処理を拒否することです。ダウンタイムを許容できないデプロイでは、専用のタイムサービスや論理クロック層の導入を検討すべきです。
実例
次の入力値を考えます。Unix エポックタイムスタンプ 1700000000000 ミリ秒、データセンター ID 7、マシン ID 13、シーケンス番号 4095。
エンコード。 まずタイムスタンプオフセットを計算します。1700000000000 から Snowflake エポック 1288834974657 を減算すると 411165025343 が得られます。このオフセットを 22 ビット左シフトして 1724551110456246272 を得ます。データセンター値 7 を 17 ビット左シフトして 917504 を得ます。マシン値 13 を 12 ビット左シフトして 53248 を得ます。シーケンス番号はシフト不要です。これら 4 つの項をビット単位 OR で結合すると、最終的な Snowflake ID 1724551110457221119 が生成されます。
デコード。 ID 1724551110457221119 から元のフィールドを復元するには、下位 12 ビットをマスクしてシーケンス 4095 を抽出します。12 ビット右シフトして下位 5 ビットをマスクすると、マシン ID 13 が復元されます。17 ビット右シフトして下位 5 ビットをマスクすると、データセンター ID 7 が復元されます。22 ビット右シフトすると、タイムスタンプオフセット 411165025343 が得られます。エポック 1288834974657 を加算すると、元の Unix エポックタイムスタンプ 1700000000000 が復元されます。
すべてのフィールドが割り当てられたビット幅に収まり、エンコード時に情報が一切失われないため、往復変換は正確です。
精度と制限事項
Snowflake のエンコード方式は、すべての入力が有効範囲内にある限り、決定的かつ可逆的です。タイムスタンプオフセットは非負の 41 ビット整数でなければならず、データセンター ID とマシン ID は 0 から 31 の範囲内、シーケンスは 0 から 4,095 の範囲内でなければなりません。これらの範囲外の入力は無効として拒否されます。
この方式は閏秒やサブミリ秒精度を考慮していません。ホストのシステムクロックに依存しており、クロックはドリフトしたり、外部プロセスによって調整されたりする可能性があります。大規模な NTP ジャンプによってシステムクロックが進められたデプロイでは、オフセットフィールドは正しく進みますが、その間シーケンスカウンターはアイドル状態にあるため、未発行の ID が生じる期間が残ります。これは一意性には無害ですが、ID の時系列に不連続を生じさせます。
同じ (データセンター, マシン) の組を共有し、ネットワーク分断されたワーカーが同時にアクティブになった場合、衝突する ID を生成します。識別子空間は 1,024 個の一意なノードスロットを提供しており、その数を超える場合はカスタムのビットレイアウトバリアントが必要です。
参考資料
- Twitter Snowflake リポジトリ: https://github.com/twitter-archive/snowflake/tree/snowflake-2010
- オリジナルの発表記事: https://blog.x.com/engineering/en_us/a/2010/announcing-snowflake
編集記録
本記事は、Twitter の 2010 年のリファレンス実装で定義された Snowflake ID 形式について解説しています。ビットレイアウトとエポック値は、オープンソースの Scala ソースコードから直接引用しています。実例は、同じ値をエンコードおよびデコードして往復変換を確認する手計算によって検証されています。クロックの巻き戻しとノード制限に関する議論は、分散 ID 生成に関するエンジニアリング文献に記録された運用経験を反映したものです。
本記事は、ビットレイアウトを変更したサードパーティの実装やバリアント — たとえば 10 ビットのマシン ID、異なるエポック、あるいはコーディネーションサービスから取得するワーカー ID フィールドを使用するもの — については扱っていません。それらのバリアントは、オリジナルの Snowflake 仕様の範囲外です。 著者: SoupCalc編集チーム 最終レビュー: 2026年8月11日