TiDB ドキュメント

序文

TiDBは、PingCAP 研究開発の分散型データベースである。TiDBMySQLプロトコルと互換性がある、MySQLユーザーにとって使いやすいことである。

公式ドキュメント

以下は中国語公式ドキュメントと英語公式ドキュメントのリンクである。中国語または英語が上手く方は直接に読むことはおすすめです。

日本語ドキュメントについて

この通訳は個人的な趣味で、自分SakuramiRin様はメンテナンスしています。日本語の初心者なので、説明または構文が不適切な場合、プルリクエストや以下のメールをいただければ心より感谢します。

バージョン

現在TiDBのステェィブルバージョンは三つである。

三つがあるが、公式ドキュメントはどちらでも適用されます。

プログレス

あんまり時間がありませんので、通訳の進捗率は遅くになるかもしれないですが、頑張りたいとおもいます!

ブログ

TiDBに関連するのブログ、最後の付録である。

TiDBの概要

TiDBは、PingCAP 研究開発の分散型HTAP(Hybrid Transactional and Analytical Processing)データベースであり、 RDBMSNoSQLの最高の機能を組み合わせています。TiDBMySQLと相互運用可能であり、機能拡張性、一貫性、高可用性ような属性を持っています。OLTP (Online Transactional Processing)およびOLAP (Online Analytical Processing)の場合でワンストップソリューションを提供することは目标として追求しております。

TiDB 特徴:

  • MySQLと高い互換性

    ほとんどの場合、コードを変更せずに移植できます。もしサブデータベースとサブテーブルを使用すると、移植ツールがあってサポートします。

  • 無制限の拡張機能

    ノードを追加するだけで、パフォーマンスが無制限で拡張するになっていますし、必要なノードを拡張すれば、高並行性と大規模データのシナリオの処理は簡単になります。

  • 分散トランザクション

    TiDBは、標準のACIDトランザクションを完全にサポートしています。

    公式ドキュメントにはこの一文しかありませんが、もう一つつたえたいのは、分散トランザクションのサポートにより、データの変更は成功になったら全てのノードがすぐに有効です。全てのノードが一つという思いがあったら良いです。

  • 金融レベルな高い可用性

    クラシックのマスタースレーブスキームに比べて、Raftの分散コヒーレンスプロトコルアプローチは終始一貫のことを保証します。そして、レプリカが多く存在すれば、障害が発生の時に人工の操作が要らなくて自動回復ことができます。

  • ワンストップHTAPソリューション

    TiDBは典型的なOLTPラインアンドバンクデータベースとともに、強いのOLAP機能があります。TiSparkを配合して、1つのストレージはOLTPOLAPを同時に処理し、面倒なETLプロセスが要りません。

  • クラウドネイティブSQLデータベース

    TiDBは、クラウドデータベース、パブリッククラウド、プライベートクラウド、およびハイブリッドクラウドをサポートします。展開、構成、および保守することは簡単です。

TiDBは100%のOLTPと80%のOLAPのシナリをサポートすることを目指して、複雑なOLAP分析が要るとTiSparkを使用できます。

TiDBはコードに侵入しなくて、クラシックのデータベースミドルウェアあるいはサブデータベースとサブテーブルを置換します。そして、開発者と保守業務者はデータベースのスケール問題を考え必要はなくて、ビジネスの開発ことをもと集中します。研究開発の効率性大きく向上させることがある。

TiDBの始める

