大規模なインターネット企業の分散IDプログラムの概要

IDは、伝統的なアプローチは、UUIDとデータベースの自動インクリメントIDを使用することで、データの一意の識別子であるインターネット企業、ほとんどの企業は、MySQLを使用している、と理由トランザクションをサポートする必要性から、それは多くの場合、InnoDBストレージエンジン、UUIDを使用しています無秩序長すぎると後に、それはInnoDB内で主キーとして適切ではない、IDをインクリメントサブテーブルながら、適切な、しかし、同社の事業開発と、データ量が増加し、データポイントテーブルの必要性であります各テーブルのデータは自分のペースで増加するだろう、IDの競合を発生しやすいです。そして、あなたも呼び出すことができるIDのうち、生成されたユニークなIDを生成するための別のメカニズムを担当する必要が分布するID、またはグローバルID分散のそれぞれのIDを生成し、次のメカニズムを分析します。

この記事では、特に、主にいくつかの要約を行うには、分析を詳細に説明しませんが、今後の記事では、プログラムの数を詳細に説明しました。

データベースの増分ID

自己増力IDデータベースに基づいて、依然として第一の実施形態では、データベースは、この例では、新たな別のテーブルを別のインスタンスが必要です。

次のようにテーブルの構造は次のとおりです。

CREATE DATABASE `SEQID`;

CREATE TABLE SEQID.SEQUENCE_ID (
	id bigint(20) unsigned NOT NULL auto_increment, 
	stub char(10) NOT NULL default '',
	PRIMARY KEY (id),
	UNIQUE KEY stub (stub)
) ENGINE=MyISAM;
复制代码

次の文を生成し、自己増力IDを取得するために使用することができます

begin;
replace into SEQUENCE_ID (stub) VALUES ('anyword');
select last_insert_id();
commit;
复制代码

スタブフィールドはここだけデータを挿入することは容易に、特別な意味はありません、唯一のデータは、インクリメントIDを生成するために挿入することができます。挿入のために我々は置き換え、同じスタブを置き換える使用し、それが挿入直接存在しない場合、それは最初に削除してから挿入が存在する場合には、データの指定された値が、存在するかどうかを見ていきます。

このIDは、実現可能な一方で発生機構は、別のMySQLの例を必要とし、分散されていますが、性能と信頼性に基づいている場合、十分、検討するたびに、システムIDを運用ニーズを、データベースが買収、低パフォーマンスを要求する必要がある、とデータベースインスタンスがダウンしている場合、それはすべてのビジネス・システムに影響を与えます。

データベースの信頼性の問題に対処するために、我々は、分散IDプログラムの第二世代を使用することができます。

マルチマスタデータベース

我々は2つのデータベースを持っている場合は形成するマスタースレーブモードのクラスタを、通常の状況下では、データベースは信頼性の問題を解決することができますが、主なライブラリがハングアップすると、データがライブラリから時間的に同期されていない、この時間は、IDの重複があるでしょう。我々は使用することができ、デュアルマスターモードの 2つのインスタンスは、MySQLは、生産インクリメントIDを分離することができ、これは、効率を向上させることができますが、別の変換により行っていない場合、それは、MySQL 2つのインスタンスが同じIDを生成する可能性がある、つまり、クラスタを。MySQLは、開始値と増分ステップ・サイズのそれぞれ異なる構成のための別のインスタンスを必要とします。

第一の構成例のMySQL:

set @@auto_increment_offset = 1;     -- 起始值
set @@auto_increment_increment = 2;  -- 步长
复制代码

第二の構成例のMysql。

set @@auto_increment_offset = 2;     -- 起始值
set @@auto_increment_increment = 2;  -- 步长
复制代码

以下のような構成の後、2つのインスタンスMySQLのID生成されたシーケンスである:mysql1、1の開始値、2のステップで、IDが生成された配列:1,3,5,7,9、... mysql2開始値は、ステップ2において、得られた配列番号2:2,4,6,8,10、...

このような分散プログラムID、例えばDistributIdServiceなどの分散アプリケーションを生成する別IDを追加する必要が発生するため、アプリケーションは、サービスアプリケーションのIDを取得するためのインタフェースを提供する、ビジネスアプリケーションは、IDを必要とする、一方向RPCによってDistributIdService、DistributIdServiceを要請MySQLはIDを取得するために上記の2つの例に無作為。

ステーションは、前記MySQLインスタンスダウン、それはDistributIdServiceに影響を与えない場合でも、本実施形態の実装後、DistributIdServiceはさらにMySQLのIDを生成するために利用することができます。

2が十分でない場合、スキームの延長は、MySQLインスタンス非常に良いではありません。しかし、あなたは、あなたが悩みを持って、パフォーマンスを向上させるためにMySQLインスタンスを追加する必要があります。

