この記事はWeChatの公開アカウント「Programmer's Insider Things」から転載したもので、著者はProgrammer's Insider Thingsです。この記事を転載する場合は、Programmer Insider 公式アカウントまでご連絡ください。 どのようなテクノロジーを導入するにもリスクは伴いますが、シャーディングも例外ではありません。データベースとテーブル内のデータ量が、既存の高可用性アーキテクチャでサポートできなくなるほど増加し続けない限り、データベースとテーブルをシャードすることはお勧めしません。なぜなら、データ シャーディングを行うと、落とし穴に陥ることになりますが、分散主キー ID が最初に遭遇する落とし穴だからです。 異なるデータ ノード間でグローバルに一意の主キーを生成することは難しい問題です。論理テーブル t_order は複数の実テーブル t_order_n に分割され、異なるシャード ライブラリ db_0、db_1 などに分散されます。各実テーブルの自動インクリメント キーは互いを認識できないため、主キーが重複します。現時点では、データベース自体の自動増分主キーは、シャード ライブラリとテーブルの主キーのグローバル一意性要件を満たすことができません。
各シャードテーブルの自己増分主キーの初期値とステップサイズを厳密に制約することで重複 ID の問題を解決できますが、これにより運用および保守コストが大幅に増加し、スケーラビリティが極めて悪くなります。シャード テーブルの数を拡張する必要がある場合、元のテーブルのデータが大幅に変更されるため、この方法はお勧めできません。
この問題を完全に解決できるサードパーティのソリューションはすでに数多く存在します。たとえば、UUID、SNOWFLAKE アルゴリズム、セグメント番号セグメントに基づいて、特定のアルゴリズムを使用して一意のキーを生成したり、Meituan (Leaf) や Didi (TinyId) などの主キー生成サービスを直接参照したりします。 Sharding-jdbc には、UUID と SNOWFLAKE という 2 つの分散主キー生成スキームが組み込まれています。また、分散主キー ジェネレーターのインターフェイスを抽出し、開発者がカスタム主キー ジェネレーターを実装できるようにします。後ほど、Didi の主キー生成サービス (TinyId) をカスタムジェネレータに接続します。 前述のように、sharding-jdbc のフィールドの主キー ID を自動的に生成する場合は、application.properties ファイルで次の構成を行うだけです。
key-generator.column は主キー フィールドを示し、key-generator.type は主キー ID 生成スキーム (組み込みまたはカスタム) を示し、key-generator.props.worker.id はマシン ID を示します。主キー生成スキームが SNOWFLAKE に設定されている場合、マシン ID はビット単位の演算に参加します。 sharding-jdbc 分散主キーを使用する場合、注意すべき点が 2 つあります。
言語 UUID 型主キー生成実装クラス UUIDShardingKeyGenerator のソースコードを開くと、その生成ルールには UUID.randomUUID() という 1 行のコードしかないことがわかりました。え~っと、心の中でうわーって思いました。 UUID はグローバルな一意性を実現できますが、実際の業務では、user_id であれ order_id であれ、主キーはほとんどが整数であり、UUID は 32 ビットの文字列を生成するため、主キーとして使用することは推奨されません。 そのストレージとクエリは MySQL のパフォーマンスを大量に消費し、MySQL の担当者も主キーをできるだけ短くすることを明確に推奨しています。データベースの主キーとしての UUID の乱れも、データの場所の頻繁な変更を引き起こし、パフォーマンスに重大な影響を与えます。
スノーフレーク SNOWFLAKE (スノーフレーク アルゴリズム) は、64 ビットの長整数 (Long) データを生成するデフォルトの主キー生成スキームです。 sharding-jdbc のスノーフレーク アルゴリズムによって生成される主キーは、主に 1 ビットの符号ビット、41 ビットのタイムスタンプ ビット、10 ビットの作業プロセス ビット、および 12 ビットのシーケンス番号ビットの 4 つの部分で構成されます。 符号ビット(1ビット) Java の Long 型の最上位ビットは符号ビットで、正の数の場合は 0、負の数の場合は 1 になります。通常、生成される ID は正の数なので、デフォルト値は 0 です。 タイムスタンプビット(41ビット) 41 ビットのタイムスタンプが保持できるミリ秒数は 2 の 41 乗であり、1 年間の合計ミリ秒数は 1000L * 60 * 60 * 24 * 365 となり、約 69 年に相当します。まあ、私の人生にはそれで十分です。
作業工程ビット(10ビット) 一意のワーカー プロセス ID を表します。デフォルト値は 0 で、key-generator.props.worker.id プロパティを介して設定できます。
シリアル番号ビット(12ビット) 同じミリ秒内に異なる ID が生成されます。 時計を戻す スノーフレーク アルゴリズムの主キー ID の構成を理解すると、これがサーバー時間に大きく依存するアルゴリズムであることは容易にわかります。サーバー時間に依存すると、クロックのダイヤルバックという厄介な問題が発生します。 なぜ時計は戻るのでしょうか? インターネットには ntp (Network Time Protocol) と呼ばれるネットワーク タイム プロトコルがあり、これは特にネットワーク内の各コンピューターの時間を同期および調整するために使用されます。 そのため、携帯電話の時刻を手動で確認する必要はなくなりましたが、誰の携帯電話の時刻も同じままです。 ハードウェア クロックは、さまざまな理由により不正確になる (速くなるか遅くなる) 場合があります。このとき、時刻調整を実行するには ntp サービスが必要です。キャリブレーション中に、サーバーのクロックがジャンプしたり、戻ったりする場合があります。 スノーフレークアルゴリズムは時計の巻き戻しの問題をどのように解決するのでしょうか? サーバー クロックのダイヤルバックにより、ID が重複する可能性があります。 SNOWFLAKE ソリューションは、最大許容クロック ダイヤルバック ミリ秒を追加することで、元のスノーフレーク アルゴリズムを改善します。 クロックのダイヤルバック時間が最大許容ミリ秒しきい値を超えると、プログラムは直接エラーを報告します。許容範囲内であれば、デフォルトの分散主キー ジェネレーターは、クロックが最後の主キー生成の時刻に同期されるまで待機してから、作業を続行します。 許容される最大クロックセットバック(ミリ秒単位)。デフォルト値は 0 で、プロパティ max.tolerate.time.difference.milliseconds を介して設定できます。
ソースコード実装クラス SnowflakeShardingKeyGenerator を見てみましょう。コアプロセスは次のとおりです。 主キーが最後に生成された時刻 (lastMilliseconds) が現在の時刻 (currentMilliseconds) と比較されます。 lastMilliseconds > currentMilliseconds の場合、クロックがコールバックされたことを意味します。 次に、2 つの時間の差 (timeDifferenceMilliseconds) が、設定された最大許容時間しきい値 max.tolerate.time.difference.milliseconds 以内であるかどうかを判断します。しきい値内の場合、スレッドは差分時間 Thread.sleep(timeDifferenceMilliseconds) の間スリープします。それ以外の場合、差より大きい場合は例外が直接報告されます。
しかし、SNOWFLAKE ソリューションによって生成された主キー ID では、order_id は 18 桁の長整数になります。長すぎると思いますか? MySQL のように 0 から増加する自動増分主キーを実装するにはどうすればよいでしょうか?心配しないでください。解決策は後で示されます。 カスタム Sharding-jdbc は、SPI (サービス プロバイダー インターフェイス) メカニズムを使用して、主キー生成ルールを拡張します。これは、プロジェクト パス META-INF/services の下のファイルをスキャンし、ファイルで定義されているクラスを自動的にロードするサービス検出メカニズムです。 カスタム主キー ジェネレーターの実装は実際には非常に簡単で、必要な手順は 2 つだけです。 最初のステップは、ShardingKeyGenerator インターフェイスを実装し、その内部メソッドを書き換えることです。ここで、getType() メソッドはカスタム主キー生成スキーム タイプであり、generateKey() メソッドは主キーを生成するための特定のルールです。 次のコードでは、AtomicInteger を使用して、順序付けられた自己増加 ID の生成をシミュレートします。
2 番目のステップは、SPI メカニズムを使用して機能拡張を実現することです。そのため、META-INF/services ファイルでカスタム主キー ジェネレーターのクラス パスを構成する必要があります。
上記が完了したら、テストを行い、定義済みの主キー生成タイプ XXX を設定し、いくつかのデータを挿入して効果を確認してみましょう。
コンソールの SQL 解析ログを見ると、order_id フィールドが順序付けられた自己増加方式でレコードに挿入されており、構成が正しいことがわかります。 一つの例から推論する 生成スキームはカスタマイズできるため、分散主キーを実装するためのアイデアは数多くあります。以前書いた記事「9 つの分散 ID 生成スキーム」を思い出しましたが、それらは完全に互換性があることがわかりました。ここでは、練習に Didi (Tinyid) を選びます。別途分散ID生成サービスなので、まずは環境を構築する必要があります。 Tinyid のサービスでは、Http と Tinyid クライアントの 2 つのアクセス方法が提供されます。以下は、Tinyid クライアント メソッドの簡単な紹介です。詳細については、こちらの記事をお読みください。何度も紹介されすぎています。 Tinyidサービス構築 まず、ソースコード https://github.com/didi/tinyid.git を取得します。 分散IDは番号セグメントモードに基づいて実装されるため、データベースに依存します。対応するテーブル tiny_id_info と tiny_id_token を作成し、デフォルト データを挿入する必要があります。
そして、Tinyidサービスで上記のテーブルのデータソース情報を設定します。
最後に、プロジェクト Maven をインストールし、TinyIdServerApplication を右クリックしてサービスを開始すると、Tinyid 分散 ID 生成サービスがセットアップされます。 カスタム Tinyid 主キー タイプ Tinyid サービスがビルドされたら、それをプロジェクトに導入し、新しい tinyid_client.properties ファイルを作成し、それに tinyid.server プロパティと tinyid.token プロパティを追加します。トークンは、SQL に事前に挿入されたユーザー データです。
コード内で ID を取得する方が簡単で、必要なコードは 1 行だけで済み、ビジネス タイプの順序は SQL によって事前に挿入されたデータです。
Tinyid 主キー生成タイプの実装クラス TinyIdShardingKeyGenerator のカスタマイズを開始します。
構成ファイルで Tinyid 主キー生成タイプを有効にします。これで設定は完了です。すぐにテストしてみましょう。
Tinyid 主キーのテスト 注文レコードをデータベースに挿入すると、主キー ID フィールド order_id が増加傾向にあることがわかりました。 Tinyid サービスが正常に接続されました。完璧! 要約する 以降の 8 つの生成方法については、「9 つの分散 ID 生成スキーム」を参照し、必要に応じてアクセスしてください。全体的な方法は比較的単純なので、ここでは一つずつ実装しません。 事例 GitHub アドレス: https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-sharding-jdbcLiu Yishou オリジナルリンク: https://mp.weixin.qq.com/s/x1gVtnKh2OEAzSwv0sFDxg |
<<: Huawei Cloud WeLinkがクラウドノート機能を開始
>>: アントファイナンシャルの「テクニカルミドルプラットフォーム」:1億レベル分散システムアーキテクチャの実践
justhost.asiaは、香港データセンターの帯域幅が200Gbpsにアップグレードされたことを...
変化する市場の需要に適応する必要性は、いくら強調してもし過ぎることはありません。クラウドネイティブ ...
Tencent Cloud は、SaaS エコシステムにおけるレイアウトにおいてさらなる一歩を踏み出...
国家市場監督管理総局がテンセントに独占音楽著作権の取り消しを命じた後、中国のオンライン音楽プラットフ...
1月29日のニュース、電子商取引に詳しい友人にとって、垂直靴電子商取引全体が現在数え切れないほどの犠...
場合によっては、Web サイトにリンク可能なコンテンツが不足していることがあります。これを解決するに...
インターネットの急速な発展と電子商取引産業の台頭により、ますます多くの人々がSEOに触れ、理解し始め...
前回の 2 つの記事「分析の前提条件 - データ品質 1」と「分析の前提条件 - データ品質 2」で...
多くのウェブマスターの心の中では、動的なウェブページを静的なウェブページに変換するのは非常に簡単です...
[オリジナル記事は51CTO.comより] あっという間にワールドカップが終わりに近づいています。サ...
インターネットマーケティングを学ぶ方法(パート2)前回の記事「インターネット マーケティングの学習は...
[51CTO.comからのオリジナル記事] サイバーセキュリティ教育業界の先駆者として、北京永鑫志成...
今年1月23日、私は「レノボの『残り物を食べる』戦略の簡単な解釈」と題する記事を発表し、レノボがIB...
現在、モバイルアプリの総ユーザー数は10億人を超え、ユーザー数と使用期間の伸びは鈍化しています。つま...