FlinkのストリーミングETL構造に基づくNetEaseゲーム

NeteaseGamesのシニア開発エンジニアであるLinXiaoboが、Flinkに基づくNetEaseGamesのストリーミングETL構築について紹介します。コンテンツが含まれます:
  1. 事業背景
  2. 専用ETL
  3. EntryX General ETL
  4. チューニング練習
  5. 未来の計画

1.事業背景

NetEase GamesETLサービスの概要

NetEaseゲームの基本データは、主にログモードで収集されます。これらのログは通常、非構造化データまたは半構造化データであり、リアルタイムまたはオフラインのデータウェアハウスに保存する前にデータ統合ETLを実行する必要があります。その後、ビジネスユーザーはSQLを簡単に使用して、リアルタイムのFlinkSQLやオフラインのHiveまたはSparkを含むほとんどのデータ計算を完了することができます。

NetEaseゲームデータ統合のデータフローは、主にゲームクライアントログ、ゲームサーバーログ、およびNginxアクセスログやデータベースログなどの他の周辺の基本ログを含む、ほとんどの企業のデータフローと同様です。これらのログは、統合されたKafkaデータパイプラインに収集され、ETLウェアハウジングサービスを介してHiveオフラインデータウェアハウスまたはKafkaリアルタイムデータウェアハウスに書き込まれます。

これは非常に一般的なアーキテクチャですが、要件に関していくつかの特別な状況があります。

NeteaseゲームストリーミングETL要求特性

まず、インターネットや金融業界で一般的に使用されているMySQLやPostgresなどのリレーショナルデータベースとは異なり、ゲーム業界ではMongoDBなどのスキーマフリーのドキュメントデータベースを使用することがよくあります。これがETLサービスにもたらす問題は、信頼できるオンラインビジネスの正確なスキーマがないことです。実際のデータ処理では、フィールドが多かれ少なかれ、1つのフィールドでも完全に異なる形式に繰り返し変更されます。ゲームプレイの状況はすべて可能です。このようなデータの不均一性の問題により、ETLデータのクリーニングに比較的高いコストがかかりました。

次に、データベースの選択により、ほとんどのビジネスデータベースモデルは反パラダイム設計に従い、テーブル間の結合を回避するために意図的に複雑な埋め込みフィールドを使用します。この状況の利点の1つは、データ統合段階で複数のデータストリームをリアルタイムで結合する必要がないことです。欠点は、データ構造が非常に複雑になる可能性があり、マルチレベルのネストが非常に一般的であるということです。

その後、近年のリアルタイムデータウェアハウスの人気により、リアルタイムデータウェアハウスも徐々に構築しているため、既存のETLパイプラインを再利用し、一度抽出して変換し、にロードするのが自然な開発の方向性です。 2つのリアルタイムオフラインデータウェアハウス。

最後に、多くのログタイプがあり、頻繁に変更されます。たとえば、複雑なゲームプレイのゲームには1,000を超えるログタイプがあり、2週間ごとにリリースされる場合があります。このコンテキストでは、ETLの異常なデータは避けられません。したがって、完全な例外処理を提供する必要があります。これにより、企業はデータの例外について時間内に学習し、プロセスを通じてデータを修復できます。

ログの分類と特性

さまざまなビジネスモデルの使用をより適切に最適化するために、さまざまなログタイプのビジネスにさまざまなサービスを提供しています。ログは通常、操作ログ、ビジネスログ、プログラムログの3種類に分けられます。

操作ログには、アカウントへのログインやギフトパッケージの受け取りなど、プレーヤーの行動イベントが記録されます。このタイプのログは最も重要なログであり、固定形式、つまり特定のヘッダー+ jsonのテキスト形式があります。データの主な目的は、データレポート、データ分析、およびプレーヤーチームのマッチングの推奨事項などのゲーム内の推奨事項を作成することです。

ビジネスログは、プレーヤーの動作以外のビジネスイベントを記録します。これは、Nginxアクセスログ、CDNダウンロードログなど、より広範囲です。これらは固定形式ではなく、バイナリまたはテキストの場合があります。主な目的は操作ログに似ていますが、より豊富でカスタマイズされています。

プログラムログレコードは、プログラムの実行ステータスです。つまり、通常ログフレームワークを介して入力するINFOやERRORなどのログです。プログラムログの主な目的は、操作上の問題を取得して特定することです。通常はESに書き込まれますが、数が多すぎる場合やインデックス分析を抽出する必要がある場合は、データウェアハウスに書き込まれることもあります。

