テクニカル乾物|ChunJunを使ってオフラインデータ同期を実現するには?

ChunJun は、安定した、使いやすい、高効率のバッチフロー統合データ統合フレームワークであり、コンピューティング エンジン Flink に基づいて、複数の異種データ ソース間のデータ同期とコンピューティングを実現します。ChunJun は、さまざまなソース、形式、特性からのデータを論理的または物理的に一元化し、企業に包括的なデータ共有を提供することができ、数千の企業に導入され、安定して稼働しています。

以前、 ChunJun を使用してリアルタイムのデータ同期を実現する方法(クリックすると本文が表示されます) を紹介しましたが、この記事では関連記事、ChunJun を使用してオフライン データ同期を実現する方法を紹介します。

ChunJunオフライン同期事例

オフライン同期は ChunJun の重要な機能です。以下では、最も一般的な mysql -> hive 同期タスクを使用して、オフライン同期を導入しています。

構成環境

空のディレクトリを見つけて、Flink と ChunJun の環境を設定します (例として /root/chunjun_demo/ を使用します)。

● フリンクの設定

フリンクをダウンロード

wget "http://archive.apache.org/dist/flink/flink-1.12.7/flink-1.12.7-bin-scala_2.12.tgz"
tar -zxvf chunjun-dist.tar.gz

● ChunJun を設定する

#下载 chunjun, 内部依赖 flink 1.12.7
wget https://github.com/DTStack/chunjun/releases/download/v1.12.8/chunjun-dist-1.12-SNAPSHOT.tar.gz
#新创建⼀个⽬录
mkdir chunjun && cd chunjun
#解压到指定⽬录
tar -zxvf chunjun-dist-1.12-SNAPSHOT.tar.gz

解凍された ChunJun には次のディレクトリがあります: bin chunjun-dist chunjun-examples lib

● 環境変数を構成する

#配置 Flink 环境变量
echo "FLINK_HOME=/root/chunjun_demo/flink-1.12.7" >> /etc/profile.d/sh.local
#配置 Chunjun 的环境变量
echo "CHUNJUN_DIST=/root/chunjun_demo/chunjun/chunjun-dist" >> /etc/profile.d/sh.local
#刷新换新变量
. /etc/profile.d/sh.local

● Yarn で Flink セッションを開始する

#启动 Flink Session
bash $FLINK_HOME/bin/yarn-session.sh -t $CHUNJUN_DIST -d

出力は次のとおりです。

echo "stop" | $FLINK_HOME/bin/yarn-session.sh -id application_1683599622970_0270
If this should not be possible, then you can also kill Flink via YARN's web interface or via:
yarn application -kill application_1683599622970_0270

Flink セッションの Yarn アプリケーション ID (application_1683599622970_0270) は、以下のタスクを送信するために使用されます。

●その他の構成

Parquet 形式を使用する場合は、flink-parquet_2.12-1.12.7.jar を flink/lib に配置する必要があります (上記の例では $FLINK_HOME/lib に配置する必要があります)。

ファイル

タスクを送信する

● MySQL でデータを準備する

-- 创建⼀个名为ecommerce_db的数据库,⽤于存储电商⽹站的数据
CREATE DATABASE IF NOT EXISTS chunjun;
USE chunjun;
-- 创建⼀个名为orders的表,⽤于存储订单信息
CREATE TABLE IF NOT EXISTS orders (
 id INT AUTO_INCREMENT PRIMARY KEY, -- ⾃增主键
 order_id VARCHAR(50) NOT NULL, -- 订单编号,不能为空
 user_id INT NOT NULL, -- ⽤户ID,不能为空
 product_id INT NOT NULL, -- 产品ID,不能为空
 quantity INT NOT NULL, -- 订购数量,不能为空
 order_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-- 订单⽇期,默认值为当前时间戳,不能为空
);
-- 插⼊⼀些测试数据到orders表
INSERT INTO orders (order_id, user_id, product_id, quantity)
VALUES ('ORD123', 1, 101, 2),
       ('ORD124', 2, 102, 1),
       ('ORD125', 3, 103, 3),  
       ('ORD126', 1, 104, 1),
       ('ORD127', 2, 105, 5);
       
select * from chunjun.orders;       

MySQL がない場合は、docker を使用してすぐに作成できます。

docker pull mysql:8.0.12
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0.12

● Hive テーブルを作成する

