TiDB ドキュメント
序文
TiDB
は、PingCAP 研究開発の分散型データベースである。TiDB
はMySQL
プロトコルと互換性がある、MySQL
ユーザーにとって使いやすいことである。
公式ドキュメント
以下は中国語公式ドキュメントと英語公式ドキュメントのリンクである。中国語または英語が上手く方は直接に読むことはおすすめです。
日本語ドキュメントについて
この通訳は個人的な趣味で、自分とSakuramiRin様はメンテナンスしています。日本語の初心者なので、説明または構文が不適切な場合、プルリクエストや以下のメールをいただければ心より感谢します。
バージョン
現在TiDB
のステェィブルバージョンは三つである。
三つがあるが、公式ドキュメントはどちらでも適用されます。
プログレス
あんまり時間がありませんので、通訳の進捗率は遅くになるかもしれないですが、頑張りたいとおもいます!
ブログ
TiDB
に関連するのブログ、最後の付録である。
TiDBの概要
TiDB
は、PingCAP 研究開発の分散型HTAP(Hybrid Transactional and Analytical Processing)
データベースであり、 RDBMS
とNoSQL
の最高の機能を組み合わせています。TiDB
はMySQL
と相互運用可能であり、機能拡張性、一貫性、高可用性ような属性を持っています。OLTP (Online Transactional Processing)
およびOLAP (Online Analytical Processing)
の場合でワンストップソリューションを提供することは目标として追求しております。
TiDB 特徴:
-
MySQL
と高い互換性ほとんどの場合、コードを変更せずに移植できます。もしサブデータベースとサブテーブルを使用すると、移植ツールがあってサポートします。
-
無制限の拡張機能
ノードを追加するだけで、パフォーマンスが無制限で拡張するになっていますし、必要なノードを拡張すれば、高並行性と大規模データのシナリオの処理は簡単になります。
-
TiDB
は、標準のACID
トランザクションを完全にサポートしています。公式ドキュメントにはこの一文しかありませんが、もう一つつたえたいのは、分散トランザクションのサポートにより、データの変更は成功になったら全てのノードがすぐに有効です。全てのノードが一つという思いがあったら良いです。
-
金融レベルな高い可用性
クラシックのマスタースレーブスキームに比べて、
Raft
の分散コヒーレンスプロトコルアプローチは終始一貫のことを保証します。そして、レプリカが多く存在すれば、障害が発生の時に人工の操作が要らなくて自動回復ことができます。 -
ワンストップ
HTAP
ソリューションTiDB
は典型的なOLTP
ラインアンドバンクデータベースとともに、強いのOLAP
機能があります。TiSpark
を配合して、1つのストレージはOLTP
とOLAP
を同時に処理し、面倒なETL
プロセスが要りません。 -
クラウドネイティブSQLデータベース
TiDBは、クラウドデータベース、パブリッククラウド、プライベートクラウド、およびハイブリッドクラウドをサポートします。展開、構成、および保守することは簡単です。
TiDB
は100%のOLTP
と80%のOLAP
のシナリをサポートすることを目指して、複雑なOLAP
分析が要るとTiSpark
を使用できます。
TiDB
はコードに侵入しなくて、クラシックのデータベースミドルウェアあるいはサブデータベースとサブテーブルを置換します。そして、開発者と保守業務者はデータベースのスケール問題を考え必要はなくて、ビジネスの開発ことをもと集中します。研究開発の効率性大きく向上させることがある。
TiDBの始める
TiDB
はローカルまたはクラウドプラットフォームに展開できます。パブリッククラウド、プライベートクラウド、あるいはハイブリッドクラウドもサポートできます。実際のシナリオに応じて、TiDBクラスターを展開するの方法を選択してください。
-
Ansible
展開:プロダクション運用環境で展開する場合、Ansible
を使用してTiDB
クラスターをデプロイしなければならない。 -
Ansible
オフライン展開:デプロイメント環境がネットワークにアクセスすることができない場合は、Ansible
オフライン展開することもできます。 -
TiDB Operator
展開:Kubernetes
環境の展開は、TiDB Operator
使用します。AWS
、GKE
、Aliyun
はサポートします。 -
Docker Compose
展開:TiDB
をテスト、TiDB
の新たな特徴を試す、またはスタンディング環境に使用する場合は、Docker Compose
はTiDB
クラスターをローカルに迅速に展開することができます。(プロジェクト環境には適していません) -
Docker
展開:Docker
を使用してTiDB
クラスターをデプロイできます。(プロジェクト環境には適していません)
ソースコード
TiDBの概要
TiDB
は、PingCAP 研究開発の分散型HTAP(Hybrid Transactional and Analytical Processing)
データベースであり、 RDBMS
とNoSQL
の最高の機能を組み合わせています。TiDB
はMySQL
と相互運用可能であり、機能拡張性、一貫性、高可用性ような属性を持っています。OLTP (Online Transactional Processing)
およびOLAP (Online Analytical Processing)
の場合でワンストップソリューションを提供することは目标として追求しております。
TiDB 特徴:
-
MySQL
と高い互換性ほとんどの場合、コードを変更せずに移植できます。もしサブデータベースとサブテーブルを使用すると、移植ツールがあってサポートします。
-
無制限の拡張機能
ノードを追加するだけで、パフォーマンスが無制限で拡張するになっていますし、必要なノードを拡張すれば、高並行性と大規模データのシナリオの処理は簡単になります。
-
TiDB
は、標準のACID
トランザクションを完全にサポートしています。公式ドキュメントにはこの一文しかありませんが、もう一つつたえたいのは、分散トランザクションのサポートにより、データの変更は成功になったら全てのノードがすぐに有効です。全てのノードが一つという思いがあったら良いです。
-
金融レベルな高い可用性
クラシックのマスタースレーブスキームに比べて、
Raft
の分散コヒーレンスプロトコルアプローチは終始一貫のことを保証します。そして、レプリカが多く存在すれば、障害が発生の時に人工の操作が要らなくて自動回復ことができます。 -
ワンストップ
HTAP
ソリューションTiDB
は典型的なOLTP
ラインアンドバンクデータベースとともに、強いのOLAP
機能があります。TiSpark
を配合して、1つのストレージはOLTP
とOLAP
を同時に処理し、面倒なETL
プロセスが要りません。 -
クラウドネイティブSQLデータベース
TiDBは、クラウドデータベース、パブリッククラウド、プライベートクラウド、およびハイブリッドクラウドをサポートします。展開、構成、および保守することは簡単です。
TiDB
は100%のOLTP
と80%のOLAP
のシナリをサポートすることを目指して、複雑なOLAP
分析が要るとTiSpark
を使用できます。
TiDB
はコードに侵入しなくて、クラシックのデータベースミドルウェアあるいはサブデータベースとサブテーブルを置換します。そして、開発者と保守業務者はデータベースのスケール問題を考え必要はなくて、ビジネスの開発ことをもと集中します。研究開発の効率性大きく向上させることがある。
TiDBの始める
TiDB
はローカルまたはクラウドプラットフォームに展開できます。パブリッククラウド、プライベートクラウド、あるいはハイブリッドクラウドもサポートできます。実際のシナリオに応じて、TiDBクラスターを展開するの方法を選択してください。
-
Ansible
展開:プロダクション運用環境で展開する場合、Ansible
を使用してTiDB
クラスターをデプロイしなければならない。 -
Ansible
オフライン展開:デプロイメント環境がネットワークにアクセスすることができない場合は、Ansible
オフライン展開することもできます。 -
TiDB Operator
展開:Kubernetes
環境の展開は、TiDB Operator
使用します。AWS
、GKE
、Aliyun
はサポートします。 -
Docker Compose
展開:TiDB
をテスト、TiDB
の新たな特徴を試す、またはスタンディング環境に使用する場合は、Docker Compose
はTiDB
クラスターをローカルに迅速に展開することができます。(プロジェクト環境には適していません) -
Docker
展開:Docker
を使用してTiDB
クラスターをデプロイできます。(プロジェクト環境には適していません)
ソースコード
4.0の新しい特徴
TiDB v4.0
(以下略記4.0
)が2020年5月28日にリリースされ、使いやすさ、安定性、パーフォーマンス、セキュリティおよび機能の方が大幅に改善されました。この記事では、改善されたことの簡単にを説明します、ユーザーは、実際のユースケースに基づいて4.0
にアップグレードするかどうかを決定する必要があります。
コア機能
スケジューリング機能
- ホットスポットの対応ために、より多くのメトリックが考慮されます。これによに、書き込み、読み取りトラフィックに基づくスケジューリング基準しながら、新しい
key
のメトリックは考慮する。新しいスケジューリング方法は、トラフィックのみを考慮する場合と比較して、CPU
リソースの使用率の不均一性の問題を大幅に改善できます。詳しくはスケジューリングをご覧ください。
ストレージエンジン。
-
TiFlash
はRealtime HTAP
機能用にTiDB
によって追加されたコンポーネントです。TiFlash
はMulti-Raft Learner
プロトコルを使用してTiKV
からリアルタイムでデータリードレプリカをコピーし、行方向ストレージエンジンTiKV
とカラム型ストレージTiFlash
の完全一貫性を確保します。TiKV
とTiFlash
を異なるマシンにデプロイして、HTAP
リソース割り当てと分離の問題を解決できます。詳しくはTiFlashをご覧ください。 -
TiKV v4.0
や新しいストレージフォーマットにある、幅の広いテーブルデータのエンコードとデコードの効率を向上させる。
TiDB Dashboard
DBAはTiDB Dashboard
のUI
を介してクラスターのトポロジー、構成情報、ログ情報、ハードウェア情報、オペレーティングシステム情報、スロークエリ情報、SQL
情報、診断レポートなど。この情報は、DBAがデータベースシステムをすばやく理解して分析するのに役立ちます。詳細は以下の通りです。
-
クラスター情報は、
TiDB
、TiKV
、PD
、TiFlash
およびインスタンスの実行状態。 -
Key Visualizer
はTiDB
クラスターの一定期間にトラフィックに関する履歴情報を取得して、DBAがTiDB
クラスターの使用モードとホットスポットを分析します。 -
SQL
ステートメント情報は、データベースに実行されたすべてのSQL
と、実行回数、実行時間の記録して、ユーザーがデータベースのSQL
実行ステータスをすばやく分析し、ホットスポットを含むSQL
を見つける。 -
Slow Queries
は、クラスターのすべてのスロークエリステートメントを取得して、問題の解決に役立ちます。 -
Diagnostic Report
は、データベースが定期的に起こりうる障害を自動的に診断し、その診断結果とクラスター関連のメトリックを診断レポートにまとめます。診断レポートはWebページであり、ブラウザに保存した後、オフラインで読むおよび共有できます。 -
Log Search & Download
は、クラスターログを視覚的に把握して、DBAによるシステム問題の分析、メンテナンスの効率を向上させる。
デプロイとメンテナンスのツール
TiUP
は、TiDB 4.0
でリリースされたデプロイとメンテナンスのツール。TiUP
の主な役割はTiDB
に関連するすべてのパッケージ、コンポーネント管理、ローカルデプロイ(Playground)、クラスター管理(Cluster)、アップグレードフレームワーク(TUF)、オフラインデプロイメントなどの機能があり、TiDB
のインストール、デプロイメント、メンテナンスをツール化し、DBAの効率を向上させる。
-
コンポーネント管理機能は、ワンクリックのコンポーネント情報クエリ、インストール、アップグレード、アンインストールなどの機能を提供し、DBAがTiDBのすべてのコンポーネントを管理しやすくします。
-
コンポーネント管理。コンポーネント情報を照会し、クラスターを簡単にインストール、アップグレード、およびアンインストールできます。DBAにとって、
TiDB
コンポーネントの管理はよりもはるかに簡単です。 -
クラスター管理機能(Cluster)は、複数の
TiDB
クラスターの展開、拡張、縮小、アップグレード、構成変更、開始、停止、再起動、クラスターの情報を取得の機能であり。 -
ローカルデプロイ(Playground)は、
TiDB
の基本機能をすばやく体験と理解するために、ローカル環境にやすいでTiDB
クラスターをデプロイして。注:この機能はプロダクション運用環境に使えない。 -
プライベートミラー管理(Mirror)は、もしオフィシャルのミラーアクセスできないので、TiUPはプライベートミラーを構築するための方法を提供し、オフライン展開機能を提供します。
-
パーフォーマンス試験の機能(Benchmark)は、
TPC-C
およびTPC-H
パフォーマンステストのワークロードを提供します。自動に展開と試験の機能があります。
トランザクション
-
ペシミスティックのトランザクションが正式なリリースして、デフォルトモードで。ペシミスティックのトランザクションは
Read Committed
の分離レベルとSELECT FOR UPDATE NOWAIT
をサポートする。詳しくはペシミスティックのトランザクションをご覧ください。 -
大きなトランザクションをサポートして、トランザクションのサイズ制限が
100 MB
から10 GB
に増加しました、楽観的およびペシミスティックの両方がサポートされます。詳しくはトランザクションのサイズ制限をご覧ください。
SQL 機能
-
SQL
プラン管理のSQL Bind
を自動キャプチャと進化をサポートする、実行プランの使いやすさと安定性を向上させます。詳しくはSQL
プラン管理をご覧ください。 -
15の新しい
SQL Hint
が追加され、オプティマイザの実行プランの生成とクエリ実行時のエンジンの動作を制御します。詳しくはSQL Hint
をご覧ください。 -
SELECT INTO outfile
ステートメントをサポートし、テーブルデータを指定したファイルにエクスポートできます。LOAD DATA
を使用すると、データベース間でデータを簡単にインポート/エクスポートできます。 -
カスタムシーケンスをサポートし、
CACHE/NO_CACHE
とCYCLE/NO_CYCLE
オプションをサポート、ユーザーはシーケンスを使用してID作成できます。詳しくはSequence
をご覧ください。 -
新しい
Flashback
は、誤ってTruncate
されたテーブルを復元する。 -
OOM
を回避するには、Join
とSort
の中間結果をディスクに書き込みます、システムの安定性を向上させる。 -
EXPLAIN
とEXPLAIN ANALYZE
の表示を改善して、より多くの情報を表示して、トラブルシューティングの効率を向上させます。詳しくはEXPLAIN ANALYZE
とEXPLAIN
をご覧ください。 -
Index Merge
をサポートする。Index Merge
は新しいテーブルデータアクセスメソッド。単一のテーブルを含むクエリの場合、複数のインデックスデータを自動的に読み取りにオプティマイザ、その結果を合併して、パフォーマンスを向上させます。詳しくはIndex Merge
をご覧ください。 -
TiDB
カラムをAUTO_RANDOM
のキーの属性をサポートする。ホットスポットの問題の解決を助ける、MySQL
ユーザーのマイグレーションのコストを節約することができる。詳しくはAUTO_RANDOM
のキーをご覧ください。 -
クラスターのトポロジー、構成情報、ログ情報、ハードウェア情報、オペレーティングシステム情報、スロークエリ情報、
SQL
情報のテーブルを追加する。DBAがデータベースシステムをすばやく理解して分析するのに役立ちます。詳しくはInformation Schema
とSQL Diagnosis
をご覧ください。詳細は以下の通りです。- データベースシステムテーブル
cluster_info
のテーブルは、クラスターのトポロジーの情報を保存する。cluster_log
のテーブルは、クラスターのログの情報を保存する。cluster_hardware
とcluster_hardware
のテーブルは、クラスターのハードウェアとオペレーティングシステムの情報を保存する。
- スロークエリ、
SQL
情報のテーブルcluster_slow_query
のテーブルは、グローバルのスロークエリの情報を保存する。cluster_processlist
のテーブルは、グローバルのプロセスリストの情報を保存する。inspection_result
のテーブルは、システムのボトルネックを自動的に分析し、DBAがパフォーマンス分析レポートを役立ちます。障害分析の効率を向上させる。metrics_summary
とmetric_summary_by_label
テーブルは、システムの全てのメトリックの情報を保存する、DBAがSQL
を介してメトリックの読みますおよび過去のデータと比較する。inspection_summary
テーブルは、複数のデータリンクとアクセスリンク中のさまざまな主要な監視メトリックを保存する。DBAが読み取り、書き込みなどのリンクの障害を分析できます。
- データベースシステムテーブル
文字セットと照合順序
TiDB 4.0
は大文字小文字を区別しませんutf8mb4_general_ci
とアクセントを区別しないutf8_general_ci,详情参阅
をサポートする。詳しくは文字セットと照合順序をご覧ください。
セキュリティ
-
クライアントとサーバー、コンポーネント間の暗号化された通信を改善し、コネクタの安全を保証する。受信と送信されたデータがアタッカーによって読み取られたり改変されたりしないように保護します。証明書ベースの認証、オンラインで証明書を更新する、
TLS
証明書のCommonName
属性を確認してなど。 -
透過的データ暗号化(TDE)は
TiDB
の新機能です、許可されているアプリケーションにデータを自動的に復号化して。TDEはファイルに対して、ディスク書き込み前に暗号化し、メモリに読み取り前に復号化して。AES128-CTR
、AES192-CTR
、AES256-CTR
の暗号化アルゴリズムおよびAWS KMS
にキーの管理をサポートする。詳しくは保存時の暗号化をご覧ください。
バックアップと復元
バックアップの所要時間を短縮するテクニックは、単一のTiDB
クラスターをバックアップと復元できます。高速の完全バックアップと復元をサポートし、データのソートして、範囲による分割をサポート。詳しくはバックアップと復元をご覧ください。
サービスレベル
-
Prepare/Execute
リクエストの実行プランのキャッシュをサポートして、SQL
実行効率を向上させる。詳しくはPrepare/Execute
プランのキャッシュをご覧ください。 -
新しいのレッドプールを実現します、スレッドプールの数を減らし、リクエストのスケジュールは最適化した。
TiDB
のパフォーマンスを向上させます。 -
Follower Read
はRaft
プロトコルの完全一貫性を確保に基づ、follower
ロールからデータを読み取ります、クラスターのスループットを改善し、leader
ロールのロードを減らした。Follower Read
ロードバランスのテクニック、follower
ロールは完全一貫性を保証もできます。詳しくはFollower Read
をご覧ください。
TiDBメイン構造
TiDB
はスケーリングと高い可用性の機能であり、深く理解欲しいなら、先ずはTiDB
のメイン構造勉強します。TiDB
クラスターは三かつメインコンポーネントである、TiDB Server
、PD Server
、TiKV Server
である。TiSpark
は、複雑なOLAP
のソリューションを目指した、TiDB Operator
は簡単にKubernetes
にデプロイできます。
TiDB Server
TiDB Server
はSQL
リクエストに受信します。TiDB Server
はSQL
を実行計画にインタプリタ後はPD Server
にデータ保管のTiKV Server
アドレス見つかった。TiDB Server
をTiKV Server
に通信データにアクセスして。TiDB Server
は持久的データではありません、自体はストレジの機能ではない、計算のみを担当、スケーリングできます。負荷分散コンポーネント(LVS
、HAProxy
、F5
)利用すれば、同じアドレスのことである。
PD Server
Placement Driver
(PD
)は、クラスター全体の管理者、主な機能は3つであり、1つはクラスターのメタデータを保管するのこと(Key
とTiKV
の対応)、二つはTiKV
クラスターのスケジューリングと負荷分散、そしてグローバルにユニークの増分のトランザクションのIDを管理配分する。
PD
はRaft
の分散コヒーレンスプロトコルを使用してデータのセキュリティを保証する。Raft
のリーダーサーバーを全ての操作を処理する、他のフォロワーサーバーは高可用性を保証するためにのみ使用されます。奇数のPD
サーバーを展開することをお勧めします。
TiKV Server
TiKV Server
はデータ実際の保管場所。外部向から、TiKV
は分散トランザクションを提供するにKey-Value
ストレージエンジンである。データを保存するための基本単位はリージョンであり、リージョンはレンジキー(StartKey
からEndKey
の左閉右開リージョン)のデータを保存する、1つのTiKV
に複数のリージョンがあります。TiKV
は、データの耐障害性を保証するために、Raft
プロトコルの一貫性のレプリケーションを行うことがである。レプリケーションはリージョンで管理され、複数の異なるノードはリージョンはお互いのコピーであるRaft
グループを形成します。複数のTiKV
間のデータのロードバランスはPD
によってスケジュールされ、これもリージョン単位でスケジュールされます。
TiSpark
TiSpark
は、ユーザーの複雑なOLAP
要件を解決するTiDB
の主要コンポーネントとして、TiDB
クラスターにSpark SQL
直接に実行にことはである。TiSpark
は分散TiKV
クラスターの利点を組み合わせ、ビッグデータエコシステムに統合します。TiSpark
を使用すると、TiDB
は1つのクラスターでOLTP
とOLAP
の両方のシナリオを対応できるため、ユーザーはデータ転送を心配する必要がありません。
TiDB Operator
TiDB Operator
は、主流のクラウドインフラストラクチャ(Kubernetes
)でTiDBクラスターを展開、管理、マルチクラスターハイブリッド、障害の自動修復できるようにします。
TiDBメイン構造
TiDB
はスケーリングと高い可用性の機能であり、深く理解欲しいなら、先ずはTiDB
のメイン構造勉強します。TiDB
クラスターは三かつメインコンポーネントである、TiDB Server
、PD Server
、TiKV Server
である。TiSpark
は、複雑なOLAP
のソリューションを目指した、TiDB Operator
は簡単にKubernetes
にデプロイできます。
TiDB Server
TiDB Server
はSQL
リクエストに受信します。TiDB Server
はSQL
を実行計画にインタプリタ後はPD Server
にデータ保管のTiKV Server
アドレス見つかった。TiDB Server
をTiKV Server
に通信データにアクセスして。TiDB Server
は持久的データではありません、自体はストレジの機能ではない、計算のみを担当、スケーリングできます。負荷分散コンポーネント(LVS
、HAProxy
、F5
)利用すれば、同じアドレスのことである。
PD Server
Placement Driver
(PD
)は、クラスター全体の管理者、主な機能は3つであり、1つはクラスターのメタデータを保管するのこと(Key
とTiKV
の対応)、二つはTiKV
クラスターのスケジューリングと負荷分散、そしてグローバルにユニークの増分のトランザクションのIDを管理配分する。
PD
はRaft
の分散コヒーレンスプロトコルを使用してデータのセキュリティを保証する。Raft
のリーダーサーバーを全ての操作を処理する、他のフォロワーサーバーは高可用性を保証するためにのみ使用されます。奇数のPD
サーバーを展開することをお勧めします。
TiKV Server
TiKV Server
はデータ実際の保管場所。外部向から、TiKV
は分散トランザクションを提供するにKey-Value
ストレージエンジンである。データを保存するための基本単位はリージョンであり、リージョンはレンジキー(StartKey
からEndKey
の左閉右開リージョン)のデータを保存する、1つのTiKV
に複数のリージョンがあります。TiKV
は、データの耐障害性を保証するために、Raft
プロトコルの一貫性のレプリケーションを行うことがである。レプリケーションはリージョンで管理され、複数の異なるノードはリージョンはお互いのコピーであるRaft
グループを形成します。複数のTiKV
間のデータのロードバランスはPD
によってスケジュールされ、これもリージョン単位でスケジュールされます。
TiSpark
TiSpark
は、ユーザーの複雑なOLAP
要件を解決するTiDB
の主要コンポーネントとして、TiDB
クラスターにSpark SQL
直接に実行にことはである。TiSpark
は分散TiKV
クラスターの利点を組み合わせ、ビッグデータエコシステムに統合します。TiSpark
を使用すると、TiDB
は1つのクラスターでOLTP
とOLAP
の両方のシナリオを対応できるため、ユーザーはデータ転送を心配する必要がありません。
TiDB Operator
TiDB Operator
は、主流のクラウドインフラストラクチャ(Kubernetes
)でTiDBクラスターを展開、管理、マルチクラスターハイブリッド、障害の自動修復できるようにします。
TiDB-Wasm 原理と実現
クイックスタート:https://play.pingcap.com/
WebAssembly の概要
読者にWebAssembly
大体理解ために、先ずはこの技術の基本的な紹介である。
WebAssembly
の公式紹介はこちら。
WebAssembly
(以下略記Wasm
)は、スタックベースの仮想マシン用のバイナリ命令形式であり、 Wasm
は、C
、C++
、Rust
などの高レベル言語のコンパイル用のポータブルターゲットとして設計されており、クライアントおよびサーバー上のアプリケーション用にWeb
上に展開できます。
言い換えれば、以下の結論で。
-
Wasm
は実行ファイルです。 -
C
、C++
、Rust
などの高レベル言語のプログラムをWasm
にコンパイルできます。 -
Wasm
はブラウザに実行できます。
実行の命令形式
以上の三つの結論見てとうり、質問があるかもしれます、命令形式は何ですか?一般的なELFファイル
はUnix
システムの共通の実行バイナリ命令形式、ローダーによって解析され、メモリにはいります、そして実行です。Wasm
も同様、対応のランタイムを解析および実行である。現在、主流のブラウザー、Node.js、およびWasmer
と呼ばれるWasm
専用に設計された一般的なランタイムです。さらに一歩進む、Wasm
作成したプログラムをカーネルモードで簡単に実行できるために、Wasm
ランタイムをカーネルに統合する機能をLinux
カーネルに提供する人もいます。
主要なブラウザのWasm
サポート:
高レベル言語からWasm
まで
上記の背景知識があれば、高レベル言語がどのようにWasm
にコンパイルされる方は理解できます。まず、高水準言語のコンパイルプロセスを見てください。
アセンブリと比較して、高レベル言語の特徴の1つは移植性です。例えば、C
とC++
はx86
マシンのターゲットにコンパイルできます、およびARM
のマシンのターゲット。Wasm
とARM
、x86
は実際には同じ種類のものであり、バイトコードの実行をサポートする仮想マシンと考えることができます。これはJava
に非常に似ていますが、実際には、C
とC++
はJVM
にコンパイルおよび実行できます。
さまざまなランタイムとWASI
以上はWasm
のデザインの目標はプログラムにweb
上に実行です。実際、Wasm
の元々デザインのターゲットはJavaScript
の実行効率を補うためください。開発が進むにつれて、この技術は仮想マシンとして扱う、そしてプログラムに移植するはまた、良いアイデアである。そのため、NodeJS
の実行環境、Wasmer
の実行環境、さらにはカーネル環境もあります。それから質問が来ます、こんあ沢山の実行環境であり、しかも各環境のインターフェースは違います、例えば、NodeJS
はファイルシステムのインターフェースはできます、ブラウザはこのインターフェースはできまさん。Wasm
の移植性に対処するには、WASI(WebAssembly System Interface)
が生まれました。WASI
は低レベルの標準のインターフェースを定義します、コンパイラとWasmランタイム環境がこの標準をサポートしている限り、生成されたWasm
はさまざまな環境にに移植できます。Wasm
ランタイムは仮想マシンに相当し、Wasm
はこのマシンの実行可能プログラムであり、WASI
はこのマシンで実行されているシステムであり、そしてWasm
の基礎的なインターフェースを提供します、例えばファイルシステムおよびソケットなど。
Wasm
とWASI
が何であるかをより良く説明するために、Hello Worldを使用して説明します、デモソース。
(module
;; type iov struct { iov_base, iov_len int32 }
;; func fd_write(id *iov, iovs_len int32, nwritten *int32) (written int32)
(import "wasi_unstable" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
(memory 1)(export "memory" (memory 0))
;; The first 8 bytes are reserved for the iov array, starting with address 8
(data (i32.const 8) "hello world\n")
;; _start is similar to main function, will be executed automatically
(func $main (export "_start")
(i32.store (i32.const 0) (i32.const 8)) ;; iov.iov_base - The string address is 8
(i32.store (i32.const 4) (i32.const 12)) ;; iov.iov_len - String length
(call $fd_write
(i32.const 1) ;; 1 is stdout
(i32.const 0) ;; *iovs - The first 8 bytes are reserved for the iov array
(i32.const 1) ;; len(iovs) - Only 1 string
(i32.const 20) ;; nwritten - Pointer, inside is the length of the data to be written
)
drop ;; Ignore return value
)
)
特定の命令の説明は、命令セットを参照できます。
こちらのhello.wat
はWasm
のテキストコードです、wat
とWasm
の関係は、アセンブリとELF
の関係に似ています。次に、wat
をWasm
にコンパイルし、Wasmer
(一般的なWasm
ランタイム実装)を使用して実行します。
先ずは依存関係をインストールする。
そしてコンパイルおよび実行。
~ » wat2wasm hello.wat -o hello.wasm
~ » wasmer run hello.wasm
hello world
TiDB の改修
未知は恐怖の源です、Wasm
の原理を知っているなら、TiDB
をブラウザに移動できます。
ブラウザのセキュリティポリシー
よく知られている、ブラウザは本質的にサンドボックスです、内部のプログラムは危険のアクションは許可されていません、例えばポートをリスニングおよびファイルシステム。しかし、TiDB
は使用の方がポートをリスニング、そしてユーザーはMySQL
クライアントを使用して接続できます。そのために、TiDB
はポートのをリスニングは必要であり。少し考えて、ポートをリスニングの限界突破、そしてMySQL
クライアントを使用して接続のことはいいじゃないは理解するできます。理想的な方法はMySQL
クライアントのターミナルがウェブページの中にある、そしてこのクライアントはTiDB
は接続されています。
先ずは、TiDB
はターミナルを統合するのことは考えて。ユーザー入力SQL
を受け入れ、そして出力はSQL
の実行結果です。このTiDB
のエグゼクティブターミナルを実装するのは難しい、ショートカットを考えました、TiDB
のテストコードを使用してターミナルを後付けすることを計画。これはテストコードで見つかったスニペットです。
result = tk.MustQuery("select count(*) from t group by d order by c")
result.Check(testkit.Rows("3", "2", "2"))
tk
という名前のこのオブジェクトは、SQL
ターミナルとして使用できます。これはtk
の主な関数。
// Exec executes a sql statement.
func (tk *TestKit) Exec(sql string, args ...interface{}) (sqlexec.RecordSet, error) {
var err error
if tk.Se == nil {
tk.Se, err = session.CreateSession4Test(tk.store)
tk.c.Assert(err, check.IsNil)
id := atomic.AddUint64(&connectionID, 1)
tk.Se.SetConnectionID(id)
}
ctx := context.Background()
if len(args) == 0 {
var rss []sqlexec.RecordSet
rss, err = tk.Se.Execute(ctx, sql)
if err == nil && len(rss) > 0 {
return rss[0], nil
}
return nil, errors.Trace(err)
}
stmtID, _, _, err := tk.Se.PrepareStmt(sql)
if err != nil {
return nil, errors.Trace(err)
}
params := make([]types.Datum, len(args))
for i := 0; i < len(params); i++ {
params[i] = types.NewDatum(args[i])
}
rs, err := tk.Se.ExecutePreparedStmt(ctx, stmtID, params)
if err != nil {
return nil, errors.Trace(err)
}
err = tk.Se.DropPreparedStmt(stmtID)
if err != nil {
return nil, errors.Trace(err)
}
return rs, nil
}
後では簡単です、Read-Eval-Print-Loop(REPL)プログラムを作成してユーザー入力を読み取り、入力を上記のExec
関数に渡し、Exec
関数の出力を標準出力にフォーマットしてから、ループでユーザー入力の読み取りを続けます。
コンパイルの問題
ターミナルの統合は最初の手順です、次には重要な質問を検証する必要があります。TiDB
をWasm
のターゲットにコンパイルできますか?TiDB
はGolang
で製されていますが、しかし、参照されたライブラリは、プラットフォーム固有のコードを直接コンパイルできない場合があります。公式のGolang
ドキュメントに従ってコンパイルはできません。
~/go/src/github.com/pingcap/tidb(master*) » GOOS=js GOARCH=wasm go build -o bin/tidb.wasm tidb-server/main.go
build command-line-arguments: cannot load github.com/pingcap/tidb/util/signal: no Go source files
~/go/src/github.com/pingcap/tidb(master*) » ls util/signal
signal_posix.go signal_windows.go
signal
関連の関数にWasm
プラットフォームの実装がないため、コンパイルに失敗しました。ネコをマネてトラを描くのことのように、signal wasm.go
を実装する。
package signal
// SetupSignalHandler setup signal handler for TiDB Server
func SetupSignalHandler(shutdownFunc func(bool)) {
}
そして、コンパイルを再開する。
~/go/src/github.com/pingcap/tidb(master*) » GOOS=js GOARCH=wasm go build -o bin/tidb.wasm tidb-server/main.go
# github.com/coreos/go-systemd/journal
../../../../pkg/mod/github.com/coreos/go-systemd@v0.0.0-20181031085051-9002847aa142/journal/journal.go:99:13: undefined: syscall.UnixRights
# github.com/pingcap/goleveldb/leveldb/storage
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:81:16: undefined: newFileLock
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:166:3: undefined: rename
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:252:11: undefined: rename
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:257:11: undefined: syncDir
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:354:14: undefined: rename
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:483:9: undefined: rename
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:519:13: undefined: syncDir
# github.com/remyoudompheng/bigfft
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:10:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:11:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:12:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:13:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:14:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:15:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:16:6: missing function body
これは同じ問題だ、偽物の実装を使用する、コンパイルは可能です。
package storage
import (
"os"
"syscall"
)
func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
return nil, syscall.ENOTSUP
}
func setFileLock(f *os.File, readOnly, lock bool) error {
return syscall.ENOTSUP
}
func rename(oldpath, newpath string) error {
return syscall.ENOTSUP
}
func isErrInvalid(err error) bool {
return false
}
func syncDir(name string) error {
return syscall.ENOTSUP
}
同じ方法を使用してarith_decl
の問題を解決はできません、missing function body
エラーとは何ですか?arith_decl.go
のディレクトリは見てとうり、何が起こったのかがわかります。
~ » ls ~/go/pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7
arith_386.s arith_arm64.s arith_decl.go arith_mipsx.s calibrate_test.go fermat_test.go fft_test.go LICENSE scan.go
arith_amd64.s arith_arm.s arith_mips64x.s benchmarks fermat.go fft.go go.mod README scan_test.go
arith_decl.go
は関数の宣言であり、関数の特定の実装は、各プラットフォームに関連するなアセンブリファイルにあります。
対応の関数は実装、問題は解除できる、そう考えるのは簡単すぎる。このbigfft
はライブラリです、だからそちのコードの編集は簡単な作業ではありません。TiDB
はこのライブラリに直接依存せず、代わりにmathutil
に依存し、mathutil
lはこのbigfft
に依存します。
TiDB
は、mathutil
のライブラリが提供する関数を使用します、理想的な対策はデフォルトでこれら2つのライブラリを使用する、Wasm
のコンパイル時には使用されません。そのために、util/mathutil
パッケージを作成する、中にリmathutil_linux.go
とmathutil_js.go
を入れて。元々参照されていた関数をmathutil_linux.go
に再輸出します、これらの関数はmathutil_js.go
に再実装されます。これから、Wasm
のターゲットをコンパイルの時はオリジナルのmathutil
ライブラリを使用しません。
~/go/src/github.com/pingcap/tidb(feature/wasm) » GOOS=js GOARCH=wasm go build -o bin/tidb.wasm tidb-server/main.go
~/go/src/github.com/pingcap/tidb(feature/wasm) » ls -l bin
total 85816
-rwxrwxr-x 1 coder coder 87868180 Dec 14 18:16 tidb.wasm
成功しました!
互換性の問題
コンパイル出したのtidb.wasm
はos.Stdin
を介して入力したSQL
を読み取り、os.Stdout
を介して結果を出力します。だから、ウェブページはまだブランクした。ただし、TiDB
のログはos.Stdout
に送られるため、ブラウザコンソールでTiDB
の通常の起動のログを確認する必要があります。しかし、残念ながら例外のスタックトレースが表示されます。
このエラーが発生するの理由はos.Stat
は実装しない。現在、Golang
はWASI
のサポートはあまり良くない、wasm_exec.js
でfs
を部分的に実装しています:
global.fs = {
writeSync(fd, buf) {
...
},
write(fd, buf, offset, length, position, callback) {
...
},
open(path, flags, mode, callback) {
...
},
...
}
このfs
の実装はstat
、lstat
、unlink
、mkdir
などの呼び出しを実装しません。幸いなことに、JavaScript
は動的プログラミング言語です、関数をfs
に動的に追加できます。
function unimplemented() {
const err = new Error('not implemented');
err.code = 'ENOSYS';
arguments[arguments.length - 1](err)
}
fs.stat = unimplemented;
fs.lstat = unimplemented;
fs.unlink = unimplemented;
fs.rmdir = unimplemented;
fs.mkdir = unimplemented;
go.run(result.instance);
ウェブページを再読み込み、起動ログがコンソールに表示されました!
これまで、TiDB
をWasm
にコンパイルするの技術的な問題はすべて解決されました。後では、以前に作成されたのREPL
ターミナルを置き換える適切なターミナルを見つけることなら、ページにSQL
を入力してのことはできます。
ユーザーインターフェース
上記の仕事により、SQL
を受け入れてその実行結果を出力するExec
関数ができました。ブラウザで実行するには、この関数とインタラクションするためのブラウザバージョンのSQL
ターミナルも必要です。その対策はwindow
にExec
関数を登録する、ならJavaScript
の関数はExec
呼び出すことはできます。
js.Global().Set("executeSQL", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
go func() {
// Simplified code
sql := args[0].String()
args[1].Invoke(k.Exec(sql))
}()
return nil
}))
それで、コンソールの場合はSQL
を実行できます。
jquery.console.js
を使用してSQL
ターミナルを構築し、executeSQL
をコールバックとして渡します。完了します!
ローカルファイルアクセス
TiDB
には、ローカルファイルシステムにアクセスする必要があるいくつかの関数があります、例えばLOAD DATA
およびLOAD STATS
。LOAD DATA
の機能は、ローカルファイルからデータベースにデータをインポートする。交換方法はブラウザのファイルアップロードウィンドウを使用した、LOAD STATS
の実装は同じです。
js.Global().Get("upload").Invoke(js.FuncOf(func(this js.Value, args []js.Value) interface{} {
go func() {
fileContent := args[0].String()
_, e := doSomething(fileContent)
c <- e
}()
return nil
}), js.FuncOf(func(this js.Value, args []js.Value) interface{} {
go func() {
c <- errors.New(args[0].String())
}()
return nil
}))
SOURCE
コマンドはローカルファイルを読み取り、まとはMySQL
クライアントで実行します。TiDB
を初めて使用するユーザーは、TiDB
とMySQL
の互換性を確認したいと考えています。このコマンドは、ユーザーがテストデータをすば速いインポートするのに役立ちます。
SOURCE
コマンドの効果を示す例としてtest.sql
ファイルを取り上げますtest.sql
ファイルの内容は下記です。
CREATE DATABASE IF NOT EXISTS samp_db;
USE samp_db;
CREATE TABLE IF NOT EXISTS person (
number INT(11),
name VARCHAR(255),
birthday DATE
);
CREATE INDEX person_num ON person (number);
INSERT INTO person VALUES("1","tom","20170912");
UPDATE person SET birthday='20171010' WHERE name='tom';
SOURCE
コマンドを入力すると、ファイル選択ボックスがポップアップします。
選択後、SQL
が自動的に実行され、TiDB
のテストを続行できます。
まとめと展望
TiDBを移植するために、主にいくつかの問題を解決しました。
-
ブラウザはポートをリスニングのことはできません。
SQL
ターミナルをTiDB
に埋め込みました。 -
goleveldb
のWasm
コンパイル。 -
bigfft
のWasm
コンパイル。 -
Golang
はWASI
のサポートが不完全なため、fs
関連の機能がありません。 -
TiDB
はローカルファイルの読み込みをブラウザのアップロードファイルの読み込みに変換します。 -
SQL
をバッチで実行するSOURCE
コマンドをサポート。
現在PingCAP
は、このプロジェクトをTiDB PlaygroundおよびTiDB Tourのユーザーが利用できるようにしました。ユーザーはインストールと構成を行う必要がないため、ユーザーはドキュメントを読みながら試してみることができます。これにより、ユーザーがTiDB
は使用して学ぶ安いです。コミュニティにはすでにTiDB Wasm
に基づくデータベースチュートリアルがありますtidb-wasm-markdown。
このプロジェクトはPingCAP Hackathon
で二等賞を受賞しました。スケジュールが厳しいため、まだたくさんの機能は実装されていません、例えば:
-
IndexedDB
を使用したデータの永続化:IndexedDB
のストレージインターフェイスのセットを実装する。 -
P2P
を使用した他のブラウザーにサービスを提供する:将来、ますます多くのアプリケーションがWasm
に移行されるでしょう、多くのデータベースが必要、TiDB Wasm
を使用できます。 -
TiDB Wasm
のバイナリスリミング:現在のはほぼ80MB
、読み込みが遅い、実行時によりたくさんのメモリを使用する、これらは最適化する必要があります。
興味のあるコミュニティの友人は、このプロジェクトに参加して一緒に楽しんでください、プロジェクト、info@pingcap.comでお問い合わせいただくこともできます。
TiDB-Wasm 原理と実現
クイックスタート:https://play.pingcap.com/
WebAssembly の概要
読者にWebAssembly
大体理解ために、先ずはこの技術の基本的な紹介である。
WebAssembly
の公式紹介はこちら。
WebAssembly
(以下略記Wasm
)は、スタックベースの仮想マシン用のバイナリ命令形式であり、 Wasm
は、C
、C++
、Rust
などの高レベル言語のコンパイル用のポータブルターゲットとして設計されており、クライアントおよびサーバー上のアプリケーション用にWeb
上に展開できます。
言い換えれば、以下の結論で。
-
Wasm
は実行ファイルです。 -
C
、C++
、Rust
などの高レベル言語のプログラムをWasm
にコンパイルできます。 -
Wasm
はブラウザに実行できます。
実行の命令形式
以上の三つの結論見てとうり、質問があるかもしれます、命令形式は何ですか?一般的なELFファイル
はUnix
システムの共通の実行バイナリ命令形式、ローダーによって解析され、メモリにはいります、そして実行です。Wasm
も同様、対応のランタイムを解析および実行である。現在、主流のブラウザー、Node.js、およびWasmer
と呼ばれるWasm
専用に設計された一般的なランタイムです。さらに一歩進む、Wasm
作成したプログラムをカーネルモードで簡単に実行できるために、Wasm
ランタイムをカーネルに統合する機能をLinux
カーネルに提供する人もいます。
主要なブラウザのWasm
サポート:
高レベル言語からWasm
まで
上記の背景知識があれば、高レベル言語がどのようにWasm
にコンパイルされる方は理解できます。まず、高水準言語のコンパイルプロセスを見てください。
アセンブリと比較して、高レベル言語の特徴の1つは移植性です。例えば、C
とC++
はx86
マシンのターゲットにコンパイルできます、およびARM
のマシンのターゲット。Wasm
とARM
、x86
は実際には同じ種類のものであり、バイトコードの実行をサポートする仮想マシンと考えることができます。これはJava
に非常に似ていますが、実際には、C
とC++
はJVM
にコンパイルおよび実行できます。
さまざまなランタイムとWASI
以上はWasm
のデザインの目標はプログラムにweb
上に実行です。実際、Wasm
の元々デザインのターゲットはJavaScript
の実行効率を補うためください。開発が進むにつれて、この技術は仮想マシンとして扱う、そしてプログラムに移植するはまた、良いアイデアである。そのため、NodeJS
の実行環境、Wasmer
の実行環境、さらにはカーネル環境もあります。それから質問が来ます、こんあ沢山の実行環境であり、しかも各環境のインターフェースは違います、例えば、NodeJS
はファイルシステムのインターフェースはできます、ブラウザはこのインターフェースはできまさん。Wasm
の移植性に対処するには、WASI(WebAssembly System Interface)
が生まれました。WASI
は低レベルの標準のインターフェースを定義します、コンパイラとWasmランタイム環境がこの標準をサポートしている限り、生成されたWasm
はさまざまな環境にに移植できます。Wasm
ランタイムは仮想マシンに相当し、Wasm
はこのマシンの実行可能プログラムであり、WASI
はこのマシンで実行されているシステムであり、そしてWasm
の基礎的なインターフェースを提供します、例えばファイルシステムおよびソケットなど。
Wasm
とWASI
が何であるかをより良く説明するために、Hello Worldを使用して説明します、デモソース。
(module
;; type iov struct { iov_base, iov_len int32 }
;; func fd_write(id *iov, iovs_len int32, nwritten *int32) (written int32)
(import "wasi_unstable" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
(memory 1)(export "memory" (memory 0))
;; The first 8 bytes are reserved for the iov array, starting with address 8
(data (i32.const 8) "hello world\n")
;; _start is similar to main function, will be executed automatically
(func $main (export "_start")
(i32.store (i32.const 0) (i32.const 8)) ;; iov.iov_base - The string address is 8
(i32.store (i32.const 4) (i32.const 12)) ;; iov.iov_len - String length
(call $fd_write
(i32.const 1) ;; 1 is stdout
(i32.const 0) ;; *iovs - The first 8 bytes are reserved for the iov array
(i32.const 1) ;; len(iovs) - Only 1 string
(i32.const 20) ;; nwritten - Pointer, inside is the length of the data to be written
)
drop ;; Ignore return value
)
)
特定の命令の説明は、命令セットを参照できます。
こちらのhello.wat
はWasm
のテキストコードです、wat
とWasm
の関係は、アセンブリとELF
の関係に似ています。次に、wat
をWasm
にコンパイルし、Wasmer
(一般的なWasm
ランタイム実装)を使用して実行します。
先ずは依存関係をインストールする。
そしてコンパイルおよび実行。
~ » wat2wasm hello.wat -o hello.wasm
~ » wasmer run hello.wasm
hello world
TiDB の改修
未知は恐怖の源です、Wasm
の原理を知っているなら、TiDB
をブラウザに移動できます。
ブラウザのセキュリティポリシー
よく知られている、ブラウザは本質的にサンドボックスです、内部のプログラムは危険のアクションは許可されていません、例えばポートをリスニングおよびファイルシステム。しかし、TiDB
は使用の方がポートをリスニング、そしてユーザーはMySQL
クライアントを使用して接続できます。そのために、TiDB
はポートのをリスニングは必要であり。少し考えて、ポートをリスニングの限界突破、そしてMySQL
クライアントを使用して接続のことはいいじゃないは理解するできます。理想的な方法はMySQL
クライアントのターミナルがウェブページの中にある、そしてこのクライアントはTiDB
は接続されています。
先ずは、TiDB
はターミナルを統合するのことは考えて。ユーザー入力SQL
を受け入れ、そして出力はSQL
の実行結果です。このTiDB
のエグゼクティブターミナルを実装するのは難しい、ショートカットを考えました、TiDB
のテストコードを使用してターミナルを後付けすることを計画。これはテストコードで見つかったスニペットです。
result = tk.MustQuery("select count(*) from t group by d order by c")
result.Check(testkit.Rows("3", "2", "2"))
tk
という名前のこのオブジェクトは、SQL
ターミナルとして使用できます。これはtk
の主な関数。
// Exec executes a sql statement.
func (tk *TestKit) Exec(sql string, args ...interface{}) (sqlexec.RecordSet, error) {
var err error
if tk.Se == nil {
tk.Se, err = session.CreateSession4Test(tk.store)
tk.c.Assert(err, check.IsNil)
id := atomic.AddUint64(&connectionID, 1)
tk.Se.SetConnectionID(id)
}
ctx := context.Background()
if len(args) == 0 {
var rss []sqlexec.RecordSet
rss, err = tk.Se.Execute(ctx, sql)
if err == nil && len(rss) > 0 {
return rss[0], nil
}
return nil, errors.Trace(err)
}
stmtID, _, _, err := tk.Se.PrepareStmt(sql)
if err != nil {
return nil, errors.Trace(err)
}
params := make([]types.Datum, len(args))
for i := 0; i < len(params); i++ {
params[i] = types.NewDatum(args[i])
}
rs, err := tk.Se.ExecutePreparedStmt(ctx, stmtID, params)
if err != nil {
return nil, errors.Trace(err)
}
err = tk.Se.DropPreparedStmt(stmtID)
if err != nil {
return nil, errors.Trace(err)
}
return rs, nil
}
後では簡単です、Read-Eval-Print-Loop(REPL)プログラムを作成してユーザー入力を読み取り、入力を上記のExec
関数に渡し、Exec
関数の出力を標準出力にフォーマットしてから、ループでユーザー入力の読み取りを続けます。
コンパイルの問題
ターミナルの統合は最初の手順です、次には重要な質問を検証する必要があります。TiDB
をWasm
のターゲットにコンパイルできますか?TiDB
はGolang
で製されていますが、しかし、参照されたライブラリは、プラットフォーム固有のコードを直接コンパイルできない場合があります。公式のGolang
ドキュメントに従ってコンパイルはできません。
~/go/src/github.com/pingcap/tidb(master*) » GOOS=js GOARCH=wasm go build -o bin/tidb.wasm tidb-server/main.go
build command-line-arguments: cannot load github.com/pingcap/tidb/util/signal: no Go source files
~/go/src/github.com/pingcap/tidb(master*) » ls util/signal
signal_posix.go signal_windows.go
signal
関連の関数にWasm
プラットフォームの実装がないため、コンパイルに失敗しました。ネコをマネてトラを描くのことのように、signal wasm.go
を実装する。
package signal
// SetupSignalHandler setup signal handler for TiDB Server
func SetupSignalHandler(shutdownFunc func(bool)) {
}
そして、コンパイルを再開する。
~/go/src/github.com/pingcap/tidb(master*) » GOOS=js GOARCH=wasm go build -o bin/tidb.wasm tidb-server/main.go
# github.com/coreos/go-systemd/journal
../../../../pkg/mod/github.com/coreos/go-systemd@v0.0.0-20181031085051-9002847aa142/journal/journal.go:99:13: undefined: syscall.UnixRights
# github.com/pingcap/goleveldb/leveldb/storage
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:81:16: undefined: newFileLock
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:166:3: undefined: rename
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:252:11: undefined: rename
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:257:11: undefined: syncDir
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:354:14: undefined: rename
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:483:9: undefined: rename
../../../../pkg/mod/github.com/pingcap/goleveldb@v0.0.0-20171020122428-b9ff6c35079e/leveldb/storage/file_storage.go:519:13: undefined: syncDir
# github.com/remyoudompheng/bigfft
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:10:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:11:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:12:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:13:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:14:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:15:6: missing function body
../../../../pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7/arith_decl.go:16:6: missing function body
これは同じ問題だ、偽物の実装を使用する、コンパイルは可能です。
package storage
import (
"os"
"syscall"
)
func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
return nil, syscall.ENOTSUP
}
func setFileLock(f *os.File, readOnly, lock bool) error {
return syscall.ENOTSUP
}
func rename(oldpath, newpath string) error {
return syscall.ENOTSUP
}
func isErrInvalid(err error) bool {
return false
}
func syncDir(name string) error {
return syscall.ENOTSUP
}
同じ方法を使用してarith_decl
の問題を解決はできません、missing function body
エラーとは何ですか?arith_decl.go
のディレクトリは見てとうり、何が起こったのかがわかります。
~ » ls ~/go/pkg/mod/github.com/remyoudompheng/bigfft@v0.0.0-20190512091148-babf20351dd7
arith_386.s arith_arm64.s arith_decl.go arith_mipsx.s calibrate_test.go fermat_test.go fft_test.go LICENSE scan.go
arith_amd64.s arith_arm.s arith_mips64x.s benchmarks fermat.go fft.go go.mod README scan_test.go
arith_decl.go
は関数の宣言であり、関数の特定の実装は、各プラットフォームに関連するなアセンブリファイルにあります。
対応の関数は実装、問題は解除できる、そう考えるのは簡単すぎる。このbigfft
はライブラリです、だからそちのコードの編集は簡単な作業ではありません。TiDB
はこのライブラリに直接依存せず、代わりにmathutil
に依存し、mathutil
lはこのbigfft
に依存します。
TiDB
は、mathutil
のライブラリが提供する関数を使用します、理想的な対策はデフォルトでこれら2つのライブラリを使用する、Wasm
のコンパイル時には使用されません。そのために、util/mathutil
パッケージを作成する、中にリmathutil_linux.go
とmathutil_js.go
を入れて。元々参照されていた関数をmathutil_linux.go
に再輸出します、これらの関数はmathutil_js.go
に再実装されます。これから、Wasm
のターゲットをコンパイルの時はオリジナルのmathutil
ライブラリを使用しません。
~/go/src/github.com/pingcap/tidb(feature/wasm) » GOOS=js GOARCH=wasm go build -o bin/tidb.wasm tidb-server/main.go
~/go/src/github.com/pingcap/tidb(feature/wasm) » ls -l bin
total 85816
-rwxrwxr-x 1 coder coder 87868180 Dec 14 18:16 tidb.wasm
成功しました!
互換性の問題
コンパイル出したのtidb.wasm
はos.Stdin
を介して入力したSQL
を読み取り、os.Stdout
を介して結果を出力します。だから、ウェブページはまだブランクした。ただし、TiDB
のログはos.Stdout
に送られるため、ブラウザコンソールでTiDB
の通常の起動のログを確認する必要があります。しかし、残念ながら例外のスタックトレースが表示されます。
このエラーが発生するの理由はos.Stat
は実装しない。現在、Golang
はWASI
のサポートはあまり良くない、wasm_exec.js
でfs
を部分的に実装しています:
global.fs = {
writeSync(fd, buf) {
...
},
write(fd, buf, offset, length, position, callback) {
...
},
open(path, flags, mode, callback) {
...
},
...
}
このfs
の実装はstat
、lstat
、unlink
、mkdir
などの呼び出しを実装しません。幸いなことに、JavaScript
は動的プログラミング言語です、関数をfs
に動的に追加できます。
function unimplemented() {
const err = new Error('not implemented');
err.code = 'ENOSYS';
arguments[arguments.length - 1](err)
}
fs.stat = unimplemented;
fs.lstat = unimplemented;
fs.unlink = unimplemented;
fs.rmdir = unimplemented;
fs.mkdir = unimplemented;
go.run(result.instance);
ウェブページを再読み込み、起動ログがコンソールに表示されました!
これまで、TiDB
をWasm
にコンパイルするの技術的な問題はすべて解決されました。後では、以前に作成されたのREPL
ターミナルを置き換える適切なターミナルを見つけることなら、ページにSQL
を入力してのことはできます。
ユーザーインターフェース
上記の仕事により、SQL
を受け入れてその実行結果を出力するExec
関数ができました。ブラウザで実行するには、この関数とインタラクションするためのブラウザバージョンのSQL
ターミナルも必要です。その対策はwindow
にExec
関数を登録する、ならJavaScript
の関数はExec
呼び出すことはできます。
js.Global().Set("executeSQL", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
go func() {
// Simplified code
sql := args[0].String()
args[1].Invoke(k.Exec(sql))
}()
return nil
}))
それで、コンソールの場合はSQL
を実行できます。
jquery.console.js
を使用してSQL
ターミナルを構築し、executeSQL
をコールバックとして渡します。完了します!
ローカルファイルアクセス
TiDB
には、ローカルファイルシステムにアクセスする必要があるいくつかの関数があります、例えばLOAD DATA
およびLOAD STATS
。LOAD DATA
の機能は、ローカルファイルからデータベースにデータをインポートする。交換方法はブラウザのファイルアップロードウィンドウを使用した、LOAD STATS
の実装は同じです。
js.Global().Get("upload").Invoke(js.FuncOf(func(this js.Value, args []js.Value) interface{} {
go func() {
fileContent := args[0].String()
_, e := doSomething(fileContent)
c <- e
}()
return nil
}), js.FuncOf(func(this js.Value, args []js.Value) interface{} {
go func() {
c <- errors.New(args[0].String())
}()
return nil
}))
SOURCE
コマンドはローカルファイルを読み取り、まとはMySQL
クライアントで実行します。TiDB
を初めて使用するユーザーは、TiDB
とMySQL
の互換性を確認したいと考えています。このコマンドは、ユーザーがテストデータをすば速いインポートするのに役立ちます。
SOURCE
コマンドの効果を示す例としてtest.sql
ファイルを取り上げますtest.sql
ファイルの内容は下記です。
CREATE DATABASE IF NOT EXISTS samp_db;
USE samp_db;
CREATE TABLE IF NOT EXISTS person (
number INT(11),
name VARCHAR(255),
birthday DATE
);
CREATE INDEX person_num ON person (number);
INSERT INTO person VALUES("1","tom","20170912");
UPDATE person SET birthday='20171010' WHERE name='tom';
SOURCE
コマンドを入力すると、ファイル選択ボックスがポップアップします。
選択後、SQL
が自動的に実行され、TiDB
のテストを続行できます。
まとめと展望
TiDBを移植するために、主にいくつかの問題を解決しました。
-
ブラウザはポートをリスニングのことはできません。
SQL
ターミナルをTiDB
に埋め込みました。 -
goleveldb
のWasm
コンパイル。 -
bigfft
のWasm
コンパイル。 -
Golang
はWASI
のサポートが不完全なため、fs
関連の機能がありません。 -
TiDB
はローカルファイルの読み込みをブラウザのアップロードファイルの読み込みに変換します。 -
SQL
をバッチで実行するSOURCE
コマンドをサポート。
現在PingCAP
は、このプロジェクトをTiDB PlaygroundおよびTiDB Tourのユーザーが利用できるようにしました。ユーザーはインストールと構成を行う必要がないため、ユーザーはドキュメントを読みながら試してみることができます。これにより、ユーザーがTiDB
は使用して学ぶ安いです。コミュニティにはすでにTiDB Wasm
に基づくデータベースチュートリアルがありますtidb-wasm-markdown。
このプロジェクトはPingCAP Hackathon
で二等賞を受賞しました。スケジュールが厳しいため、まだたくさんの機能は実装されていません、例えば:
-
IndexedDB
を使用したデータの永続化:IndexedDB
のストレージインターフェイスのセットを実装する。 -
P2P
を使用した他のブラウザーにサービスを提供する:将来、ますます多くのアプリケーションがWasm
に移行されるでしょう、多くのデータベースが必要、TiDB Wasm
を使用できます。 -
TiDB Wasm
のバイナリスリミング:現在のはほぼ80MB
、読み込みが遅い、実行時によりたくさんのメモリを使用する、これらは最適化する必要があります。
興味のあるコミュニティの友人は、このプロジェクトに参加して一緒に楽しんでください、プロジェクト、info@pingcap.comでお問い合わせいただくこともできます。