NetEase GamesETLサービスの分析

これらのログ分類では、特に3種類のETLストレージサービスを提供しています。1つは操作ログ専用のETLで、操作ログのモードに応じてカスタマイズされます。次に、テキストログ用の一般的なentryX ETLサービスがあります。これは、操作ログを除くすべてのログを提供します。最後に、暗号化されたデータや特別な変換が必要なデータなど、EntryXがサポートできない特別なETL要件があります。この場合、それらに対処するためのアドホックジョブを開発します。

2.操作ログのETL

運用ログETL開発履歴

操作ログETLサービスには長い歴史があります。2013年頃、NetEase Gamesは、Hadoopストリーミング+ Pythonの前処理/後処理に基づくオフラインETLフレームワークの最初のバージョンを確立しました。このフレームワークは、長年にわたってスムーズに実行されています。

2017年、Spark Streamingの登場に伴い、POCに相当するSpark Streamingをベースにした2つ目のバージョンを開発しましたが、微調整が難しく、小さなファイルが多いため、アプリケーションを起動しませんでした。

Flinkがすでに比較的成熟していた2018年に、ビジネスをFlinkに移行することを決定したため、FlinkDataStreamに基づいて操作ログETLサービスの第3版を自然に開発しました。ここでの特別な点は、私たちのビジネス側が長い間多くのPython ETLスクリプトを蓄積してきたため、新しいバージョンの最も重要なポイントは、これらのPythonUDFのシームレスな移行をサポートすることです。

運用ログETLアーキテクチャ

次に、2つのバージョンのアーキテクチャの比較を見てみましょう。

Hadoop Streamingの初期バージョンでは、データは最初にHDFSにダンプされ、次にHadoop Streamingがマッパーを起動してデータを読み取り、標準入力を介してPythonスクリプトに渡しました。Pythonスクリプトは3つのモジュールに分割されます。最初にUDFを前処理します。これは通常、文字列ベースの置換であり、通常は正規化されたデータとして使用されます。たとえば、一部の海外の協力メーカーの時間形式は、当社のものとは異なる場合があります。ここで団結します。前処理されたデータは、一般的な解析/変換モジュールに入ります。ここで、操作ログの形式に従ってデータを解析し、テストサーバーデータの除外などの一般的な変換を実行します。一般モジュールの後に、一般的な為替レート変換などのフィールド変換のための後処理モジュールが最後にあります。その後、データは標準出力を介してMapperに返され、MapperはデータをHiveディレクトリにバッチで書き込みます。

Flinkでリファクタリングした後、データソースがHDFSからKafkaに直接接続するように変更され、IOモジュールはFlinkのソース/シンク演算子を使用して元のマッパーを置き換えます。その後、中間の一般モジュールをJavaに直接書き換えることができます。残りの前処理と後処理は、PythonUDFをサポートする必要がある場所です。

PythonUDFの実装

特定の実装に関しては、Flink ProcessFunctionの上にRunnerレイヤーを追加し、Runnerレイヤーが言語間の実行を担当します。技術的な選択に関しては、Py4jの代わりにJythonが選択されました。これは主に、Jythonが追加のPythonプロセスを開始せずにJVMで直接計算を完了できるため、開発、運用、および保守管理のコストが比較的低いためです。パンダなどのcベースのライブラリをサポートしないなど、Jythonによってもたらされる制限は、PythonUDFで受け入れられます。

呼び出しチェーン全体では、TaskManagerが呼び出されたときに、ProcessFunctionがopen関数でのランナーの初期化を遅らせます。これは、Jythonがシリアル化できないためです。ランナーは、初期化時にリソースの準備を担当します。これには、依存モジュールをPYTHONPATHに追加したり、構成の反映に従ってUDF関数を呼び出したりすることが含まれます。

を呼び出すと、UDF Runnerは文字列を前処理のためにJythonのPyUnicodeタイプに変換し、後処理のためにUDFは解析されたMapオブジェクトをそれぞれ2つの入力としてJythonのPyDcitionaryに変換します。UDFは他のモジュールを呼び出して計算を実行し、最後にPyObjectを返すことができます。次に、RunnerはそれをJava StringまたはMapに変換し、ProcessFunctionに返して出力します。