CREATE DATABASE IF NOT EXISTS chunjun;
USE chunjun;
-- 创建⼀个名为orders的表,⽤于存储订单信息
CREATE TABLE IF NOT EXISTS chunjun.orders (
 id INT,
 order_id VARCHAR(50),
 user_id INT,
 product_id INT,
 quantity INT,
 order_date TIMESTAMP
)
 STORED AS PARQUET;
-- 查看 hive 表,底层的 HDFS ⽂件位置,下⾯的 SQL 结果⾥⾯ Location 字段,就是 HDFS ⽂件的位置。
desc formatted chunjun.orders;
-- Location: hdfs://ns1/dtInsight/hive/warehouse/chunjun.db/orders
-- ⼀会配置同步任务的时候会⽤到 hdfs://ns1/dtInsight/hive/warehouse/chunjun.db/orders

● 現在のディレクトリ ( /root/chunjun_demo/ ) にタスク mysql_hdfs.json を設定します。

vim mysql_hdfs.json に次の内容を入力します。

{
"job": {
"content": [
 {
"reader": {
"parameter": {
"connection": [
 {
"schema": "chunjun",
"jdbcUrl": [ "jdbc:mysql://172.16.85.200:3306/chunjun" ],
"table": [ "orders" ]
 }
 ],
"username": "root",
"password": "123456",
"column": [
 { "name": "id", "type": "INT" },
 { "name": "order_id", "type": "VARCHAR" },
 { "name": "user_id", "type": "INT" },
 { "name": "product_id", "type": "INT" },
 { "name": "quantity", "type": "INT" },
 { "name": "order_date", "type": "TIMESTAMP" }
 ]
 },
"name": "mysqlreader"
 },
"writer": {
"parameter": {
"path": "hdfs://ns1/dtInsight/hive/warehouse/chunjun.db/orders",
"defaultFS": "hdfs://ns1",
"hadoopConfig": {
"dfs.nameservices": "ns1",
"dfs.ha.namenodes.ns1": "nn1,nn2",
"dfs.namenode.rpc-address.ns1.nn1": "172.16.85.194:9000",
"dfs.namenode.rpc-address.ns1.nn2": "172.16.85.200:9000",
"dfs.client.failover.proxy.provider.ns1":
"org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider"
 },
"column": [
 { "name": "id", "type": "INT" },
 { "name": "order_id", "type": "VARCHAR" },
 { "name": "user_id", "type": "INT" },
 { "name": "product_id", "type": "INT" },
 { "name": "quantity", "type": "INT" },
 { "name": "order_date", "type": "TIMESTAMP" }
 ],
"writeMode": "overwrite",
"encoding": "utf-8",
"fileType": "parquet",
"fullColumnName":
 [ "id", "order_id", "user_id", "product_id", "quantity", "order_date"],
"fullColumnType":
 [ "INT", "VARCHAR", "INT", "INT", "INT", "TIMESTAMP" ]
 },
"name": "hdfswriter"
 }
 }
 ],
"setting": {
"errorLimit": {
"record": 0
 },
"speed": {
"bytes": 0,
"channel": 1
 }
 }
 }
}

MySQL を Hive に同期したいのですが、Hive を直接同期すると内部で jdbc が使用されてしまい、jdbc の効率が高くないため、Hive の基盤となる HDFS にデータを直接同期できるため、ライターは hdfswriter を使用します。スクリプトは次のように解析されます。

