サブデータベースとサブテーブルのアーキテクチャの 21 のルールを理解するための 1 つの記事

この記事では、サブデータベースとサブテーブルのアーキテクチャに関する 21 の一般的な概念を紹介します。ある程度理解した後、読み取りと書き込みの分離、データの非感作、分散主キー、分散トランザクション、構成センター、レジストレーションセンター、プロキシサービスなどの実戦事例の解説とソースコード解析。

(1) 優れたシステムでは、なぜデータベースとテーブルを分割する必要があるのでしょうか?

まず、サブデータベースおよびサブテーブル アーキテクチャの実装中に遭遇する一般的な概念をいくつか紹介します。これらの概念を理解することは、市販されている他のサブデータベース ツールやサブテーブル ツールを理解するのに役立ちます。それらの実装方法は次のとおりです。違いはありますが、全体的な考え方は基本的に同じです。したがって、実際の運用を開始する前に、サブデータベースとサブテーブルのテクノロジをよりよく理解し、適用するために、これらの一般的な概念を習得する必要があります。

特定のビジネス シナリオを組み合わせ、t_order テーブルを例としてアーキテクチャを最適化します。データ量が1億件に達してからクエリ性能が著しく低下しているため、サブデータベースやサブテーブル技術を導入してこの問題に対応しています。具体的には、元の単一データベースを DB_1 と DB_2 の 2 つのデータベースに分割し、それぞれのデータベースで再度サブテーブル処理を実行して 2 つのテーブル t_order_1 と t_order_2 を生成し、注文テーブルのサブデータベースとサブデータベースを実現します。 .テーブル処理。

データシャーディング

通常、サブデータベースやテーブルを参照する場合、基本として水平セグメンテーション モード (水平サブデータベース、サブテーブル) を使用することがほとんどです データ シャーディングにより、元のテーブル t_order が大量のデータで分割されます 複数の小さなデータ量が生成されますまったく同じテーブル構造 t_order_0、t_order_1、...、t_order_n を持つテーブル (分割テーブル) があり、各テーブルには元の大きなテーブルのデータの一部のみが格納されます。

データノード

データノードとは、データシャーディングにおける分割不可の最小単位(テーブル)であり、データソース名とデータテーブルから構成されます。たとえば、上図の DB_1.t_order_1 と DB_2.t_order_2 がデータノードを表します。

論理テーブル

論理テーブルとは、同じ構造を持つ水平方向に分割されたテーブルの論理名を指します。

たとえば、注文テーブル t_order サブテーブルを t_order_0 ... t_order_9 など 10 個のテーブルに分割しました。この時点で、t_order テーブルはデータベースに存在しなくなり、いくつかの t_order_n テーブルに置き換えられます。

サブデータベースとサブテーブルは、通常、ビジネス コードに影響を与えません。開発者は、ビジネス ロジック SQL コーディングのみに集中します。それでも、コード内の t_order に SQL を記述し、論理 SQL を実行する前に、それを対応する実際のデータベースに解析します。SQL実行する。この時点で、t_order はこれらの分割テーブルの論理テーブルになります。

ビジネスロジックSQL

コピー

select * from t_order where order_no='A11111'
  • 1.

SQLの実際の実行

コピー

select * from DB_1.t_order_n where order_no='A11111'
  • 1.

実テーブル

実テーブルは、データベースに実際に存在する物理テーブル DB_1.t_order_n です。

ブロードキャストテーブル

ブロードキャスト テーブルは、テーブル構造とデータがすべてのシャード データ ソースで完全に一貫している特別なタイプのテーブルです。ブロードキャストテーブルは、分割テーブルに比べてデータ量が少なく、更新頻度も低いため、辞書テーブルや構成テーブルなどのシナリオでよく使用されます。すべてのノードにコピーがあるため、JOIN アソシエーション クエリのネットワーク オーバーヘッドが大幅に削減され、クエリの効率が向上します。

ブロードキャスト テーブルの変更操作では、すべてのノード上のデータの一貫性を確保するために同期を確保する必要があることに注意してください。