運用ログETLランタイム

ちょうど今、UDFモジュールの部分的なビューです。全体的なETLジョブビューを見てみましょう。まず、一般的なFlink jarを提供します。ETLジョブを生成してジョブプラットフォームに送信すると、スケジューラーは一般的なmain関数を実行してFlinkJobGraphを構築します。この時点で、ETL構成は構成センターであるConfigServerから取得されます。ETL構成には使用済みのPythonモジュールが含まれており、バックエンドサービスは、その中で参照されている他のモジュールをスキャンし、YARN配布機能を介してリソースファイルとしてHDFSにアップロードします。Flink JobManagerとTaskManagerが起動すると、これらのPythonリソースは、バックアップのためにYARNによって作業ディレクトリに自動的に同期されます。これは、ジョブ全体を初期化するプロセスです。

また、フィールドの追加やフィルター条件の変更など、ETLルールの小さな変更は非常に頻繁に行われるため、変更するたびにジョブを再起動する必要がある場合、ジョブの再起動によって利用できない時間がダウンストリームユーザーと比較されます。 。悪い経験。したがって、変更を分類し、FlinkJobGraphに影響を与えないいくつかの軽量変更のホットアップデートをサポートします。これを実現する方法は、各TaskManagerがホットアップデートスレッドを開始し、定期的に同期構成について構成センターをポーリングすることです。

3. EntryX General ETL

次に、一般的なETLサービスであるEntryXを紹介します。ここでの一般的な目的は、2つの意味に分けることができます。1つは非構造化から構造化までのさまざまなテキストデータをサポートするデータ形式の一般的な目的であり、2つ目はユーザーグループの一般的な目的です。ターゲットユーザーは従来のユーザーを対象としています。データ分析やデータ開発など。そしてビジネス手順、弱いデータバックグラウンドを持つこれらのユーザーを計画します。

EntryXの基本概念

最初に、EntryX、Source、StreamingTable、およびSinkの3つの基本概念を紹介します。ユーザーはこれら3つのモジュールを個別に構成する必要があり、システムはこれらに基づいてETLジョブを自動的に生成します。

ソースはETLジョブの入力ソースであり、通常はビジネス側から収集された元のログトピック、または配布とフィルタリング後のトピックです。これらのトピックには1種類のログしか含まれない場合がありますが、多くの場合、複数の異種ログが含まれます。

次に、StreamingTable、より一般的な名前はStreamingTableです。フローテーブルは、データの変換方法など、ETLパイプラインの主要なメタデータと、変換されたデータに従って定義されたフローテーブルスキーマを定義し、データはスキーマ化されます。フローテーブルスキーマは最も重要な概念です。これは、主にフィールド名、フィールドデータ型、フィールド制約、およびテーブル属性を含むテーブルDDLと同等です。アップストリームとダウンストリームの接続を容易にするために、フローテーブルスキーマは自己開発のSQLのような型システムを使用します。これは、JSON型などの拡張データ型の一部をサポートします。

最後に、Sinkは、ターゲットHiveテーブルへのマッピングなど、ターゲットストレージの物理テーブルへのフローテーブルのマッピングを担当します。ここでは、フローテーブルのどのフィールドがターゲットテーブルのどのフィールドにマップされるか、フローテーブルのどのフィールドがターゲットHiveテーブルパーティションフィールドとして使用されるかなど、スキーママッピングの関係が主に必要です。最下層では、システムはスキーママッピング関係に基づいてフィールドを自動的に抽出し、データをターゲットテーブルのストレージ形式に変換して、ターゲットテーブルにロードします。

EntryXETLパイプライン

EntryXETLパイプラインの特定の実装を見てみましょう。青い部分は外部ストレージシステムで、緑の部分はEnrtyXの内部モジュールです。

データは、ドッキングによって収集された元のデータトピックから最初に流入し、ソースを介してフィルターに取り込まれます。フィルタは、キーワードに基づいてデータをフィルタリングする役割を果たします。一般的に、フィルタリングされたデータは同じスキーマを持っている必要があります。これらの2つのステップの後、抽出が完了し、変換段階になります。