TiDBはローカルまたはクラウドプラットフォームに展開できます。パブリッククラウド、プライベートクラウド、あるいはハイブリッドクラウドもサポートできます。実際のシナリオに応じて、TiDBクラスターを展開するの方法を選択してください。

  • Ansible展開:プロダクション運用環境で展開する場合、Ansibleを使用してTiDBクラスターをデプロイしなければならない。

  • Ansibleオフライン展開:デプロイメント環境がネットワークにアクセスすることができない場合は、Ansibleオフライン展開することもできます。

  • TiDB Operator展開Kubernetes環境の展開は、TiDB Operator使用します。AWSGKEAliyunはサポートします。

  • Docker Compose展開TiDBをテスト、TiDBの新たな特徴を試す、またはスタンディング環境に使用する場合は、Docker ComposeTiDBクラスターをローカルに迅速に展開することができます。(プロジェクト環境には適していません)

  • Docker展開Dockerを使用してTiDBクラスターをデプロイできます。(プロジェクト環境には適していません)

ソースコード

TiDBの概要

TiDBは、PingCAP 研究開発の分散型HTAP(Hybrid Transactional and Analytical Processing)データベースであり、 RDBMSNoSQLの最高の機能を組み合わせています。TiDBMySQLと相互運用可能であり、機能拡張性、一貫性、高可用性ような属性を持っています。OLTP (Online Transactional Processing)およびOLAP (Online Analytical Processing)の場合でワンストップソリューションを提供することは目标として追求しております。

TiDB 特徴:

  • MySQLと高い互換性

    ほとんどの場合、コードを変更せずに移植できます。もしサブデータベースとサブテーブルを使用すると、移植ツールがあってサポートします。

  • 無制限の拡張機能

    ノードを追加するだけで、パフォーマンスが無制限で拡張するになっていますし、必要なノードを拡張すれば、高並行性と大規模データのシナリオの処理は簡単になります。

  • 分散トランザクション

    TiDBは、標準のACIDトランザクションを完全にサポートしています。

    公式ドキュメントにはこの一文しかありませんが、もう一つつたえたいのは、分散トランザクションのサポートにより、データの変更は成功になったら全てのノードがすぐに有効です。全てのノードが一つという思いがあったら良いです。

  • 金融レベルな高い可用性

    クラシックのマスタースレーブスキームに比べて、Raftの分散コヒーレンスプロトコルアプローチは終始一貫のことを保証します。そして、レプリカが多く存在すれば、障害が発生の時に人工の操作が要らなくて自動回復ことができます。

  • ワンストップHTAPソリューション

    TiDBは典型的なOLTPラインアンドバンクデータベースとともに、強いのOLAP機能があります。TiSparkを配合して、1つのストレージはOLTPOLAPを同時に処理し、面倒なETLプロセスが要りません。

  • クラウドネイティブSQLデータベース

    TiDBは、クラウドデータベース、パブリッククラウド、プライベートクラウド、およびハイブリッドクラウドをサポートします。展開、構成、および保守することは簡単です。

TiDBは100%のOLTPと80%のOLAPのシナリをサポートすることを目指して、複雑なOLAP分析が要るとTiSparkを使用できます。

TiDBはコードに侵入しなくて、クラシックのデータベースミドルウェアあるいはサブデータベースとサブテーブルを置換します。そして、開発者と保守業務者はデータベースのスケール問題を考え必要はなくて、ビジネスの開発ことをもと集中します。研究開発の効率性大きく向上させることがある。

TiDBの始める

TiDBはローカルまたはクラウドプラットフォームに展開できます。パブリッククラウド、プライベートクラウド、あるいはハイブリッドクラウドもサポートできます。実際のシナリオに応じて、TiDBクラスターを展開するの方法を選択してください。

  • Ansible展開:プロダクション運用環境で展開する場合、Ansibleを使用してTiDBクラスターをデプロイしなければならない。

  • Ansibleオフライン展開:デプロイメント環境がネットワークにアクセスすることができない場合は、Ansibleオフライン展開することもできます。

  • TiDB Operator展開Kubernetes環境の展開は、TiDB Operator使用します。AWSGKEAliyunはサポートします。

  • Docker Compose展開TiDBをテスト、TiDBの新たな特徴を試す、またはスタンディング環境に使用する場合は、Docker ComposeTiDBクラスターをローカルに迅速に展開することができます。(プロジェクト環境には適していません)

  • Docker展開Dockerを使用してTiDBクラスターをデプロイできます。(プロジェクト環境には適していません)