ブロードキャストテーブルの特徴:

  • すべての断片化されたデータ ソースにおいて、ブロードキャスト テーブル内のデータは完全に一貫しています。したがって、ブロードキャスト テーブルに対する操作 (挿入、更新、削除など) は、データの一貫性を確保するために各シャード データ ソースでリアルタイムに実行されます。
  • ブロードキャスト テーブルのクエリ操作については、シャード データ ソースで 1 回実行するだけで済みます。
  • ブロードキャスト テーブルのデータはすべてのノードで一貫しているため、他のテーブルとの JOIN 操作を実行することが可能であり、どのノードでも同じデータにアクセスできます。

ブロードキャストテーブルとして使用できるテーブルはどのようなものですか?

注文管理システムでは、特定の都市エリアの注文データをクエリして集計する必要があることがよくありますが、これには州エリアテーブル t_city と注文フローテーブル DB_n.t_order_n の JOIN クエリが含まれるため、次のように考えることができます。州エリアテーブルをコアとなるブロードキャストテーブルとして設計する このアイデアは、ライブラリ間の JOIN 操作を回避することです。

注: ブロードキャスト テーブルのデータの挿入、更新、削除は各シャード データ ソースでリアルタイムで実行されると前述しました。つまり、1000 個のシャード データ ソースがある場合、ブロードキャスト テーブルの変更が実行されます。 SQL は 1000 回実行されるため、システムのパフォーマンスに影響を与えないように、同時実行環境やビジネスのピーク時には実行しないようにしてください。

単一のテーブル

単一テーブルとは、すべての断片化されたデータ ソースの中で唯一のテーブル (断片化されていないテーブル) を指し、データ量が小さく断片化の必要がないテーブルに適しています。

テーブルのデータ量が数千万単位と推定され、他の分割テーブルと関連するクエリを実行する必要がない場合は、テーブルを単一のテーブル タイプとして設定し、デフォルトのシャード データに保存することをお勧めします。ソース。

シャードキー

シャード キーは、データがどこに配置されるか、つまり、データがストレージ用にどのデータ ノードに割り当てられるかを決定します。したがって、シャード キーの選択は非常に重要です。

たとえば、t_order テーブルをシャード化した後、注文データを挿入して SQL を実行する場合、SQL ステートメントで指定されたシャード キーを解析して、データがどのシャードに分類されるかを計算する必要があります。テーブルの order_no フィールドを例にとると、モジュロ演算 (order_no % 2 など) を実行してシャード番号を取得し、シャードに従って対応するデータベース インスタンス (DB_1 や DB_2 など) にデータを割り当てることができます。番号。分割テーブルも同様に計算されます。

このプロセスでは、order_no は t_order テーブルのシャード キーです。つまり、各注文データの order_no 値によって、それを保存するデータベース インスタンスとテーブルが決まります。シャーディング キーとして適切なフィールドを選択すると、水平シャーディングによってもたらされるパフォーマンスの向上をより効果的に活用できます。

このようにして、同じ注文の関連データが同じデータベースとテーブルに分類されます。注文をクエリするときも同様の計算が行われ、データの場所を直接特定できるため、データ検索とテーブルのパフォーマンスが大幅に向上します。データベーステーブル全体のスキャンを回避します。

それだけでなく、ShardingSphere は、シャーディング キーとして複数のフィールドに基づくシャーディングもサポートしています。これについては、後続の対応する章で詳しく説明します。

断片化戦略

使用する断片化アルゴリズム、断片化キーとして選択するフィールド、および異なるノードにデータを分散する方法を指定する断片化戦略。

シャーディング戦略はシャーディング アルゴリズムとシャーディング キーで構成され、複数のシャーディング アルゴリズムと複数のシャーディング キーに対する操作をシャーディング戦略で使用できます。

データベース シャーディングとテーブル シャーディングのシャーディング戦略構成は比較的独立しており、それぞれ異なる戦略とアルゴリズムを使用できます。各戦略は複数のシャーディング アルゴリズムを組み合わせて使用​​でき、各シャーディング アルゴリズムは複数のシャーディング キーに使用できます。判定。

断片化アルゴリズム

断片化アルゴリズムは、断片化キーを操作し、データを特定のデータ ノードに分割するために使用されます。

