MRでより少ないコードを記述する方法、またはなぜ世界に別のクエリ言語が必要なのですか? Yandexクエリ言語の歴史

歴史的に、Yandexの多くの部分では、特定のプロジェクトの詳細を考慮して、大量のデータを保存および処理するシステムが開発されてきました。 この開発では、効率、拡張性、および信頼性が常に優先事項でした。したがって、原則として、このようなシステムを使用するための便利なインターフェースのための時間はありませんでした。 1年半前、大規模なインフラストラクチャコンポーネントの開発は、製品チームから別の方向に選ばれました。 目標は次のとおりでした:より速く動き始め、同様のシステム間の重複を減らし、新しい内部ユーザーのしきい値を下げます。



すぐに、ここで共通の高レベルクエリ言語が役立ち、既存のシステムへの均一なアクセスを提供し、これらのシステムで採用されている低レベルプリミティブの典型的な抽象化を再実装する必要もなくなることに気付きました。 したがって、データストレージおよび処理システム用の汎用宣言型クエリ言語であるYandex Query Language(YQL)の開発が始まりました。 (これはYQLと呼ばれる世界で最初のものではないことがわかっているとすぐに言いますが、これが問題を妨げないことを決定し、名前を残しました。)

Yandexインフラストラクチャに特化した会議を期待して、Habrahabrの読者にYQLについて伝えることにしました。

建築


もちろん、HadoopやSparkなど、世界で人気のあるオープンソースエコシステムの方向を見ることができます。 しかし、彼らは真剣に考慮されませんでした。 実際には、Yandexですでに普及しているデータウェアハウスとコンピューターシステムのサポートが必要でした。 このため、YQLはあらゆるレベルで拡張可能に設計および実装されました。 以下のすべてのレベルを順番に見ていきます。



図では、ユーザークエリは上から下に移動しますが、ストーリーがよりつながりやすくなるように、影響を受ける要素を下から上に逆の順序で説明します。 開始するには、現在サポートされているバックエンドまたは私たちが呼んでいるデータプロバイダーに関するいくつかの言葉:



コア


技術的には、YQLは比較的分離されたコンポーネントとライブラリで構成されていますが、主にサービスとして内部ユーザーに提供されます。 これにより、彼らは「シングルウィンドウサービス」としての観点から見て、各バックエンドのアクセスの発行やファイアウォールの設定などの組織の問題に対する人件費を最小限に抑えることができます。 さらに、Yandexの従来のMapReduceの両方の実装では、トランザクションの完了を同期的に待機するクライアントプロセスが必要であり、YQLサービスがそれを処理し、ユーザーが「後で結果を求めて実行」モードで作業できるようにします。 ただし、サービスのモデルをライブラリ形式の配布と比較すると、欠点もあります。 たとえば、互換性のない変更やリリースにはさらに注意を払う必要があります。そうでない場合は、最も不適切な瞬間にユーザープロセスが中断される可能性があります。

YQLサービスの主なエントリポイントはHTTP REST APIです。これはNettyの Javaアプリケーションとして実装され、計算のための着信要求の起動を処理するだけでなく、幅広い補助的な役割も持ちます。

Javaを使用すると、必要なすべてのシステムで既製の非同期クライアントを使用できるため、このすべてのビジネスロジックを迅速に実装することができました。 あまりにも厳密な遅延要件はまだないので、ガベージコレクションにはほとんど問題がなく、 G1に切り替えた後、それらはほとんどなくなりました。 上記に加えて、ノード間の同期のために、 ZooKeeperが使用されます。これには、通知を送信するときのパブリッシャー-サブスクライバーパターンも含まれます。

カスタム計算クエリの実行自体は、yqlworkerと呼ばれる別個のC ++プロセスによって調整されます。 これらは、REST APIと同じマシン上でもリモートでも実行できます。 実際には、Yandexで開発され広く使用されているMessageBusプロトコルを使用して、ネットワーク上で通信が行われています。 yqlworkerのコピーは、forkシステムコール(execなし)を使用して、リクエストごとに作成されます。 このようなスキームにより、 コピーオンライトメカニズムのおかげで、初期化に時間を無駄にせずに、異なるユーザーからのリクエストを十分に分離することができます。

高度なアーキテクチャの図からわかるように、Yandexクエリ言語には2つの表現があります。

選択された構文に関係なく、クエリから、関数型プログラミングで一般的なプリミティブを使用して必要なデータ処理を論理的に記述する式グラフが作成されます。 このようなプリミティブには、λ関数、表示(MapおよびFlatMap)、フィルタリング(Filter)、畳み込み(Fold)、ソート(Sort)、アプリケーション(Apply)などが含まれます。 SQL構文の場合、 ANTLR v3に基づくレクサーとパーサーが抽象構文ツリーを構築し、それを使用して計算グラフを構築します。 s-expression構文の場合、文法は非常に単純であり、プログラムはいずれにせよこれらの抽象化で動作するため、パーサーはほとんど自明です。

さらに、必要な結果を得るために、要求はいくつかの段階を経て、必要に応じて、すでに完了した状態に戻ります。

リクエストのライフサイクルのどの段階でも、s-expressions構文にシリアル化することができます。これは、何が起こっているかを診断して理解するのに非常に便利です。