ソースコード

4.0の新しい特徴

TiDB v4.0(以下略記4.0)が2020年5月28日にリリースされ、使いやすさ、安定性、パーフォーマンス、セキュリティおよび機能の方が大幅に改善されました。この記事では、改善されたことの簡単にを説明します、ユーザーは、実際のユースケースに基づいて4.0にアップグレードするかどうかを決定する必要があります。

コア機能

スケジューリング機能

  • ホットスポットの対応ために、より多くのメトリックが考慮されます。これによに、書き込み、読み取りトラフィックに基づくスケジューリング基準しながら、新しいkeyのメトリックは考慮する。新しいスケジューリング方法は、トラフィックのみを考慮する場合と比較して、CPUリソースの使用率の不均一性の問題を大幅に改善できます。詳しくはスケジューリングをご覧ください。

ストレージエンジン。

  • TiFlashRealtime HTAP機能用にTiDBによって追加されたコンポーネントです。TiFlashMulti-Raft Learnerプロトコルを使用してTiKVからリアルタイムでデータリードレプリカをコピーし、行方向ストレージエンジンTiKVとカラム型ストレージTiFlashの完全一貫性を確保します。TiKVTiFlashを異なるマシンにデプロイして、HTAPリソース割り当てと分離の問題を解決できます。詳しくはTiFlashをご覧ください。

  • TiKV v4.0や新しいストレージフォーマットにある、幅の広いテーブルデータのエンコードとデコードの効率を向上させる。

TiDB Dashboard

DBAはTiDB DashboardUIを介してクラスターのトポロジー、構成情報、ログ情報、ハードウェア情報、オペレーティングシステム情報、スロークエリ情報、SQL情報、診断レポートなど。この情報は、DBAがデータベースシステムをすばやく理解して分析するのに役立ちます。詳細は以下の通りです。

  • クラスター情報は、TiDBTiKVPDTiFlashおよびインスタンスの実行状態。

  • Key VisualizerTiDBクラスターの一定期間にトラフィックに関する履歴情報を取得して、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_CACHECYCLE/NO_CYCLEオプションをサポート、ユーザーはシーケンスを使用してID作成できます。詳しくはSequenceをご覧ください。

  • 新しいFlashbackは、誤ってTruncateされたテーブルを復元する。

  • OOMを回避するには、JoinSortの中間結果をディスクに書き込みます、システムの安定性を向上させる。

  • EXPLAINEXPLAIN ANALYZEの表示を改善して、より多くの情報を表示して、トラブルシューティングの効率を向上させます。詳しくはEXPLAIN ANALYZEEXPLAINをご覧ください。

  • Index Mergeをサポートする。Index Mergeは新しいテーブルデータアクセスメソッド。単一のテーブルを含むクエリの場合、複数のインデックスデータを自動的に読み取りにオプティマイザ、その結果を合併して、パフォーマンスを向上させます。詳しくはIndex Mergeをご覧ください。

  • TiDBカラムをAUTO_RANDOMのキーの属性をサポートする。ホットスポットの問題の解決を助ける、MySQLユーザーのマイグレーションのコストを節約することができる。詳しくはAUTO_RANDOMのキーをご覧ください。

  • クラスターのトポロジー、構成情報、ログ情報、ハードウェア情報、オペレーティングシステム情報、スロークエリ情報、SQL情報のテーブルを追加する。DBAがデータベースシステムをすばやく理解して分析するのに役立ちます。詳しくはInformation SchemaSQL Diagnosisをご覧ください。詳細は以下の通りです。

    • データベースシステムテーブル
      • cluster_infoのテーブルは、クラスターのトポロジーの情報を保存する。
      • cluster_logのテーブルは、クラスターのログの情報を保存する。
      • cluster_hardwarecluster_hardwareのテーブルは、クラスターのハードウェアとオペレーティングシステムの情報を保存する。
    • スロークエリ、SQL情報のテーブル
      • cluster_slow_queryのテーブルは、グローバルのスロークエリの情報を保存する。
      • cluster_processlistのテーブルは、グローバルのプロセスリストの情報を保存する。
      • inspection_resultのテーブルは、システムのボトルネックを自動的に分析し、DBAがパフォーマンス分析レポートを役立ちます。障害分析の効率を向上させる。
      • metrics_summarymetric_summary_by_labelテーブルは、システムの全てのメトリックの情報を保存する、DBAがSQLを介してメトリックの読みますおよび過去のデータと比較する。
      • inspection_summaryテーブルは、複数のデータリンクとアクセスリンク中のさまざまな主要な監視メトリックを保存する。DBAが読み取り、書き込みなどのリンクの障害を分析できます。