今、あなたはそれが動作しませんどのように、インスタンスmysql3を追加したい場合は?まず、mysql1、mysql2ステップサイズは確かに3に修正されるだろう、とだけ修正する人工することができ、それは時間がかかります。mysql1とmysql2がに保管されているので、第二に、mysql3開始値の自動インクリメント我々はmysql1、mysql2ステップサイズを変更するための十分な時間を与えるために、少し大きすぎる設定する必要があります。この問題を解決するために、IDを繰り返したときに第三に、それはあなたが仕事をシャットダウンする必要がある場合があり、修正ステップで表示されることがあります。

上記課題を解決するため、さらに性能DistributIdServiceを改善する能力において、機構ID第三世代場合を配布しました。

いいえセグメントモードありません

我々は、彼らがバルク、複数のIDを取得し、ローカルにキャッシュできるかどうか、そしてそれが大幅にIDを取得するためにビジネスアプリケーションを提供し、IDを取得するために、データベースからそのようなDistributIdServiceとして、セグメント数が一括取得として理解することができ、インクリメントIDを取得するには、スタイルのセクションを使用することができます効率。

例えばIDから取得DistributIdService各データベースは、例えば(1、1000]のようなセグメントの数を得るために、この範囲は、ID 1000を示し、サービスアプリケーションがDistributIdService IDを提供要求するとき、DistributIdServiceはローカルから始まるインクリメント現在のセグメント番号は、次のセグメントの第一を取得するために、再びデータベースに行く前に、最大使用されている1000、ローカルインクリメントまでたびにデータベースを要求することなく、戻ります。

以下のように、我々は、データベーステーブルへの変更を行う必要があります。