一般的に使用される断片化アルゴリズムが多数あります。

  • ハッシュ シャーディング: シャード キーのハッシュ値に従って、データがどのノードに配置されるかが決定されます。たとえば、ユーザー ID に基づいてハッシュ シャーディングが実行され、同じユーザーに属するデータが同じノードに割り当てられるため、後続のクエリ操作が容易になります。
  • 範囲シャーディング: シャードキー値は範囲範囲に従って異なるノードに割り当てられます。たとえば、注文の作成時間や地理的位置に基づくシャーディングなどです。
  • モジュロシャーディング: シャードキー値とシャード数のモジュロ値を取得し、その結果をデータを割り当てるノード番号として使用します。たとえば、order_no % 2 は、注文データを 2 つのノードのいずれかに分割します。
  • ……

実際のビジネス開発におけるシャーディングのロジックはさらに複雑で、さまざまなシナリオやニーズに適したさまざまなアルゴリズムがあり、実際の状況に応じて選択および調整する必要があります。

バインディングテーブル

バインディング テーブルは、同じシャーディング ルールを持つシャーディング テーブルのグループです。シャーディング ルールが一貫しているため、データのランディング位置が同じになり、JOIN 結合クエリ中のデータベース間の操作を効果的に回避できます。

たとえば、 t_order 注文テーブルと t_order_item 注文品目テーブルは両方とも、order_no フィールドをシャード キーとして使用し、関連付けに order_no を使用するため、2 つのテーブルは相互にバインドされます。

複数テーブルの関連付けクエリにバインドされたテーブルを使用する場合は、関連付けにシャード キーを使用する必要があります。そうしないと、デカルト積の関連付けまたはデータベース間の関連付けが発生し、クエリの効率に影響します。

複数テーブルの結合クエリに t_order テーブルと t_order_item テーブルを使用する場合、結合クエリの論理 SQL は次のように実行します。

コピー

SELECT * FROM t_order o JOIN t_order_item i ON o.order_no=i.order_no
  • 1.

バインディング テーブルのリレーションシップが構成されていない場合、2 つのテーブルのデータの場所が不明な場合はデータベース テーブル全体がクエリされ、デカルト積関連のクエリによって次の 4 つの SQL が生成されます。

コピー

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_no=i.order_no 
SELECT * FROM t_order_0 o JOIN t_order_item_1 i ON o.order_no=i.order_no 
SELECT * FROM t_order_1 o JOIN t_order_item_0 i ON o.order_no=i.order_no 
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_no=i.order_no
  • 1.
  • 2.
  • 3.
  • 4.

バインディング テーブルの関係を構成した後に関連付けクエリを実行すると、一貫したシャーディング ルールによって生成されたデータは同じライブラリ テーブルに分類されるため、現在のライブラリの t_order_n テーブルと t_order_item_n テーブルを関連付ける必要があるだけです。

コピー

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id 
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id
  • 1.
  • 2.

注: t_order は、クエリを結合するときにユニオン クエリ全体のメイン テーブルとして使用されます。関連するすべてのルーティング計算ではメイン テーブルの戦略のみが使用され、t_order_item テーブルのシャーディング関連の計算でも t_order 条件が使用されるため、バインディング テーブル間のシャーディング キーが正確に同じであることを確認する必要があります。

SQLの解析

サブデータベースとサブテーブルの後にアプリケーション レベルで SQL ステートメントを実行する場合、通常は次の 6 つの手順を実行する必要があります。 SQL 解析 -> 実行プログラムの最適化 -> SQL ルーティング -> SQL 書き換え -> SQL 実行 -> 結果合併中。

SQL 解析プロセスは、字句解析と構文解析の 2 つのステップに分かれています。たとえば、以下のユーザー注文について SQL をクエリし、最初に字句解析を使用して SQL を分割できない原子単位に分解します。さまざまなデータベース方言によって提供される辞書では、これらの単位はキーワード、式、変数、または演算子として分類されます。

コピー

SELECT order_no FROM t_order where  order_status > 0  and user_id = 10086
  • 1.

次に、構文解析により、分割された SQL キーワードが抽象構文ツリーに変換され、抽象構文ツリーをたどって断片化に必要なコンテキスト (クエリ フィールド情報 (Field)、テーブル情報 (Table)、クエリ条件 (Condition) が抽出されます)。 )、ソート情報 (Order By)、グループ化情報 (Group By)、ページング情報 (Limit) などを表示し、SQL 内の書き換えが必要な可能性のある位置をマークします。