文字セットと照合順序

TiDB 4.0は大文字小文字を区別しませんutf8mb4_general_ciとアクセントを区別しないutf8_general_ci,详情参阅をサポートする。詳しくは文字セットと照合順序をご覧ください。

セキュリティ

  • クライアントとサーバー、コンポーネント間の暗号化された通信を改善し、コネクタの安全を保証する。受信と送信されたデータがアタッカーによって読み取られたり改変されたりしないように保護します。証明書ベースの認証、オンラインで証明書を更新する、TLS証明書のCommonName属性を確認してなど。

  • 透過的データ暗号化(TDE)はTiDBの新機能です、許可されているアプリケーションにデータを自動的に復号化して。TDEはファイルに対して、ディスク書き込み前に暗号化し、メモリに読み取り前に復号化して。AES128-CTRAES192-CTRAES256-CTRの暗号化アルゴリズムおよびAWS KMSにキーの管理をサポートする。詳しくは保存時の暗号化をご覧ください。

バックアップと復元

バックアップの所要時間を短縮するテクニックは、単一のTiDBクラスターをバックアップと復元できます。高速の完全バックアップと復元をサポートし、データのソートして、範囲による分割をサポート。詳しくはバックアップと復元をご覧ください。

サービスレベル

  • Prepare/Executeリクエストの実行プランのキャッシュをサポートして、SQL実行効率を向上させる。詳しくはPrepare/Executeプランのキャッシュをご覧ください。

  • 新しいのレッドプールを実現します、スレッドプールの数を減らし、リクエストのスケジュールは最適化した。TiDBのパフォーマンスを向上させます。

  • Follower ReadRaftプロトコルの完全一貫性を確保に基づ、followerロールからデータを読み取ります、クラスターのスループットを改善し、leaderロールのロードを減らした。Follower Readロードバランスのテクニック、followerロールは完全一貫性を保証もできます。詳しくはFollower Readをご覧ください。

TiDBメイン構造

TiDBはスケーリングと高い可用性の機能であり、深く理解欲しいなら、先ずはTiDBのメイン構造勉強します。TiDBクラスターは三かつメインコンポーネントである、TiDB ServerPD ServerTiKV Serverである。TiSparkは、複雑なOLAPのソリューションを目指した、TiDB Operatorは簡単にKubernetesにデプロイできます。

architecture

TiDB Server

TiDB ServerSQLリクエストに受信します。TiDB ServerSQLを実行計画にインタプリタ後はPD Serverにデータ保管のTiKV Serverアドレス見つかった。TiDB ServerTiKV Serverに通信データにアクセスして。TiDB Serverは持久的データではありません、自体はストレジの機能ではない、計算のみを担当、スケーリングできます。負荷分散コンポーネント(LVSHAProxyF5)利用すれば、同じアドレスのことである。

PD Server

