第1章;序章
前回の記事では、Flink関連環境の準備を紹介し、簡単なFlink開発環境の確立を完了しました。この記事では、Flinkコンピューティングをカバーする完全なエンドツーエンドのケースを紹介します:client => Web API service = > Kafka => Flink => MySQL。今回も例としてFlinkTable API / SQLを取り上げ、docker-composeにデプロイします。(コードの重要な部分のみが記事に記載されています。完全なコードについては、作成者がアップロードしたフォローアップgithubを参照してください)。
第2章docker-compose
2.1docker-compose.ymlファイルを追加します
version: '2'
services:
jobmanager:
image: zihaodeng/flink:1.11.1
volumes:
- D:/21docker/flinkDeploy:/opt/flinkDeploy
hostname: "jobmanager"
expose:
- "6123"
ports:
- "4000:4000"
command: jobmanager
environment:
- JOB_MANAGER_RPC_ADDRESS=jobmanager
taskmanager:
image: zihaodeng/flink:1.11.1
volumes:
- D:/21docker/flinkDeploy:/opt/flinkDeploy
expose:
- "6121"
- "6122"
depends_on:
- jobmanager
command: taskmanager
links:
- jobmanager:jobmanager
environment:
- JOB_MANAGER_RPC_ADDRESS=jobmanager
zookeeper:
container_name: zookeeper
image: zookeeper:3.6.1
ports:
- "2181:2181"
kafka:
container_name: kafka
image: wurstmeister/kafka:2.12-2.5.0
volumes:
- D:/21docker/var/run/docker.sock:/var/run/docker.sock
ports:
- "9092:9092"
depends_on:
- zookeeper
environment:
#KAFKA_ADVERTISED_HOST_NAME: kafka
HOSTNAME_COMMAND: "route -n | awk '/UG[ \t]/{print $$2}'"
KAFKA_CREATE_TOPICS: "order-log:1:1"
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
#KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092
#KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
mysql:
image: mysql:5.7
container_name: mysql
volumes:
- D:/21docker/mysql/data/db:/var/lib/mysql/
- D:/21docker/mysql/mysql-3346.sock:/var/run/mysql.sock
- D:/21docker/mysql/data/conf:/etc/mysql/conf.d
ports:
- 3306:3306
command:
--default-authentication-plugin=mysql_native_password
--lower_case_table_names=1
environment:
MYSQL_ROOT_PASSWORD: 123456
TZ: Asia/Shanghai
2.2docker-作成開始
$ docker-compose up -d
動作確認
このセクションでは、docker-composeの準備ができており、後で作業環境を開始すると非常に便利です。次に、対応するプログラムの準備を開始します。
第3章WebApiプロジェクトの作成
3.1 WebApi(Restful API)インターフェイスプロジェクトを作成する
springbootを使用してAPIプロジェクトをすばやく構築します。ここでの作成者はRestfulApiインターフェイス形式を使用しています。コードの一部は次のとおりです(完全なコードについては、作成者のgithubを参照してください)。
クライアントが呼び出すための投稿インターフェイスを作成します
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private Sender sender;
@PostMapping
public String insertOrder(@RequestBody Order order) {
sender.producerKafka(order);
return "{\"code\":0,\"message\":\"insert success\"}";
}
}
Senderクラスを作成し、Kafkaにデータを送信します
public class Sender {
@Autowired
private KafkaTemplate<String,String> kafkaTemplate;
private static Random rand = new Random();
public void producerKafka(Order order){
order.setPayTime(String.valueOf(new Timestamp(System.currentTimeMillis()+ rand.nextInt(100))));//EventTime
kafkaTemplate.send("order-log", JSON.toJSONString(order));
}
}
第4章Flinkジョブの作成
ここでは、Flink Table API / SQLを使用してタンブルウィンドウ計算を実装しています。Kafkaで読み取られたデータは、ウィンドウ計算によって要約され、MySQLに書き込まれます。
public class Kafka2MysqlByEnd2End {
public static void main(String[] args) throws Exception {
// Kafka source
String sourceSQL="CREATE TABLE order_source (\n" +
" payTime VARCHAR,\n" +
" rt as TO_TIMESTAMP(payTime),\n" +
" orderId BIGINT,\n" +
" goodsId INT,\n" +
" userId INT,\n" +
" amount DECIMAL(23,10),\n" +
" address VARCHAR,\n" +
" WATERMARK FOR rt as rt - INTERVAL '2' SECOND\n" +
" ) WITH (\n" +
" 'connector' = 'kafka-0.11',\n" +
" 'topic'='order-log',\n" +
" 'properties.bootstrap.servers'='kafka:9092',\n" +
" 'format' = 'json',\n" +
" 'scan.startup.mode' = 'latest-offset'\n" +
")";
//Mysql sink
String sinkSQL="CREATE TABLE order_sink (\n" +
" goodsId BIGINT,\n" +
" goodsName VARCHAR,\n" +
" amount DECIMAL(23,10),\n" +
" rowtime TIMESTAMP(3),\n" +
" PRIMARY KEY (goodsId) NOT ENFORCED\n" +
" ) WITH (\n" +
" 'connector' = 'jdbc',\n" +
" 'url' = 'jdbc:mysql://mysql:3306/flinkdb?characterEncoding=utf-8&useSSL=false',\n" +
" 'table-name' = 'good_sale',\n" +
" 'username' = 'root',\n" +
" 'password' = '123456',\n" +
" 'sink.buffer-flush.max-rows' = '1',\n" +
" 'sink.buffer-flush.interval' = '1s'\n" +
")";
// 创建执行环境
EnvironmentSettings settings = EnvironmentSettings
.newInstance()
.useBlinkPlanner()
.inStreamingMode()
.build();
//TableEnvironment tEnv = TableEnvironment.create(settings);
StreamExecutionEnvironment sEnv = StreamExecutionEnvironment.getExecutionEnvironment();
//sEnv.setRestartStrategy(RestartStrategies.fixedDelayRestart(3, Time.of(1, TimeUnit.SECONDS)));
//sEnv.enableCheckpointing(1000);
//sEnv.setStateBackend(new FsStateBackend("file:///tmp/chkdir",false));
StreamTableEnvironment tEnv= StreamTableEnvironment.create(sEnv,settings);
Configuration configuration = tEnv.getConfig().getConfiguration();
//设置并行度为1
configuration.set(CoreOptions.DEFAULT_PARALLELISM, 1);
//注册souuce
tEnv.executeSql(sourceSQL);
//注册sink
tEnv.executeSql(sinkSQL);
//UDF 在作业中定义UDF
tEnv.createFunction("exchangeGoods", ExchangeGoodsName.class);
String strSQL=" SELECT " +
" goodsId," +
" exchangeGoods(goodsId) as goodsName, " +
" sum(amount) as amount, " +
" tumble_start(rt, interval '5' seconds) as rowtime " +
" FROM order_source " +
" GROUP BY tumble(rt, interval '5' seconds),goodsId";
//查询数据 插入数据
tEnv.sqlQuery(strSQL).executeInsert("order_sink");
//执行作业
tEnv.execute("统计各商品营业额");
}
}
第5章MySQLデータベーステーブルの作成
5.1ライブラリを構築する
mysql> create database flinkdb;
5.2テーブルを作成する
mysql> create table good_sale(goodsId bigint primary key, goodsName varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci, amount decimal(23,10), rowtime timestamp);
注:プライマリキーは、flinkジョブddlで定義されたプライマリキーと同じです。プライマリキーはflink ddlで定義され、コネクタはアップサートモードです(Flinkは、プライマリキーに従って新しい行を挿入するか、既存の行を更新するかを決定して、同一性を確保します)。定義は追加モードです(挿入モードを挿入します。主キーが競合すると、挿入は失敗します)。
この時点で、環境とコードが準備され、検証の実行が開始されます。
第6章ジョブの実行
6.1ローカルデバッグ検証
6.1.1クラスターを開始します
第2章の方法を使用して、準備したクラスター環境を開始します。
$ docker-compose up -d
6.1.2ジョブを開始する
ローカルIDEAでWebApiプロジェクトとFlinkジョブプロジェクトを開始します。
6.1.3リクエストを開始する
ここでは、httpツールを使用して、クライアントをシミュレートして要求を開始し、json形式でデータを送信します。
6.1.4flinkジョブの実行ステータスを表示する
IDEAコンソールでログを直接表示する
6.1.5結果の表示
MySQLで結果を表示する
このステップでは、ローカルIDEによってデバッグされたジョブがソースからデータを正常にプルし、flinkによる計算後、データがMySQLに書き込まれていることがわかります。次に、実行するクラスターへのジョブの送信を完了します。
6.2クラスター動作の検証
6.2.1パッケージング
WebAPIプロジェクトjarパッケージのパッケージ化
lotemall-webapi(作成者のWebApiプロジェクト)ディレクトリに移動して、パッケージ化コマンドを実行します
mvn clean package -DskipTests
Dockerfileを準備し、jarパッケージと同じディレクトリに配置します。次のコマンドを実行してイメージを作成します。
$ docker build -t lotemall-webapi .
Flinkジョブjarパッケージをパッケージ化します
flink-kafka2mysql(作成者のFlinkジョブプロジェクト)ディレクトリに移動して、パッケージ化コマンドを実行します
使用するためにコンテナに送信するため、ソースおよびシンク接続の構成IPを元のlocalhostからコンテナ名に変更する必要があることに注意してください
mvn clean package -DskipTests
パッケージ化されたjarパッケージをdockerのマウントディレクトリに配置します
6.2.2クラスターを開始します
第2章の方法を使用して、準備したクラスター環境を開始します。
$ docker-compose up -d
6.2.3WebAPIプロジェクトを開始します
dockerrunコマンドを実行してWebAPIプロジェクトを開始します
$ docker run --link kafka:kafka --net flink-online_default -e TZ=Asia/Shanghai -d -p 8090:8080 lotemall-webapi
6.2.4Flinkジョブの実行
flink jobmanagerコンテナに入り、ジョブを実行します
$ docker exec -it flink-online_jobmanager_1 /bin/bash
$ bin/flink run -c sql.Kafka2MysqlByEnd2End /opt/flinkDeploy/flink-kafka2mysql-0.0.1.jar -d
または、Webインターフェイスを介してジョブjarパッケージを送信します
ジョブが送信されたら、Flink Webインターフェイスを確認してください。送信したジョブが、実行を開始したことがわかります。
6.2.5リクエストを開始する
また、httpツールを使用してクライアントをシミュレートし、要求を開始してjson形式でデータを送信します。
6.2.6Flinkジョブの実行ステータスを表示する
実行するクラスターに送信すると、FlinkWebインターフェイスでジョブの実行ステータスを直接表示できます。
生成されたウォーターマークを表示する
6.2.7結果の表示
MySQLで結果を表示する
最初の行のgoodsNameが「cake」であるレコードは、このクラスターでのFlink計算の結果です。
要約すると、この記事では、docker-composeを使用したクラスターの便利な展開を紹介し、完全なFlinkストリームコンピューティングのケースを完了します。