抽象構文ツリー

エグゼキュータの最適化

エグゼキューターの最適化とは、SQL クエリの特性と実行統計に基づいて最適なクエリ プランを選択して実行することで、たとえば user_id フィールドにインデックスがある場合、2 つのクエリ条件の位置が調整され、主に SQL の実行効率が向上します。

コピー

SELECT order_no FROM t_order where user_id = 10086 and order_status > 0
  • 1.

SQLルーティング

シャーディング コンテキスト データは上記の SQL 解析を通じて取得され、ユーザーが設定したシャーディング戦略とアルゴリズムを照合した後、ルーティング パスが計算され、対応するデータ ノードにルーティングされます。

簡単に理解すると、シャーディング戦略で設定されたシャーディングキーなどの情報を取得し、SQL解析結果から対応するシャーディングキーフィールドの値を見つけて、どのデータベースやテーブルでSQLを実行するか、SQLルーティングを計算するということになります。フラグメントキーの有無によりフラグメントルーティングとブロードキャストルーティングに分けられます。

シャードキーを持つルートはシャードルートと呼ばれ、直接ルート、標準ルート、直積ルートの 3 種類に分類されます。

標準ルーティング

標準ルーティングは、最も推奨され、一般的に使用されるシャーディング方法であり、その適用範囲は、バインドされたテーブル間の関連クエリを含まない、または関連クエリのみを含む SQL です。

SQL シャーディング キーの演算子が = の場合、ルーティング結果は単一のデータベース (テーブル) に分類されます。シャーディング演算子が BETWEEN や IN などの範囲にある場合、ルーティング結果は必ずしも唯一のデータベース (テーブル) に分類されるとは限りません。 table). そのため、論理 SQL は最終的に複数の実際の SQL に分割されて実行される可能性があります。

コピー

SELECT * FROM t_order  where t_order_id in (1,2)
  • 1.

SQLルーティング処理後

コピー

SELECT * FROM t_order_0  where t_order_id in (1,2)
SELECT * FROM t_order_1  where t_order_id in (1,2)
  • 1.
  • 2.

ダイレクトルーティング

ダイレクト ルーティングは、指定されたデータベースやテーブルに SQL を直接ルーティングするシャーディング方法であり、ダイレクト ルーティングは、シャーディング キーが SQL にないシナリオで使用でき、サブクエリやカスタム関数を含む複雑な状況を実行することもできます。

デカルト積ルーティング

デカルト ルーティングは、非バインド テーブル間の関連付けクエリによって生成されます。たとえば、注文テーブル t_order のシャード キーは t_order_id で、ユーザー テーブル t_user のシャード キーは t_order_id です。2 つのテーブルのシャード キーは異なり、結合テーブルクエリが必要です。デカルト積ルーティングが実行され、クエリのパフォーマンスが低いため、このルーティング モードを回避してください。

コピー

SELECT * FROM t_order_0 t LEFT JOIN t_user_0 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_0 t LEFT JOIN t_user_1 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_1 t LEFT JOIN t_user_0 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_1 t LEFT JOIN t_user_1 u ON u.user_id = t.user_id WHERE t.user_id = 1
  • 1.
  • 2.
  • 3.
  • 4.

シャード キーを使用しないルーティングはブロードキャスト ルーティングとも呼ばれ、フル データベース テーブル ルーティング、フル データベース ルーティング、フル インスタンス ルーティング、ユニキャスト ルーティング、およびブロッキング ルーティングの 5 つのタイプに分類できます。

フルテーブルルーティング

フル データベース テーブル ルーティングは、データベース DQL、DML、DDL などの操作を対象としています。論理テーブル t_order SQL を実行すると、すべてのシャード データベースの対応する実テーブル t_order_0 t_order_n で 1 つずつ実行されます。

完全なライブラリルーティング

フル データベース ルーティングは、主に、データベース SET タイプのデータベース管理コマンドや TCL などのトランザクション制御ステートメントなど、データベース レベルでの操作を対象としています。

論理ライブラリに自動コミット属性を設定すると、コマンドは対応するすべての実ライブラリで実行されます。