Placement DriverPD)は、クラスター全体の管理者、主な機能は3つであり、1つはクラスターのメタデータを保管するのこと(KeyTiKVの対応)、二つはTiKVクラスターのスケジューリングと負荷分散、そしてグローバルにユニークの増分のトランザクションのIDを管理配分する。

PDRaftの分散コヒーレンスプロトコルを使用してデータのセキュリティを保証する。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つのクラスターでOLTPOLAPの両方のシナリオを対応できるため、ユーザーはデータ転送を心配する必要がありません。

TiDB Operator

TiDB Operatorは、主流のクラウドインフラストラクチャ(Kubernetes)でTiDBクラスターを展開、管理、マルチクラスターハイブリッド、障害の自動修復できるようにします。

TiDBメイン構造

TiDBはスケーリングと高い可用性の機能であり、深く理解欲しいなら、先ずはTiDBのメイン構造勉強します。TiDBクラスターは三かつメインコンポーネントである、TiDB ServerPD ServerTiKV Serverである。TiSparkは、複雑なOLAPのソリューションを目指した、TiDB Operatorは簡単にKubernetesにデプロイできます。

architecture

TiDB Server

TiDB ServerSQLリクエストに受信します。TiDB ServerSQLを実行計画にインタプリタ後はPD Serverにデータ保管のTiKV Serverアドレス見つかった。TiDB ServerTiKV Serverに通信データにアクセスして。TiDB Serverは持久的データではありません、自体はストレジの機能ではない、計算のみを担当、スケーリングできます。負荷分散コンポーネント(LVSHAProxyF5)利用すれば、同じアドレスのことである。

PD Server

Placement DriverPD)は、クラスター全体の管理者、主な機能は3つであり、1つはクラスターのメタデータを保管するのこと(KeyTiKVの対応)、二つはTiKVクラスターのスケジューリングと負荷分散、そしてグローバルにユニークの増分のトランザクションのIDを管理配分する。

PDRaftの分散コヒーレンスプロトコルを使用してデータのセキュリティを保証する。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つのクラスターでOLTPOLAPの両方のシナリオを対応できるため、ユーザーはデータ転送を心配する必要がありません。

TiDB Operator

TiDB Operatorは、主流のクラウドインフラストラクチャ(Kubernetes)でTiDBクラスターを展開、管理、マルチクラスターハイブリッド、障害の自動修復できるようにします。

TiDB-Wasm 原理と実現

クイックスタート:https://play.pingcap.com/

tidb-wasm-demo

WebAssembly の概要

読者にWebAssembly大体理解ために、先ずはこの技術の基本的な紹介である。

WebAssembly公式紹介はこちら。

WebAssembly(以下略記Wasm)は、スタックベースの仮想マシン用のバイナリ命令形式であり、 Wasmは、CC++Rustなどの高レベル言語のコンパイル用のポータブルターゲットとして設計されており、クライアントおよびサーバー上のアプリケーション用にWeb上に展開できます。

言い換えれば、以下の結論で。

  • Wasmは実行ファイルです。

  • CC++Rustなどの高レベル言語のプログラムをWasmにコンパイルできます。

  • Wasmはブラウザに実行できます。

実行の命令形式

以上の三つの結論見てとうり、質問があるかもしれます、命令形式は何ですか?一般的なELFファイルUnixシステムの共通の実行バイナリ命令形式、ローダーによって解析され、メモリにはいります、そして実行です。Wasmも同様、対応のランタイムを解析および実行である。現在、主流のブラウザー、Node.js、およびWasmerと呼ばれるWasm専用に設計された一般的なランタイムです。さらに一歩進む、Wasm作成したプログラムをカーネルモードで簡単に実行できるために、Wasmランタイムをカーネルに統合する機能をLinuxカーネルに提供する人もいます。

主要なブラウザのWasmサポート

wasm-support

高レベル言語からWasmまで