{
"job": {
"content": [
 {
"reader": {
"parameter": {
"connectionComment": "数据库链接, 数据库, 表, 账号, 密码",
"connection": [
 {
"schema": "chunjun",
"jdbcUrl": [ "jdbc:mysql://172.16.85.200:3306/chunjun" ],
"table": [ "orders" ]
 }
 ],
"username": "root",
"password": "123456",
"columnComment": "要同步的列选择, 可以选择部分列",
"column": [
 { "name": "id", "type": "INT" },
 { "name": "order_id", "type": "VARCHAR" },
 { "name": "user_id", "type": "INT" },
 { "name": "product_id", "type": "INT" },
 { "name": "quantity", "type": "INT" },
 { "name": "order_date", "type": "TIMESTAMP" }
 ]
 },
"nameComment" : "source 是 mysql",
"name": "mysqlreader"
 },
"writer": {
"parameter": {
"pathComment": "HDFS 上⾯的路径, 通过 hive 语句的 desc formatted 查看",
"path": "hdfs://ns1/dtInsight/hive/warehouse/chunjun.db/orders",
"defaultFS": "hdfs://ns1",
"hadoopConfigComment": "是 hdfs ⾼可⽤最基本的配置, 在 Hadoop 配置⽂件 hdfs-site.xml 可以找到",
"hadoopConfig": {
"dfs.nameservices": "ns1",
"dfs.ha.namenodes.ns1": "nn1,nn2",
"dfs.namenode.rpc-address.ns1.nn1": "172.16.85.194:9000",
"dfs.namenode.rpc-address.ns1.nn2": "172.16.85.200:9000",
"dfs.client.failover.proxy.provider.ns1":
"org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider"
 },
"columnComment": "要同步的列选择, 可以选择部分列",
"column": [
 { "name": "id", "type": "INT" },
 { "name": "order_id", "type": "VARCHAR" },
 { "name": "user_id", "type": "INT" },
 { "name": "product_id", "type": "INT" },
 { "name": "quantity", "type": "INT" },
 { "name": "order_date", "type": "TIMESTAMP" }
 ],
"writeModeComment": "覆盖写⼊到 hdfs 上⾯的⽂件, 可选 overwrite, append(默认模式)",
"writeMode": "overwrite",
"encoding": "utf-8",
"fileTypeComment": "可选 orc, parquet, text",
"fileType": "parquet",
"fullColumnNameComment": "全部字段,有时候 column ⾥⾯同步部分字段,但是⼜需要有全部字段的格式,例如 fileType : text ",
"fullColumnName": [ "id", "order_id", "user_id", "product_id", "quantity", "order_date"], 
"fullColumnTypeComment": "全部字段的类型",
"fullColumnType": [ "INT", "VARCHAR", "INT", "INT", "INT", "TIMESTAMP" ]
 },
"nameComment" : "sink 是 hdfs",
"name": "hdfswriter"
 }
 }
 ],
"setting": {
"errorLimit": {
"record": 0
 },
"speed": {
"bytes": 0,
"channel": 1
 }
 }
 }
}

● タスクを送信する