コピー

SET autocommit=0;
  • 1.

フルインスタンスルーティング

フルインスタンス ルーティングは、データベース インスタンスに対する DCL 操作 (データベース ユーザーまたはロールの権限の設定または変更) です。たとえば、ユーザー注文を作成します。このコマンドは、すべての実データベース インスタンスで実行され、注文ユーザーが確実に注文できるようにします。通常は各データベース インスタンスにアクセスします。

コピー

CREATE USER [email protected] identified BY '程序员小富';
  • 1.

ユニキャストルーティング

ユニキャスト ルーティングは、テーブルの説明情報など、実際のテーブルに関する情報を取得するために使用されます。

コピー

DESCRIBE t_order;
  • 1.

t_order の実テーブルは t_order_0 … t_order_n であり、それらの記述構造はまったく同じであり、実テーブルで 1 回実行するだけで済みます。

ブロックルーティング

データベース上の SQL 操作を保護するために使用されます。例:

コピー

USE order_db;
  • 1.

ShardingSphere は論理スキーマ (データベースの組織と構造) を使用するため、このコマンドは実際のデータベースでは実行されません。そのため、データベースを実際のデータベースに切り替えるコマンドを送信する必要はありません。

SQLの書き換え

SQL が解析、最適化、ルーティングされた後、シャードの特定の実行場所が決定され、論理テーブルに基づいて開発された SQL を実際のデータベースで正しく実行できるステートメントに書き直す必要があります。たとえば、順序テーブル t_order をクエリする場合、実際の開発における SQL は論理テーブル t_order に従って記述されます。

コピー

SELECT * FROM t_order
  • 1.

このとき、サブテーブル構成上の論理テーブル名をルーティング後の実テーブル名に書き換える必要があります。

コピー

SELECT * FROM t_order_n
  • 1.

SQLの実行

ルーティングおよび書き換えられた実際の SQL は、実行のために基礎となるデータ ソースに安全かつ効率的に送信されます。ただし、このプロセスは、JDBC を介して SQL をデータ ソースに直接送信して実行することはできません。データ ソース接続の作成とメモリ使用量のバランスをとる必要があります。リソース制御と実行効率のバランスが自動的にとられます。

結果をマージする

各データ ノードから取得したマルチデータの結果セットを大きな結果セットにマージし、それを要求元のクライアントに正しく返すことを結果のマージと呼びます。SQL の並べ替え、グループ化、ページング、および集計の構文はすべて、マージされた結果セットに対して操作されます。

分散主キー

データが断片化されると、1つの論理テーブル(t_order)と多数の実テーブル(t_order_n)が対応することになりますが、互いに認識できないため、主キーIDが初期値から累積されていくため、必然的に主キーIDの重複が発生します。主キーが唯一のものである場合、ビジネスにとっては意味がありません。

テーブルの自動インクリメント主キーの初期値とステップ サイズを設定することで ID の衝突を回避できますが、これによりメンテナンス コストが増加し、スケーラビリティが低下します。

このとき、データレコードに世界的に一意な ID を手動で割り当てる必要がありますが、この ID を分散 ID と呼び、この ID を生成するシステムを通常発行者と呼びます。

9種類の分散ID生成スキームについては以前に公開したこちらの記事を参照してください。

データの感度を下げる

サブデータベースおよびサブテーブルのデータの機密保護を解除することは、機密データの機密性とセキュリティを確保し、データ漏洩のリスクを軽減できる効果的なデータ保護手段です。

たとえば、データベースとテーブルを分割するときに、テーブルのどのフィールドが非感作列であるかを指定し、対応する非感作アルゴリズムを設定できます。データがシャーディングされるときは、実行 SQL で非感作するフィールドを解析し、フィールド値は直接非感作され、ライブラリテーブルに書き込まれます。

ユーザーの氏名、住所、電話番号などの個人情報については、ユーザーのプライバシーを確​​実に保護するために、暗号化、ランダム化、または擬似ランダムデータへの置換によって機密性を解除することができます。

以前公開した記事「大手工場でも採用されている6種類のデータ非感作スキーム」を参照してください。

分散トランザクション

分散トランザクションの中心的な問題は、複数のデータ ソースにわたってアトミックな操作を実装する方法です。