上記の背景知識があれば、高レベル言語がどのようにWasmにコンパイルされる方は理解できます。まず、高水準言語のコンパイルプロセスを見てください。

compile-process

アセンブリと比較して、高レベル言語の特徴の1つは移植性です。例えば、CC++x86マシンのターゲットにコンパイルできます、およびARMのマシンのターゲット。WasmARMx86は実際には同じ種類のものであり、バイトコードの実行をサポートする仮想マシンと考えることができます。これはJavaに非常に似ていますが、実際には、CC++JVMにコンパイルおよび実行できます。

さまざまなランタイムとWASI

以上はWasmのデザインの目標はプログラムにweb上に実行です。実際、Wasmの元々デザインのターゲットはJavaScriptの実行効率を補うためください。開発が進むにつれて、この技術は仮想マシンとして扱う、そしてプログラムに移植するはまた、良いアイデアである。そのため、NodeJSの実行環境、Wasmerの実行環境、さらにはカーネル環境もあります。それから質問が来ます、こんあ沢山の実行環境であり、しかも各環境のインターフェースは違います、例えば、NodeJSはファイルシステムのインターフェースはできます、ブラウザはこのインターフェースはできまさん。Wasmの移植性に対処するには、WASI(WebAssembly System Interface)が生まれました。WASIは低レベルの標準のインターフェースを定義します、コンパイラとWasmランタイム環境がこの標準をサポートしている限り、生成されたWasmはさまざまな環境にに移植できます。Wasmランタイムは仮想マシンに相当し、Wasmはこのマシンの実行可能プログラムであり、WASIはこのマシンで実行されているシステムであり、そしてWasmの基礎的なインターフェースを提供します、例えばファイルシステムおよびソケットなど。

WasmWASIが何であるかをより良く説明するために、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.watWasmのテキストコードです、watWasmの関係は、アセンブリとELFの関係に似ています。次に、watWasmにコンパイルし、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関数の出力を標準出力にフォーマットしてから、ループでユーザー入力の読み取りを続けます。

コンパイルの問題

ターミナルの統合は最初の手順です、次には重要な質問を検証する必要があります。TiDBWasmのターゲットにコンパイルできますか?TiDBGolangで製されていますが、しかし、参照されたライブラリは、プラットフォーム固有のコードを直接コンパイルできない場合があります。公式の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に依存し、mathutillはこのbigfftに依存します。

TiDBは、mathutilのライブラリが提供する関数を使用します、理想的な対策はデフォルトでこれら2つのライブラリを使用する、Wasmのコンパイル時には使用されません。そのために、util/mathutilパッケージを作成する、中にリmathutil_linux.gomathutil_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.wasmos.Stdinを介して入力したSQLを読み取り、os.Stdoutを介して結果を出力します。だから、ウェブページはまだブランクした。ただし、TiDBのログはos.Stdoutに送られるため、ブラウザコンソールでTiDBの通常の起動のログを確認する必要があります。しかし、残念ながら例外のスタックトレースが表示されます。

exception-stack

このエラーが発生するの理由はos.Statは実装しない。現在、GolangWASIのサポートはあまり良くない、wasm_exec.jsfsを部分的に実装しています:

global.fs = {
  writeSync(fd, buf) {
    ...
  },
  write(fd, buf, offset, length, position, callback) {
    ...
  },
  open(path, flags, mode, callback) {
    ...
  },
  ...
}

このfsの実装はstatlstatunlinkmkdirなどの呼び出しを実装しません。幸いなことに、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);

ウェブページを再読み込み、起動ログがコンソールに表示されました!

startup-log

これまで、TiDBWasmにコンパイルするの技術的な問題はすべて解決されました。後では、以前に作成されたのREPLターミナルを置き換える適切なターミナルを見つけることなら、ページにSQLを入力してのことはできます。

ユーザーインターフェース