bash chunjun/bin/chunjun-yarn-session.sh -job mysql_hdfs.json -confProp
{\"yarn.application.id\":\"application_1683599622970_0270\"}

● タスクの表示

ファイル ファイル

タスクの同期が完了すると、HDFS 上のデータを確認できるようになります。

ファイル

Hive テーブルのデータを見てください。

ファイル

パーティション分割された Hive テーブルの場合は、MSCK コマンドを使用して Hive メタデータを手動で更新する必要があることに注意してください。(MSCK は、テーブル内のパーティションをチェックし、それらを Hive メタデータに追加する Hive のコマンドです)

MSCK REPAIR TABLE my_table;

ChunJun オフライン同期原理の分析

HDFS ファイル同期原理

· ファイル システムの場合、同期時にファイルはパス + [ファイル名] ディレクトリにある .data ファイルに書き込まれます。タスクが失敗した場合、.data 内のファイルは生成されません。

· TaskManager 上のすべてのタスクが完了すると、FinalizeOnMaster の FinalizeGlobal メソッドが JobManager 上で実行され、最後に moveAllTmpDataFileToDir が呼び出され、.data 内のファイルが .data の上位レベルに削除されます。

パブリック インターフェイス FinalizeOnMaster {

/**
The method is invoked on the master (JobManager) after all (parallel) instances of an OutputFormat finished.
Params:parallelism – The parallelism with which the format or functions was run.
Throws:IOException – The finalization may throw exceptions, which may cause the job to abort.
*/
void finalizeGlobal(int parallelism) throws IOException; 
}
// 在 JobManager 执⾏
@Override
protected void moveAllTmpDataFileToDir() {
if (fs == null) {
openSource();
 }
String currentFilePath = "";
try {
Path dir = new Path(outputFilePath);
Path tmpDir = new Path(tmpPath);

FileStatus[] dataFiles = fs.listStatus(tmpDir);
for (FileStatus dataFile : dataFiles) {
currentFilePath = dataFile.getPath().getName();
fs.rename(dataFile.getPath(), dir);
LOG.info("move temp file:{} to dir:{}", dataFile.getPath(), dir);
 }
fs.delete(tmpDir, true);
 } catch (IOException e) {
throw new ChunJunRuntimeException(
String.format(
"can't move file:[%s] to dir:[%s]", currentFilePath, outputFilePath),
e);
 }
}

増分同期

増分同期は主に、挿入操作のみを行う特定のテーブルに対して行われます。ビジネスが成長するにつれて、テーブル内のデータは増加します。テーブル全体が毎回同期されると、より多くの時間とリソースが消費されます。したがって、インクリメンタル同期機能が必要となり、毎回データの増加部分のみが読み取られます。

●実施原則

実際の実装の原理は、クエリの SQL ステートメント内のフィルター条件を、where id > ? などのインクリメント キーと結合して、以前に読み取られたデータをフィルターで除外することです。

増分同期は、2 つ以上の同期ジョブを対象とします。初めて増分同期を実行するジョブでは、実際にはテーブル全体が同期されます。他のジョブと異なるのは、増分同期ジョブはジョブの実行後に endLocation インジケーターを記録し、このインジケーターを prometheus にアップロードしてさらに実行することです。その後の使用のために。

最初のジョブを除き、後続のすべての増分同期ジョブは、前のジョブの endLocation をこのジョブのフィルター基準 (startLocation) として使用します。たとえば、最初のジョブが実行され、endLocation が 10 になった後、次のジョブは、増分読み取りの目的を達成するために、id > 10 のテーブルから SELECT id,name,age などの SQL ステートメントを構築します。

●使用制限について

・RDB Readerプラグインのみ使用可能

SQL フィルター ステートメントを構築することによって実装されるため、RDB プラグインにのみ使用できます

· 増分同期は書き込みではなく読み取りのみを考慮するため、Reader プラグインにのみ関連します

· 増分フィールドには数値型と時間型のみを使用できます

· インジケーターは prometheus にアップロードする必要があります。prometheus は文字列型をサポートしていないため、データ型と時刻型のみがサポートされます。時刻型はタイムスタンプに変換されてアップロードされます。

· インクリメントキー値は繰り返すことができますが、インクリメントする必要があります

· 「>」を使用しているため、必須フィールドをインクリメントする必要があります

http

ブレークポイント再開はオフライン同期用です。1 日以上の長期同期タスクの場合、同期プロセス中に何らかの理由でタスクが失敗した場合、最初から開始すると非常にコストがかかります。そのため、ブレークポイント再開は渡された関数は、タスクが失敗したところから続行されます。

●実施原則

· Flink のチェックポイントに基づいて、ソース側の最後のデータの特定のフィールド値がチェックポイント中に保存され、シンク側プラグインがトランザクションの送信を実行します。

· タスクが失敗し、その後チェックポイントを通じて再実行されると、ソース側は、最後の障害点から回復するために、select ステートメントの生成時にデータをフィルターするための条件として状態の値を使用します。

ファイル· jdbcInputFormat が SQL を結合して読み取るときに、チェックポイントから復元された状態が空でなく、restoreColumn も空でない場合は、チェックポイントの状態がデータの読み取りを開始する開始点として使用されます。

● 適用可能なシナリオ

上記の原理により、ブレークポイント再開を実現するために select ステートメントを where 条件で結合することによってデータ フィルタリングが実現されるため、ソース エンドが RDB タイプのプラグインである必要があることがわかります。フィルタ条件としてフィールドを指定する必要があり、このフィールドの要件は増分です。

· タスクはチェックポイントを有効にする必要があります

リーダーはすべての RDB プラグインでサポートされるプラグインであり、ライターはトランザクション (rdb ファイルシステムなど) をサポートします。ダウンストリームが冪等である場合、ライター プラグインはトランザクションをサポートする必要はありません

· フィルター条件が > であるため、ブレークポイントとして再開されるフィールドのソース テーブル内のデータは増分です。

「Dutstack 製品ホワイトペーパー」: https://www.dtstack.com/resources/1004?src=szsm

「データ ガバナンス業界実践ホワイト ペーパー」ダウンロード アドレス: https://www.dtstack.com/resources/1001?src=szsm Kangaroo Cloud のビッグデータ製品、業界ソリューション、顧客事例について詳しく知りたい、相談したい場合は、 Kangaroo Cloud 公式 Web サイトにアクセスしてください: https://www.dtstack.com/?src=szkyzg

同時に、ビッグデータのオープンソース プロジェクトに興味のある学生は、最新のオープンソース テクノロジー情報を交換するために「Kangaroo Cloud Open Source Framework DingTalk Technology qun」に参加することを歓迎します。qun 番号: 30537511、プロジェクト アドレス: https: // github.com/DTStack

{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/3869098/blog/8817162