インターフェース


はじめに述べたように、YQLの重要な要件の1つは使いやすさでした。 したがって、パブリックインターフェイスには特別な注意が払われており、非常に積極的に開発されています。

コンソールクライアント




この図は、自動補完、構文の強調表示、色のテーマ、通知、その他の装飾を備えたインタラクティブモードを示しています。 ただし、コンソールクライアントは、ファイルまたは標準ストリームからI / Oモードで起動することもできます。これにより、コンソールクライアントを任意のスクリプトや通常のプロセスに統合できます。 操作の同期および非同期の両方の起動、クエリプランの表示、ローカルファイルの添付、クラスターおよびその他の基本機能のナビゲートがあります。

このような豊富な機能は、2つの理由で登場しました。 一方で、主にコンソールで作業することを好むYandexの人々の顕著な層があります。 一方、これは、フル機能のWebインターフェイスの開発に時間をかけるために行われました。これについては後で説明します。

興味深い技術的ニュアンス:コンソールクライアントはPythonで実装されますが、Linux、OS X、およびWindows用にコンパイルされる組み込みインタープリターを使用して、依存関係のない静的にリンクされたネイティブアプリケーションとして配布されます。 さらに、最新のブラウザのような自動更新も可能です。 コードを構築してリリースを準備するためのYandexの内部インフラストラクチャのおかげで、これらはすべて非常に簡単に整理できました。

Pythonライブラリ




PythonはYandexでC ++に次いで2番目に広く使用されているプログラミング言語です。そのため、YQLクライアントライブラリが実装されています。 実際、最初はコンソールクライアントの一部として開発された後、独立した製品として分離されたため、同じコードを再発明することなく他のPython環境で使用できるようになりました。

たとえば、多くのアナリストはJupyter環境での作業を好むため、いわゆる%yqlマジックがこのクライアントライブラリに基づいて作成されています。



コンソールクライアントとともに、事前に構成されたJupyterまたはIPythonを実行する2つの特別なルーチンが提供され、クライアントライブラリが既に利用可能です。 それらは上に示されています。

Webインターフェース




YQL言語、クエリ開発、および分析を学習するための主要なツールは、初心者向けに残しました。 Webインターフェースでは、コンソールの技術的な制限がないため、すべてのYQL機能はより視覚的な形式で利用でき、常に手元にあります。 インターフェース機能の一部は、他の画面の例に示されています。


...だけでなく

REST API自体のすべてのペンにはコードで注釈が付けられ、Swaggerを使用してこれらの注釈を使用して詳細なオンラインドキュメントが自動的に生成されます。 それから、コードを1行も使わずにリクエストを試みることができます。 これにより、何らかの理由で上記の既製のオプションが適合しなかった場合でも、YQLを簡単に使用できます。 たとえば、Perlが好きな場合。

特徴


Yandex Query Languageを使用して解決できるタスクプランの種類と、ユーザーに提供される機会についてお話します。 すでに長いポストを延長しないように、この部分はむしろ論文です。

SQL



ユーザー定義関数

すべてのタイプのデータ変換が宣言的に便利に表現されるわけではありません。 ループを書いたり、既製のライブラリを使用したほうが簡単な場合があります。 このような状況に対して、YQLはユーザー関数のメカニズムを提供します。これらはユーザー定義関数であり、UDFでもあります。



集計関数

内部では、集計関数は、 DISTINCTサポートし、最上位とGROUP BY両方で実行される共通フレームワークを使用しDISTINCT (SQL:1999標準のROLLUP/CUBE/GROUPING SETSを含む)。 そして、これらの機能はビジネスロジックのみが異なります。 以下に例を示します。


パフォーマンス上の理由から、集計関数のMapReduceの観点から、Mapサイドコンバイナーが自動的に作成され、Reduceの中間集計結果の集計が行われます。 DISTINCTは常に(近似計算なしで)正確に機能するようになったため、一意の値をマークするには追加のReduceが必要です。

テーブルを結合する

キーによるテーブルのマージは、問題を解決するためにしばしば必要とされる最も一般的な操作の1つですが、MapReduceの観点から正しく実装されるのはほとんど科学です。 論理的に、Yandexクエリ言語では、すべての標準モードに加えて、いくつかの追加モードが利用できます。



ユーザーから詳細を隠すために、MapReduceに基づくバックエンドの場合、参加テーブルの必要な論理タイプと物理プロパティに応じて、JOIN実行戦略がオンザフライで選択されます(これはいわゆるコストベースの最適化です)。

戦略簡単な説明ブール型に利用可能
共通参加1-2マップ+削減全部
マップ側の結合1地図内側、左、左のみ、左セミ、クロス
シャードマップ側の結合k並列マップ(デフォルトではk <= 4)内側、左セミ、ユニークな右、クロス
ソートせずに削減1削減しますが、事前にソートされた入力が必要です開発中


開発方向


Yandex Query Languageの中期および中期計画の中で:




まとめると




最後に、10月15日の次の土曜日にオフィスでの会議に招待します。そこでは、Yandexインフラストラクチャのさまざまな側面について詳しく説明します。

Source: https://habr.com/ru/post/J312430/


All Articles