変換の最初のステップは、データを解析することです。ここではパーサーです。パーサーは、JSON / Regex / Csvの3種類の解析をサポートしており、基本的にすべてのケースをカバーできます。2番目のステップは、データを変換することです。これはExtenderの責任です。Extenderは、組み込み関数またはUDFを介して派生フィールドを計算します。最も一般的な方法は、JSONオブジェクトをフラット化および拡張して、埋め込みフィールドを抽出することです。最後に、Formatter、Formatterは、ユーザーが以前に定義したフィールドの論理タイプに従って、フィールドの値を対応する物理タイプに変換します。たとえば、論理型がBIGINTのフィールドは、ここでは長い間、Javaの物理型に一律に変換されます。

データが変換を完了すると、最終的なロードフェーズになります。ロード最初のステップは、データをロードするテーブルを決定することです。Splitterモジュールは、各テーブルのストレージ条件(つまり、式)に従ってデータを分割し、2番目のステップでローダーに移動して、特定の外部ストレージシステムにデータを書き込みます。現在、Hive / Kafkaストレージをサポートし、HiveはText / Parquet / JSON 3つの形式をサポートし、KafkaはJSONとAvroの2つの形式をサポートしています。

リアルタイムのオフライン統合スキーマ

Entryxの設計では、データはリアルタイムとオフラインの両方のデータウェアハウスに書き込むことができます。つまり、同じデータが異なるストレージシステムで異なる形式で表現されます。Flink SQLの観点からは、スキーマ部分は同じですが、コネクタと形式が異なる2つのテーブルがあります。スキーマ部分はビジネスによって変わることが多く、コネクタとフォーマット(つまり、ストレージシステムとストレージフォーマット)は比較的安定しています。つまり、自然な考えは、スキーマ部分を個別に抽出して維持できるかということです。実際、この抽象スキーマはすでに存在します。これは、ETLで抽出したフローテーブルスキーマです。

EntryXでは、フローテーブルスキーマはシリアライザーやストレージシステムとは関係のないスキーマであり、信頼できる唯一の情報源として機能します。フローテーブルスキーマに加えて、ストレージシステム情報とストレージ形式情報に基づいて、特定の物理テーブルのDDLを導出できます。現在、主にHive / Kafkaをサポートしており、将来的にES / HBaseテーブルをサポートするように拡張したい場合に非常に便利です。

リアルタイムのデータウェアハウス統合

EntryXの重要な位置は、リアルタイム倉庫への統一された入り口として機能することです。実際、Kafkaテーブルについては今何度も言及されていますが、リアルタイムデータウェアハウスがどのように行われるかについては触れていません。リアルタイムデータウェアハウスの一般的な問題は、Kafkaがスキーマメタデータの永続性をネイティブにサポートしていないことです。コミュニティの現在の主流のソリューションは、Hive MetaStoreに基づいてKafkaテーブルのメタデータを保存し、HiveCatalogを再利用してFlinkSQLに直接接続することです。

しかし、私たちにとって、Hive MetaStoreの使用にはいくつかの主な問題があります。1つは、Hiveの依存関係を導入し、リアルタイム操作でHiveと結合することです。これは重い依存関係であり、定義されたテーブルを他のコンポーネントで再利用することが困難です。 、Flinkを含む。DataStreamユーザー。2つ目は、Avroスキーマなどの物理スキーマを管理するためのKafka SaaSプラットフォームアバターがすでにあることです。HiveMetaStoreが再び導入されると、メタデータの断片化が発生します。したがって、私たちはAvatarプラットフォームを拡張したスキーマレジストリであり、論理スキーマと物理スキーマの両方をサポートしています。

次に、リアルタイムデータウェアハウスとEntryXの統合関係は次のとおりです。まず、EntryXのフローテーブルスキーマがあり、新しいシンクを作成するときに、Avatarのスキーマインターフェイスを呼び出して、マッピング関係に従って論理スキーマを生成します。その場合、アバターはFlink SQLタイプと物理タイプのマッピングに基づいています。この関係により、トピックの物理スキーマが生成されます。

アバタースキーマ登録センターに加えて、自己開発のKafkaCatalogがあります。これは、トピックの論理および物理スキーマを読み取って、FlinkSQLのTableSourceまたはTableSinkを生成する役割を果たします。Flink DataStream APIのユーザーなど、Flink SQL以外の一部のユーザーは、物理スキーマを直接読み取って、データウェアハウスの利便性を享受することもできます。

EntryXランタイム

操作ログETLと同様に、EntryXの実行中、システムは一般的なjarと構成に基づいてFlinkジョブを生成しますが、特別な処理が必要な場合が2つあります。