多くの場合、サービスごとにデータの保存と管理に異なるデータ ソースが使用されるため、データ ソース間での操作はデータの不整合や損失のリスクにつながる可能性があります。したがって、分散トランザクションの一貫性を確保することが非常に重要です。

注文システムを例にとると、決済システム、在庫システム、ポイント システムなどの複数のシステムを呼び出す必要があり、各システムは独自のデータベース インスタンスを保持し、API インターフェイスを介してデータを交換します。

注文後に複数のシステムが同時に正常に呼び出されるようにするには、強い一貫性のあるトランザクションには XA プロトコルを、柔軟なトランザクションには代表的なツールである Seata を使用して分散トランザクションの一貫性を実現します。これらのツールは、開発者が分散トランザクションの実装を簡素化し、エラーや脆弱性を軽減し、システムの安定性と信頼性を向上させるのに役立ちます。

サブデータベースサブテーブル以降、問題の難易度はさらに向上します。独自の注文サービスも、データ ソース間の操作を処理する必要があります。その結果、システムの複雑さが大幅に増加します。したがって、最後の手段でない限り、サブデータベースとサブテーブルの解決策は避けるのが最善です。

分散トランザクションの詳細については、以前に公開したこの記事を参照してください。5 つの分散トランザクション ソリューションと比較して、私は依然として Ali の Seata (原理 + 実戦) を好みます。

データ移行

サブデータベースのサブテーブル、つまりデータの移行後もまだ頭の痛い問題があり、既存の業務システムに影響を与えないように、通常は新しいデータベース クラスターを作成してデータを移行します。古いクラスターのデータベースとテーブルから新しいクラスターのサブデータベースとテーブルにデータを移行します。これは比較的複雑なプロセスであり、移行プロセス中にデータ量、データの一貫性、移行速度などの多くの要素を考慮する必要があります。

移行は主にストック データと増分データの処理のために行われます。ストック データとは、古いデータ ソース内の既存の貴重な履歴データを指します。増分データは、成長を続け将来生成されるビジネス データを指します。

インベントリ データは定期的またはバッチで移行でき、移行プロセスには数日かかる場合があります。

増分データは、新旧のデータベース クラスター二重書き込みモードを採用できます。データの移行が完了し、企業がデータの整合性を検証した後、アプリケーションはデータ ソースを直接切り替えることができます。

後で、サードパーティのツールを組み合わせて、移行プロセスをデモンストレーションします。

シャドウライブラリ

シャドウテーブルとは何ですか?

シャドウ データベースは、本番環境と同じデータベース構造を持つインスタンスであり、オンライン システムに影響を与えることなく、データベースの移行やその他のデータベース変更操作の正確性を検証するため、およびフルリンク ストレス テストを行うために存在します。シャドウ ライブラリに保存されているデータは運用環境から定期的にコピーされますが、オンライン ビジネスには影響せず、テスト、検証、デバッグにのみ使用されます。

テスト環境のデータは信頼できないため、データベースのアップグレード、バージョン変更、パラメータ調整などの操作を実行する前に、シャドウ データベースでこれらの操作をシミュレートすることで潜在的な問題を見つけることができます。

シャドウ ライブラリを使用する場合は、次の原則に従う必要があります。

  • 本番環境データベースの構造は、テーブル構造、インデックス、制約などを含め、完全に一貫している必要があります。
  • データは実稼働環境と一致している必要があり、これは定期的な同期によって実現できます。
  • 読み取りおよび書き込み操作は運用環境には影響しませんが、シャドウ ライブラリに対する更新や削除などの操作は通常禁止されています。
  • シャドウ データベースのデータ特性により、アクセス権は厳密に制御される必要があり、許可された担当者のみがアクセスおよび操作を許可されます。

要約する

この記事では、サブデータベースとサブテーブルのアーキテクチャに関する 21 の一般的な概念を紹介します。ある程度理解した後、読み取りと書き込みの分離、データの非感作、分散主キー、分散トランザクション、構成センター、レジストレーションセンター、プロキシサービスなどの実戦事例の解説とソースコード解析。

おすすめ

転載: blog.csdn.net/xxxzzzqqq_/article/details/130677763