上記の仕事により、SQLを受け入れてその実行結果を出力するExec関数ができました。ブラウザで実行するには、この関数とインタラクションするためのブラウザバージョンのSQLターミナルも必要です。その対策はwindowExec関数を登録する、なら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を実行できます。

console-call-go-func

jquery.console.jsを使用してSQLターミナルを構築し、executeSQLをコールバックとして渡します。完了します!

show-databases

ローカルファイルアクセス

TiDBには、ローカルファイルシステムにアクセスする必要があるいくつかの関数があります、例えばLOAD DATAおよびLOAD STATSLOAD 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を初めて使用するユーザーは、TiDBMySQLの互換性を確認したいと考えています。このコマンドは、ユーザーがテストデータをすば速いインポートするのに役立ちます。

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コマンドを入力すると、ファイル選択ボックスがポップアップします。

source-file-select

選択後、SQLが自動的に実行され、TiDBのテストを続行できます。

source-test

まとめと展望

TiDBを移植するために、主にいくつかの問題を解決しました。

  • ブラウザはポートをリスニングのことはできません。SQLターミナルをTiDBに埋め込みました。

  • goleveldbWasmコンパイル。

  • bigfftWasmコンパイル。

  • GolangWASIのサポートが不完全なため、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/

tidb-wasm-demo

WebAssembly の概要

読者にWebAssembly大体理解ために、先ずはこの技術の基本的な紹介である。

WebAssembly公式紹介はこちら。

WebAssembly(以下略記Wasm)は、スタックベースの仮想マシン用のバイナリ命令形式であり、 Wasmは、CC++Rustなどの高レベル言語のコンパイル用のポータブルターゲットとして設計されており、クライアントおよびサーバー上のアプリケーション用にWeb上に展開できます。

言い換えれば、以下の結論で。

  • Wasmは実行ファイルです。

  • CC++Rustなどの高レベル言語のプログラムをWasmにコンパイルできます。

  • Wasmはブラウザに実行できます。

実行の命令形式

以上の三つの結論見てとうり、質問があるかもしれます、命令形式は何ですか?一般的なELFファイルUnixシステムの共通の実行バイナリ命令形式、ローダーによって解析され、メモリにはいります、そして実行です。Wasmも同様、対応のランタイムを解析および実行である。現在、主流のブラウザー、Node.js、およびWasmerと呼ばれるWasm専用に設計された一般的なランタイムです。さらに一歩進む、Wasm作成したプログラムをカーネルモードで簡単に実行できるために、Wasmランタイムをカーネルに統合する機能をLinuxカーネルに提供する人もいます。

主要なブラウザのWasmサポート

wasm-support

高レベル言語からWasmまで

上記の背景知識があれば、高レベル言語がどのようにWasmにコンパイルされる方は理解できます。まず、高水準言語のコンパイルプロセスを見てください。

compile-process

アセンブリと比較して、高レベル言語の特徴の1つは移植性です。例えば、CC++x86マシンのターゲットにコンパイルできます、およびARMのマシンのターゲット。WasmARMx86は実際には同じ種類のものであり、バイトコードの実行をサポートする仮想マシンと考えることができます。これはJavaに非常に似ていますが、実際には、CC++JVMにコンパイルおよび実行できます。

さまざまなランタイムとWASI

以上はWasmのデザインの目標はプログラムにweb上に実行です。実際、Wasmの元々デザインのターゲットはJavaScriptの実行効率を補うためください。開発が進むにつれて、この技術は仮想マシンとして扱う、そしてプログラムに移植するはまた、良いアイデアである。そのため、NodeJSの実行環境、Wasmerの実行環境、さらにはカーネル環境もあります。それから質問が来ます、こんあ沢山の実行環境であり、しかも各環境のインターフェースは違います、例えば、NodeJSはファイルシステムのインターフェースはできます、ブラウザはこのインターフェースはできまさん。Wasmの移植性に対処するには、WASI(WebAssembly System Interface)が生まれました。WASIは低レベルの標準のインターフェースを定義します、コンパイラとWasmランタイム環境がこの標準をサポートしている限り、生成されたWasmはさまざまな環境にに移植できます。Wasmランタイムは仮想マシンに相当し、Wasmはこのマシンの実行可能プログラムであり、WASIはこのマシンで実行されているシステムであり、そしてWasmの基礎的なインターフェースを提供します、例えばファイルシステムおよびソケットなど。