1つ目は、Kafkaトピックには数十または数千のログがあることが多いため、実際には数十または数千のフローテーブルがあります。各フローテーブルが別々のジョブで実行される場合、トピックは数千回読み取られる可能性があります。非常に大きな無駄です。したがって、ジョブの実行時に最適化戦略が提供され、同じソースの異なるフローテーブルを1つのジョブにマージして実行できます。たとえば、写真では、モバイルゲームが3種類のログをKafkaにアップロードし、ユーザーがプレーヤー登録、プレーヤーログイン、ギフトパッケージの3つのフローテーブルをそれぞれ構成しました。次に、これら3つのフローテーブルを1つのジョブにマージして同じものを共有します。Kafkaソース。

もう1つの最適化は、通常の状況では、「抽出して1回変換し、1回ロードする」という以前のアイデアに従って、HiveとKafkaに同時にデータを書き込むことができるということですが、HiveまたはHDFSは結局オフラインシステムであるためです、リアルタイムのパフォーマンスは比較的劣ります。負荷の高い一部の古いHDFSクラスターでは、バックプレッシャが頻繁に発生すると同時に、アップストリームがブロックされます。これは、Kafkaの書き込みにも影響します。この場合、通常、ビジネスのSLAとHDFSのパフォーマンスに応じて、リアルタイムとオフラインにロードされたETLパイプラインを分離する必要があります。

4.チューニングの練習

次に、ETL構築におけるチューニングの実践経験を皆さんと共有します。

HDFS書き込みチューニング

1つ目は、HDFS書き込みの調整です。HDFSシーンのストリーミングでよくある問題は、小さなファイルが多すぎることです。一般的に、小さなファイルとリアルタイムのパフォーマンスを同時に達成することはできません。待ち時間を短くするには、ファイルを頻繁にスクロールしてデータを送信する必要があります。これにより、必然的に小さなファイルが多すぎます。

小さいファイルが多すぎると、主に2つの問題が発生します。1つは、HDFSクラスター管理の観点から、小さいファイルは多数のファイルとブロックを占有し、NameNodeのメモリを浪費します。2つ目は、ユーザーの観点から、書き込みにより読み取りと書き込みが減少しますRPCを呼び出してデータをフラッシュする頻度を増やす必要があるため、輻輳が発生し、チェックポイントタイムアウトが発生することもあります。読み取り時には、データを読み取るためにより多くのファイルを開く必要があります。

HDFS書き込みチューニング-データストリームの事前パーティション化

小さなファイルの問題を最適化するときに行った調整の1つのポイントは、データストリームの事前パーティション化を行うことです。具体的には、Flinkジョブ内のターゲットHiveテーブルに基づいてkeybyパーティションを実行し、同じテーブルが、いくつかのサブタスクに可能な限り集中しています。

たとえば、Flinkジョブの並列処理がnであり、ターゲットHiveパーティションの数がmであるとします。各サブタスクは任意のパーティションのデータを読み取る可能性があるため、デフォルトのサブタスクが完全に並列の場合、各サブタスクはすべてのパーティションに書き込み、書き込まれるファイルの総数はn * mになります。nが100、mが1000であるとすると、10分ごとにファイルをロールすると、毎日14,400,000個のファイルが生成されます。これは、多くの古いクラスターにとって非常にストレスがかかります。

データストリームのパーティショニングを最適化した後、Flinkの並列処理によってもたらされる成長を制限できます。たとえば、keyby hiveテーブルフィールドを追加し、データの偏りを回避するために0〜sの整数の範囲のソルトを追加すると、パーティションは最大でs個のサブタスクによって読み書きされます。元のnが100であるのに対し、sが5であるとすると、元のファイル数を20分の1に減らします。

OperatorStateに基づくSLA統計

次に共有したいのは、SLA統計ツールです。背景には、ユーザーがWeb UIを使用して、さまざまなサブタスクの入力と出力の数などの問題をデバッグおよびトラブルシューティングすることがよくありますが、これらのメトリックはジョブの再起動またはフェイルオーバーのためにリセットされるため、SLA-Utilsツールを開発しましたOperatorStateに基づく統計データの入力と分類の出力。このツールは非常に軽量になるように設計されており、独自のサービスやユーザーの宿題に簡単に統合できます。