CREATE TABLE id_generator (
  id int(10) NOT NULL,
  current_max_id bigint(20) NOT NULL COMMENT '当前最大id',
  increment_step int(10) NOT NULL COMMENT '号段的长度',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码

ロジックはDistributIdServiceが移動行く増分されるので、(すなわち、現在の番号の値の最後のセグメントに適用されている)ので、データベースにはないデータベーステーブルは、自己増力ステップのレコード長に使用され、現在のIDは、最大値から増加させますロジックのこの部分。

このプログラムは、データベースが利用できない場合でも、DistributIdServiceは一定の期間をサポートし続けることができ、もはや強力なデータベースに依存しません。しかしDistributIdService再起動すると、空のIDで、その結果、いくつかのIDを失いました。

可用性DistributIdServiceを向上させるためには、クラスタを作成する必要があり、要求に応じてクラスタサービスは、IDを取得しDistributIdService、ランダムDistributIdService、各DistributIdServiceノードを取得するノードを選択します、データベースは、同じデータベース接続で、あなたかもしれません同時にDistributIdServiceデータベースアクセッション番号のセクションを要求する複数のノードを生成し、次いで、ポジティブロックの使用を制御するために必要な時間、そのような取得に次のSQL数のセグメントを使用して、データベーステーブル内のバージョンフィールドを追加するなど。

update id_generator set current_max_id=#{newMaxId}, version=version+1 where version = #{version}
复制代码

newMaxId DistributIdServiceがoldMaxId +ステップに応じて算出されているので、限り、上記のアップデート更新が成功したとして、成功のための多数のセグメントは述べています。

高可用性データベースの層を提供するためには、各データベースのマルチマスターデータベースの展開を使用する必要がある最初のアイデアの使用を必要とする、生成されたセグメントの数が繰り返されないことを確認し、その後だけでデータベーステーブルを増加させることですそれは、2つのMysql、その後、数生成mysql1セグメント(1、1001]であった場合、例えば、時間増分は1,3,4,5,7であり、値とステップサイズを開始.... mysql1シーケンス番号が生成されます段落(2,1002]、時間増分系列2,4,6,8 ...

詳細は、オープンソースTinyIdの部分を参照することができます:github.com/didi/tinyidを...

TinyIdも効率を向上させる工程、上記実装を追加では、増分論理IDは、ローカルサービスアプリケーションに論理進行をインクリメントすることができ、実際にDistributIdServiceに実装するようにされている業務用アプリケーションあなただけがもはやコールDistributIdServiceたび増分を要求する必要がない、段落を取得する必要があります。

雪のアルゴリズム

一般的には上記の3つの方法は、自己の成長の考えに基づいている、そして次はもっと有名なスノーフレークアルゴリズム-snowflakeをご紹介します。

私たちは、別の角度から配信されたIDを考える限り、ライン上のミリ秒ごとのIDで同じではありません各マシンの分散型発電のIDを生成するための責任を作ることができます。

スノーフレークは、TwitterのIDオープン生成アルゴリズムは、アルゴリズムで分配され、そしてそれはデータベースに依存しない、分散機構IDの上記の3つの種類が同じではありません生成します。

核となるアイデアである:長い分散型IDは、固定数、長い8バイトのタイプであり、それは64ビット、ビット割り当ての元スノーフレークアルゴリズムは以下に示す通りです。

image.png

  • 長い符号ビットであるので、第1の識別部分は0、負の数は、1であり、一般的に正のIDを生成し、それが0に固定されている正の数であり、1ビット、Javaで最上位ビットです。
  • IDが小さいから生成することができるように、 - (開始時の定電流時)のタイムスタンプの部分は、これをミリ秒レベルで、現在のタイムスタンプは、一般的な実装に格納されていないが、タイムスタンプの差分値であり、41bitを表します開始値、タイムスタンプ41は、69年、(1L << 41)/(1000L * 60 * 60 * 24 * 365)= 69年を使用することができます
  • より柔軟な10ビットのアカウントID作業機は、例えば、トップ5は、スタンドアロン機IDなどの識別データセンタールーム、ルーム5として用いることができる、ノード1024が配備されてもよいです。
  • 一部のシリアル番号12ビットを表し、同一のノードが同じID 4096 MSを生成することができるサポート

このロジックアルゴリズムによると、このアルゴリズムは唯一のツール方法としてパッケージJava言語、と出てくる必要があり、その後、様々なビジネスアプリケーションは、ちょうど各事業は独自の業務アプリケーションを持っていることを保証するために、分散型IDを取得するために、このツール直接法を使用することができますID機は、構築するために別のアプリケーションを必要とせずにIDを取得する分散することができます。

スノーフレークアルゴリズムは難しいことではありません、GitHubのでJavaの実現を提供:github.com/beyondfengyを...

大規模な工場では、実際には、直接雪の結晶を使用していないが、変換された、雪の結晶のアルゴリズムは作業機のIDを練習するのが最も困難であるため、元スノーフレークアルゴリズムは、手動で各マシンに指定されたマシンIDに移動し、設定する必要がありますどこかで雪の結晶がここからマシンIDを取得することができます。

しかし、大きな工場では、機械は、労働者の多くは、あまりにもエラーが発生しやすいコストなので、雪の結晶のメーカーが変換されています。

百度(UID-ジェネレータ)

githubの住所:UID-ジェネレータ

UID-発電機の使用は雪の結晶であるが、生産マシンIDは、時間もworkId呼ばれて異なっています。

アプリケーションが起動されると:workIdでのUID-ジェネレータは自動的にユーザー自身がUID-発電機でworkId生成戦略を定義することができ、UID-ジェネレータによって生成され、考慮にドッキングウィンドウの上に配置されたアプリケーションの場合を取っている、デフォルトで提供ポリシーがありますデータベースによって割り当てられました。それが成功の増加に対応するデータ挿入データを挿入するために、データベーステーブル(UID-発電WORKER_NODEは、テーブルを追加する必要があります)を開始したときにデータが使用後に返却された機械workIdの固有のIDです:彼は単純なポイントは言いましたホストからのデータ、ポート組成物。

WorkIdでUIDジェネレータについては、22ビットの28ビット時間占有ビットをビットを占め、13ビットのシーケンスがこと、雪片や時間の元、第二ユニットと同じではないに留意すべきで、ビットを占有しますミリ秒は、同じではありませんworkIdのではなく、同じアプリケーションは、消費者がworkIdますたびに再起動します。

特定の参照github.com/baidu/uid-g ...

米国のグループ(リーフ)

githubのアドレス:リーフ

リーフ米国のグループIDは、分散生成フレームワークです。また、雪の結晶パターンをサポートし、セグメントのモデル番号をサポートすることである、非常に包括的です。いいえバーストモードは、ここで提示していない、上記と同様の分析されていません。

スノーフレークパターンは、IDのZooKeeperを生成するために主にworkId生成、ベース葉workIdにおいて、雪片オリジナルアルゴリズム葉とは異なる、各アプリケーション葉スノーフレークを使用する場合、起動時に飼育係になります即ちIdの配列、ノードに対応する配列に相当する機械、workIdを生成します。

概要

一般的に言えば、上記の二つのシステムをより安定させると労働成功を減少させるために、workIdを自動的に生成されます。

Redisの

ここで再び分散IDを生成するために、追加の使用のRedisを紹介し、実際にはMySQLの同様の増分IDを使用して、次のようなアトミックインクリメントとリターンを達成するためにINCRコマンドでのRedisを使用することができます。

127.0.0.1:6379> set seq_id 1     // 初始化自增ID为1
OK
127.0.0.1:6379> incr seq_id      // 增加1,并返回
(integer) 2
127.0.0.1:6379> incr seq_id      // 增加1,并返回
(integer) 3
复制代码

Redisの利用効率が非常に高いですが、問題の持続性を検討します。RedisのはAOF RDBとの永続的な方法の2種類をサポートしています。

スナップショットは、連続増分数回を終了している場合、永続的な時限スナップショットを演奏するRDB永続的な同等は、スナップショットの永続性はRedisのがハングアップし、この時点で行うには時間がなかった、リスタートのRedis IDの後が繰り返されます。

持続性のために、各書き込みコマンドにAOF永続的な同等は、Redisのハング場合は、IDの重複されませんが、原因INCRコマンドハエに、データ復旧時間を再起動するようにつながる長すぎます。

より分散技術を学びたい、追加のマイクロチャネル公共番号を:1時25分

reny125.jpeg

おすすめ

転載: juejin.im/post/5d6fc8eff265da03ef7a324b