WasmWASIが何であるかをより良く説明するために、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.watWasmのテキストコードです、watWasmの関係は、アセンブリとELFの関係に似ています。次に、watWasmにコンパイルし、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関数の出力を標準出力にフォーマットしてから、ループでユーザー入力の読み取りを続けます。

コンパイルの問題

ターミナルの統合は最初の手順です、次には重要な質問を検証する必要があります。TiDBWasmのターゲットにコンパイルできますか?TiDBGolangで製されていますが、しかし、参照されたライブラリは、プラットフォーム固有のコードを直接コンパイルできない場合があります。公式の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に依存し、mathutillはこのbigfftに依存します。

TiDBは、mathutilのライブラリが提供する関数を使用します、理想的な対策はデフォルトでこれら2つのライブラリを使用する、Wasmのコンパイル時には使用されません。そのために、util/mathutilパッケージを作成する、中にリmathutil_linux.gomathutil_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.wasmos.Stdinを介して入力したSQLを読み取り、os.Stdoutを介して結果を出力します。だから、ウェブページはまだブランクした。ただし、TiDBのログはos.Stdoutに送られるため、ブラウザコンソールでTiDBの通常の起動のログを確認する必要があります。しかし、残念ながら例外のスタックトレースが表示されます。

exception-stack

このエラーが発生するの理由はos.Statは実装しない。現在、GolangWASIのサポートはあまり良くない、wasm_exec.jsfsを部分的に実装しています:

global.fs = {
  writeSync(fd, buf) {
    ...
  },
  write(fd, buf, offset, length, position, callback) {
    ...
  },
  open(path, flags, mode, callback) {
    ...
  },
  ...
}

このfsの実装はstatlstatunlinkmkdirなどの呼び出しを実装しません。幸いなことに、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);

ウェブページを再読み込み、起動ログがコンソールに表示されました!

startup-log

これまで、TiDBWasmにコンパイルするの技術的な問題はすべて解決されました。後では、以前に作成されたのREPLターミナルを置き換える適切なターミナルを見つけることなら、ページにSQLを入力してのことはできます。

ユーザーインターフェース

上記の仕事により、SQLを受け入れてその実行結果を出力するExec関数ができました。ブラウザで実行するには、この関数とインタラクションするためのブラウザバージョンのSQLターミナルも必要です。その対策はwindowExec関数を登録する、なら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を実行できます。

console-call-go-func

jquery.console.jsを使用してSQLターミナルを構築し、executeSQLをコールバックとして渡します。完了します!

show-databases

ローカルファイルアクセス

TiDBには、ローカルファイルシステムにアクセスする必要があるいくつかの関数があります、例えばLOAD DATAおよびLOAD STATSLOAD 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を初めて使用するユーザーは、TiDBMySQLの互換性を確認したいと考えています。このコマンドは、ユーザーがテストデータをすば速いインポートするのに役立ちます。

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コマンドを入力すると、ファイル選択ボックスがポップアップします。

source-file-select

選択後、SQLが自動的に実行され、TiDBのテストを続行できます。

source-test

まとめと展望

TiDBを移植するために、主にいくつかの問題を解決しました。

  • ブラウザはポートをリスニングのことはできません。SQLターミナルをTiDBに埋め込みました。

  • goleveldbWasmコンパイル。

  • bigfftWasmコンパイル。

  • GolangWASIのサポートが不完全なため、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でお問い合わせいただくこともできます。