SLA-Utilsでは、3つのメトリックをサポートしています。1つ目は、標準メトリックrecordsIn / recordsOut / recordsDropped / recordsErroredです。これは、入力レコードの数/通常の出力レコードの数/フィルターで除外されるレコードの数/例外を処理するレコードの数に対応します。一般的に、recordsInは後者の3つの合計に等しくなります。2番目のタイプのユーザー定義メトリックは、通常、より詳細な理由を記録するために使用されます。たとえば、recordsEventTimeDroppedは、イベント時間のためにデータがフィルター処理されることを意味します。

その場合、上記の2つのメトリックは静的です。つまり、ジョブを実行する前にメトリックキーを決定する必要があります。さらに、SLA-Utilsは、実行時に動的に登録されるTTLメトリックもサポートします。この種のメトリックは通常、動的に生成された日付をプレフィックスとして持ち、TTL時間が経過すると自動的にクリーンアップされます。TTLメトリックは、主に日レベルの時間枠の統計を作成するために使用できます。ここでの特別なポイントは、OperatorStateがTTLをサポートしていないため、チェックポイントスナップショットが取得されるたびにSLA-Utilsがフィルター処理を行い、期限切れのメトリックを削除してTTLの効果を実現することです。

次に、StateがSLAインジケーターを保存した後、ユーザーに公開する必要があります。現在のアプローチは、Accumulaterを介して公開することです。利点は、Web UIがサポートされており、すぐに使用できることです。同時に、Flinkはさまざまなサブタスクのメトリックを自動的にマージできます。欠点は、メトリックレポーターを使用して監視システムにプッシュする方法がないことです。同時に、Acuumulaterは実行時に動的にログアウトできないため、TTLメトリックを使用するとメモリリークが発生するリスクがあります。したがって、将来的には、これらの問題を回避するためにメトリックグループをサポートすることも検討します。

データのフォールトトレランスとリカバリ

最後に、データのフォールトトレランスとリカバリに関するプラクティスを共有します。

多くのベストプラクティスと同様に、SideOutputを使用して、ETLの各リンクでエラーデータを収集し、それを統合されたエラーストリームに要約します。エラーレコードには、事前設定されたエラーコード、元の入力データ、エラーカテゴリ、およびエラー情報が含まれています。一般に、間違ったデータは分類されてHDFSに書き込まれ、ユーザーはHDFSディレクトリを監視することでデータが正常であるかどうかを知ることができます。

異常なデータを保存した後、次のステップはデータを復元することです。通常、2つの状況があります。

まず、データ形式が異常です。たとえば、ログが切り捨てられ、タイムスタンプが合意された形式に準拠していません。この場合、通常、オフラインバッチジョブを介してデータを修復し、元のデータパイプラインを補充します。

次に、ETLパイプラインが異常です。たとえば、データの実際のスキーマは変更されますが、フローテーブルの構成が更新されないため、フィールドが空になる可能性があります。現時点での解決策は、最初にオンラインフローを更新することです。テーブル構成を最新のものにします。異常なデータが生成されないことが保証されます。現時点では、Hiveにはまだ異常なパーティションがいくつかあります。次に、独立した補完ジョブを発行して異常データを修復し、出力データを一時ディレクトリに書き込み、ハイブメタストア上のパーティションの場所を切り替えて元の異常ディレクトリを置き換えます。したがって、このような補完プロセスは、オフラインでクエリを実行するユーザーに対して透過的です。最後に、異常なパーティションデータを適切なタイミングで置き換え、場所を復元します。

V.将来の計画

最後に、今後の計画をご紹介します。

  • 1つ目は、データレイクのサポートです。現在、ほとんどのログは追加タイプですが、CDCおよびFlink SQLビジネスの改善により、更新および削除の要件が増える可能性があるため、データレイクが適しています。
  • 2つ目は、リアルタイムのデータ重複排除や小さなファイルの自動マージなど、より豊富な追加機能を提供します。これらは両方とも、ビジネス側にとって非常に便利な機能です。
  • 最後のものはPyFlinkをサポートします。現在、Pythonサポートはデータ統合段階のみを対象としており、PyFlinkを介して後続のデータウェアハウスのPythonサポートを実装したいと考えています。

元のリンク

この記事はAlibabaCloudのオリジナルのコンテンツであり、許可なく複製することはできません。

おすすめ

転載: blog.csdn.net/weixin_43970890/article/details/114924705