Flink DataStream API, karmaşık iş mantığını ve veri işlemeyi yönetmek üzere özel veri dönüşümleri, işlemler ve operatörler oluşturmak için esnek bir programlama modeli sunar.
Apache Flink uyumluluğu
Realtime Compute for Apache Flink tarafından desteklenen DataStream API, açık kaynaklı Apache Flink sürümüyle tam uyumludur. Daha fazla bilgi için bkz. Apache Flink Nedir? ve Flink DataStream API Programlama Kılavuzu.
Önkoşullar
IntelliJ IDEA gibi bir entegre geliştirme ortamı (IDE) yüklüdür.
Maven 3.6.3 veya sonraki bir sürüm yüklüdür.
İş geliştirme yalnızca JDK 8 ve JDK 11'i destekler.
JAR işinizi Realtime Compute for Apache Flink konsolunda dağıtıp çalıştırmadan önce yerel ortamınızda geliştirin.
Başlamadan önce
Bu örnekte veri kaynağı konnektörleri kullanıldığından gerekli veri kaynaklarını önceden hazırlayın.
Bu örnekte veri kaynağı olarak ApsaraMQ for Kafka (2.6.2) ve ApsaraDB RDS for MySQL (8,0) kullanılır.
Genel ağ erişimi veya VPC'ler arası erişim gerektiren kendi yönetimindeki veri kaynaklarınız varsa bkz. Ağ bağlantısı seçenekleri.
Bir ApsaraMQ for Kafka veri kaynağınız yoksa bir örnek satın alıp dağıtın. Daha fazla bilgi için bkz. Adım 2: Örnek satın alma ve dağıtma. Örneği dağıtırken Realtime Compute for Apache Flink çalışma alanınızla aynı VPC içinde olduğundan emin olun.
Bir ApsaraDB RDS for MySQL veri kaynağınız yoksa bir ApsaraDB RDS for MySQL örneği satın alın. Daha fazla bilgi için bkz. Adım 1: ApsaraDB RDS for MySQL örneği oluşturma ve veritabanı yapılandırma. Örneği satın alırken Realtime Compute for Apache Flink çalışma alanınızla aynı bölge ve VPC içinde olduğundan emin olun.
İşi geliştirme
Flink ortam bağımlılıklarını yapılandırma
JAR bağımlılık çakışmalarını önlemek için aşağıdaki yönergeleri izleyin:
${flink.version}parametresi işin çalıştırılacağı Flink sürümünü belirtir. Bu sürüm, iş dağıtım sayfasında seçtiğiniz VVR motorunun Flink sürümüyle tutarlı olmalıdır. Örneğin, iş dağıtım sayfasındavvr-8.0.9-flink-1.17motorunu seçerseniz karşılık gelen Flink sürümü1.17.2olur. VVR motor sürümleri hakkında daha fazla bilgi için bkz. Geçerli işin Flink sürümünü nasıl kontrol ederim?.Flink bağımlılıkları için
<scope>provided</scope>ekleyerek kapsamıprovidedolarak ayarlayın. Bunlar çoğunluklaorg.apache.flinkgrubunda yer alan veflink-ile başlayan konnektör dışı bağımlılıklardır.Flink kaynak kodunda yalnızca @Public veya @PublicEvolving ile açıkça işaretlenmiş yöntemler genel API'lerdir. Realtime Compute for Apache Flink yalnızca bu yöntemler için uyumluluk garantisi verir.
Yerleşik bir Flink konnektörünün DataStream API'sini kullanıyorsanız provided bağımlılıklarını kullanın.
Aşağıda temel Flink bağımlılıkları listelenmiştir. Günlük kaydı bağımlılıklarını da eklemeniz gerekebilir. Tam bağımlılık listesi için bu konunun sonundaki Tam kod örneği bölümüne bakın.
Konnektör bağımlılıkları ve kullanımı
DataStream API ile veri okumak ve yazmak için Realtime Compute for Apache Flink'e bağlanacak bir DataStream konnektörü kullanın. Maven Merkezi Deposu, geliştirme sırasında kullanabileceğiniz VVR DataStream konnektörlerini sağlar.
Yalnızca Desteklenen konnektörler bölümünde DataStream API'yi desteklediği belirtilen konnektörleri kullanın. Arayüzleri ve parametreleri gelecekte değişebileceğinden DataStream API desteği açıkça işaretlenmemiş konnektörleri kullanmayın.
Konnektörü aşağıdaki yollardan biriyle kullanabilirsiniz:
(Önerilen) Ek bağımlılık olarak yükleme
-
İşinizin pom.xml dosyasına gerekli konnektörü "provided" kapsamıyla proje bağımlılığı olarak ekleyin. Tam bağımlılık dosyası için bu konunun sonundaki Tam kod örneği bölümüne bakın.
Not${vvr.version}parametresi iş çalışma zamanı motoru sürümüdür. Örneğin, işinizvvr-8.0.9-flink-1.17motorunda çalışıyorsa karşılık gelen Flink sürümü1.17.2olur. En son motoru kullanmanızı öneririz. Belirli sürümler hakkında bilgi için bkz. Motor.Konnektörün JAR paketi ek bağımlılık olarak eklendiğinden uygulama JAR dosyasına paketlenmesine gerek yoktur. Bu nedenle kapsamını
providedolarak bildirmeniz gerekir.
<!-- Kafka connector dependency --> <dependency> <groupId>com.alibaba.ververica</groupId> <artifactId>ververica-connector-kafka</artifactId> <version>${vvr.version}</version> <scope>provided</scope> </dependency> <!-- MySQL connector dependency --> <dependency> <groupId>com.alibaba.ververica</groupId> <artifactId>ververica-connector-mysql</artifactId> <version>${vvr.version}</version> <scope>provided</scope> </dependency> -
Yeni konnektörler geliştirmeniz veya mevcut konnektörlerin işlevselliğini genişletmeniz gerekiyorsa projenizin
flink-connector-baseveyaververica-connector-commonortak konnektör paketlerine de bağımlı olması gerekir.<!-- Basic dependency for Flink connector public interfaces --> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-connector-base</artifactId> <version>${flink.version}</version> </dependency> <!-- Basic dependency for Alibaba Cloud connector public interfaces --> <dependency> <groupId>com.alibaba.ververica</groupId> <artifactId>ververica-connector-common</artifactId> <version>${vvr.version}</version> </dependency> -
DataStream bağlantı yapılandırmaları ve kod örnekleri için ilgili DataStream konnektörünün belgelerine bakın.
DataStream API'yi destekleyen konnektörlerin listesi için bkz. Desteklenen konnektörler.
-
İşi dağıtın ve Additional Dependencies alanında ilgili konnektör JAR paketlerini ekleyin. Daha fazla bilgi için bkz. JAR işi dağıtma. Özel konnektörlerinizi veya Realtime Compute for Apache Flink tarafından sağlanan konnektörleri yükleyebilirsiniz. Konnektörleri indirmek için bkz. Konnektörler.
Örneğin,
ververica-connector-mysql-1.17-vvr-8.0.4-1.jarveververica-connector-kafka-1.17-vvr-8.0.4-1.jarkonnektör JAR paketlerini veconfig.propertiesyapılandırma dosyasını yükleyin.
İş JAR dosyasına paketleme
-
Gerekli konnektörleri işinizin pom.xml dosyasına proje bağımlılığı olarak ekleyin. Aşağıdaki kod Kafka ve MySQL konnektörleri için bir örnek gösterir.
Not${vvr.version}parametresi işin çalışma ortamının motor sürümüdür. Örneğin, işinizvvr-8.0.9-flink-1.17motor sürümünde çalışıyorsa karşılık gelen Flink sürümü1.17.2olur. En son motoru kullanmanızı öneririz. Daha fazla bilgi için bkz. Motorlar.Konnektörleri proje bağımlılığı olarak iş JAR dosyasına paketlerseniz bunların varsayılan kapsamda (compile) olması gerekir.
<!-- Kafka connector dependency --> <dependency> <groupId>com.alibaba.ververica</groupId> <artifactId>ververica-connector-kafka</artifactId> <version>${vvr.version}</version> </dependency> <!-- MySQL connector dependency --> <dependency> <groupId>com.alibaba.ververica</groupId> <artifactId>ververica-connector-mysql</artifactId> <version>${vvr.version}</version> </dependency> -
Yeni konnektörler geliştirmeniz veya mevcut konnektörlerin işlevselliğini genişletmeniz gerekiyorsa projenizin
flink-connector-baseveyaververica-connector-commonortak konnektör paketlerine de ihtiyacı vardır.<!-- Basic dependency for Flink connector public interfaces --> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-connector-base</artifactId> <version>${flink.version}</version> </dependency> <!-- Basic dependency for Alibaba Cloud connector public interfaces --> <dependency> <groupId>com.alibaba.ververica</groupId> <artifactId>ververica-connector-common</artifactId> <version>${vvr.version}</version> </dependency> -
DataStream bağlantı yapılandırmaları ve kod örnekleri için ilgili DataStream konnektörünün belgelerine bakın.
DataStream API'yi destekleyen konnektörlerin listesi için bkz. Desteklenen konnektörler.
Ek bağımlılıkları OSS'ten okuma
Flink JAR işleri main yönteminden yerel yapılandırma dosyalarını okuyamaz. Bunun yerine yapılandırma dosyasını çalışma alanınızın OSS paketine yükleyin, dağıtım sırasında ek bağımlılık olarak ekleyin ve çalışma zamanında okuyun. Aşağıdaki bölümde bir örnek sunulmaktadır.
-
Kimlik bilgilerinin kodda sabit kodlanmasını önlemek için config.properties adlı bir yapılandırma dosyası oluşturun.
# Kafka bootstrapServers=host1:9092,host2:9092,host3:9092 inputTopic=topic groupId=groupId # MySQL database.url=jdbc:mysql://localhost:3306/my_database database.username=username database.password=password -
JAR işinizde OSS paketinde depolanan config.properties dosyasını okumak için kod kullanın.
Yöntem 1: Çalışma alanı paketinden okuma
Realtime Compute for Apache Flink konsolunun sol gezinme bölmesinde Artifacts sayfasına gidin ve dosyayı yükleyin.
Çalışma zamanında Additional Dependencies alanında eklenen dosyalar işin çalıştığı pod'un /flink/usrlib dizinine yüklenir.
-
Aşağıdaki kod bu yapılandırma dosyasının nasıl okunacağını gösterir.
Properties properties = new Properties(); Map<String,String> configMap = new HashMap<>(); try (InputStream input = new FileInputStream("/flink/usrlib/config.properties")) { // Load the property file. properties.load(input); // Obtain the property values. configMap.put("bootstrapServers",properties.getProperty("bootstrapServers")) ; configMap.put("inputTopic",properties.getProperty("inputTopic")); configMap.put("groupId",properties.getProperty("groupId")); configMap.put("url",properties.getProperty("database.url")) ; configMap.put("username",properties.getProperty("database.username")); configMap.put("password",properties.getProperty("database.password")); } catch (IOException ex) { ex.printStackTrace(); }
Yöntem 2: Yetkilendirilmiş paketten okuma
Yapılandırma dosyasını hedef OSS paketine yükleyin.
-
Dosyayı doğrudan OSS'ten okumak için OSSClient kullanın. Daha fazla bilgi için bkz. Akışlı indirme ve Erişim kimlik bilgilerini yönetme. Aşağıdaki kod bir örnek sunar.
OSS ossClient = new OSSClientBuilder().build("Endpoint", "AccessKeyId", "AccessKeySecret"); try (OSSObject ossObject = ossClient.getObject("examplebucket", "exampledir/config.properties"); BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()))) { // read file and process ... } finally { if (ossClient != null) { ossClient.shutdown(); } }
İş mantığını yazma
-
Harici veri kaynaklarını Flink veri akışı programlarına entegre edebilirsiniz.
Watermarkzaman temelli bir Flink hesaplama stratejisidir ve genellikle zaman damgalarıyla birlikte kullanılır. Bu nedenle bu örnekte bir watermark stratejisi kullanılmaz. Daha fazla bilgi için bkz. Watermark stratejisi.// Integrate the external data source into the Flink data stream program. // WatermarkStrategy.noWatermarks() indicates that no watermark strategy is used. DataStreamSource<String> stream = env.fromSource(kafkaSource, WatermarkStrategy.noWatermarks(), "kafka Source"); -
Operatör dönüşümü bu örnekte bir
DataStream<String>öğesini birDataStream<Student>öğesine dönüştürür. Daha karmaşık operatör dönüşümleri ve işleme yöntemleri için bkz. Flink Operatörleri.// Operator that converts the data structure to Student. DataStream<Student> source = stream .map(new MapFunction<String, Student>() { @Override public Student map(String s) throws Exception { // Data is separated by commas. String[] data = s.split(","); return new Student(Integer.parseInt(data[0]), data[1], Integer.parseInt(data[2])); } }).filter(student -> student.score >=60); // Filter for data where the score is 60 or higher.
İşi paketleme
İşi maven-shade-plugin kullanarak paketleyin.
Konnektörü ek bağımlılık olarak eklerseniz işi paketlerken konnektör bağımlılıklarının kapsamının
providedolarak ayarlandığından emin olun.Konnektörleri iş JAR dosyasına paketlerseniz varsayılan kapsamı (compile) kullanın.
İşi test etme ve dağıtma
Realtime Compute for Apache Flink varsayılan olarak genel internete erişemez; bu durum yerel ortamda doğrudan test yapılmasını engeller. Birim testlerini ayrı ayrı gerçekleştirmenizi öneririz. Daha fazla bilgi için bkz. Konnektörlü bir işi yerel ortamda çalıştırma ve hata ayıklama.
-
JAR işini dağıtmak için bkz. JAR işi dağıtma.
NotDağıtım sırasında konnektörleri ek bağımlılık olarak kullanıyorsanız ilgili JAR paketlerini yüklediğinizden emin olun.
Bir yapılandırma dosyası okumanız gerekiyorsa bunu da ek bağımlılık olarak yüklemeniz gerekir.
Tam kod örneği
Bu örnek ApsaraMQ for Kafka kaynağından gelen verileri işler ve sonucu bir ApsaraDB RDS for MySQL hedefine yazar. Bu örnek yalnızca referans amaçlıdır. Daha fazla kod stili ve kalite kılavuzu için bkz. Kod stili ve kalite kılavuzu.
Bu örnekte checkpoint, TTL ve yeniden başlatma stratejisi gibi çalışma zamanı parametrelerinin yapılandırmaları atlanmıştır. Bu ayarları iş dağıtıldıktan sonra deployment details sayfasında yapılandırabilirsiniz. Kod içindeki ayarlar daha yüksek önceliğe sahip olduğundan gelecekteki güncellemeleri basitleştirmek için bunları dağıtımdan sonra yapılandırmanızı öneririz. Daha fazla bilgi için bkz. İş dağıtım bilgilerini yapılandırma.
FlinkDemo.java
package com.aliyun;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.connector.jdbc.JdbcConnectionOptions;
import org.apache.flink.connector.jdbc.JdbcExecutionOptions;
import org.apache.flink.connector.jdbc.JdbcSink;
import org.apache.flink.connector.jdbc.JdbcStatementBuilder;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.connector.kafka.source.reader.deserializer.KafkaRecordDeserializationSchema;
import org.apache.flink.kafka.shaded.org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class FlinkDemo {
// Define the data structure.
public static class Student {
public int id;
public String name;
public int score;
public Student(int id, String name, int score) {
this.id = id;
this.name = name;
this.score = score;
}
}
public static void main(String[] args) throws Exception {
// Create a Flink execution environment.
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
Properties properties = new Properties();
Map<String,String> configMap = new HashMap<>();
try (InputStream input = new FileInputStream("/flink/usrlib/config.properties")) {
// Load the property file.
properties.load(input);
// Obtain the property values.
configMap.put("bootstrapServers",properties.getProperty("bootstrapServers")) ;
configMap.put("inputTopic",properties.getProperty("inputTopic"));
configMap.put("groupId",properties.getProperty("groupId"));
configMap.put("url",properties.getProperty("database.url")) ;
configMap.put("username",properties.getProperty("database.username"));
configMap.put("password",properties.getProperty("database.password"));
} catch (IOException ex) {
ex.printStackTrace();
}
// Build Kafka source
KafkaSource<String> kafkaSource = KafkaSource.<String>builder()
.setBootstrapServers(configMap.get("bootstrapServers"))
.setTopics(configMap.get("inputTopic"))
.setStartingOffsets(OffsetsInitializer.latest())
.setGroupId(configMap.get("groupId"))
.setDeserializer(KafkaRecordDeserializationSchema.valueOnly(StringDeserializer.class))
.build();
// Integrate the external data source into the Flink data stream program.
// WatermarkStrategy.noWatermarks() indicates that no watermark strategy is used.
DataStreamSource<String> stream = env.fromSource(kafkaSource, WatermarkStrategy.noWatermarks(), "kafka Source");
// Filter for scores of 60 or higher.
DataStream<Student> source = stream
.map(new MapFunction<String, Student>() {
@Override
public Student map(String s) throws Exception {
String[] data = s.split(",");
return new Student(Integer.parseInt(data[0]), data[1], Integer.parseInt(data[2]));
}
}).filter(Student -> Student.score >=60);
source.addSink(JdbcSink.sink("INSERT IGNORE INTO student (id, username, score) VALUES (?, ?, ?)",
new JdbcStatementBuilder<Student>() {
public void accept(PreparedStatement ps, Student data) {
try {
ps.setInt(1, data.id);
ps.setString(2, data.name);
ps.setInt(3, data.score);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
},
new JdbcExecutionOptions.Builder()
.withBatchSize(5) // Number of records per batch write.
.withBatchIntervalMs(2000) // Batch interval in milliseconds.
.build(),
new JdbcConnectionOptions.JdbcConnectionOptionsBuilder()
.withUrl(configMap.get("url"))
.withDriverName("com.mysql.cj.jdbc.Driver")
.withUsername(configMap.get("username"))
.withPassword(configMap.get("password"))
.build()
)).name("Sink MySQL");
env.execute("Flink Demo");
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.aliyun</groupId>
<artifactId>FlinkDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<name>FlinkDemo</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<flink.version>1.17.1</flink.version>
<vvr.version>1.17-vvr-8.0.4-1</vvr.version>
<target.java.version>1.8</target.java.version>
<maven.compiler.source>${target.java.version}</maven.compiler.source>
<maven.compiler.target>${target.java.version}</maven.compiler.target>
<log4j.version>2.14.1</log4j.version>
</properties>
<dependencies>
<!-- Apache Flink dependencies -->
<!-- These dependencies are set to 'provided' because they should not be packaged into the JAR file. -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<!-- Add connector dependencies here. They must be in the default scope (compile). -->
<dependency>
<groupId>com.alibaba.ververica</groupId>
<artifactId>ververica-connector-kafka</artifactId>
<version>${vvr.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.ververica</groupId>
<artifactId>ververica-connector-mysql</artifactId>
<version>${vvr.version}</version>
</dependency>
<!-- Add a logging framework to generate console output at runtime. -->
<!-- By default, these dependencies are excluded from the application JAR. -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Java Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${target.java.version}</source>
<target>${target.java.version}</target>
</configuration>
</plugin>
<!-- We use the maven-shade-plugin to create a fat JAR that contains all necessary dependencies. -->
<!-- Modify the value of <mainClass> if your program's entry point changes. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<!-- Exclude unnecessary dependencies. -->
<configuration>
<artifactSet>
<excludes>
<exclude>org.apache.flink:force-shading</exclude>
<exclude>com.google.code.findbugs:jsr305</exclude>
<exclude>org.slf4j:*</exclude>
<exclude>org.apache.logging.log4j:*</exclude>
</excludes>
</artifactSet>
<filters>
<filter>
<!-- Do not copy the signatures from the META-INF directory.
Otherwise, security exceptions may be thrown when you use the JAR file. -->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.aliyun.FlinkDemo</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
İlgili belgeler
DataStream API'yi destekleyen konnektörlerin listesi için bkz. Desteklenen konnektörler.
Flink JAR işi geliştirme iş akışının uçtan uca tam bir örneği için bkz. Flink JAR işleri.
Realtime Compute for Apache Flink SQL ve Python işlerini de destekler. Geliştirme rehberliği için bkz. İş geliştirme genel bakış ve Python işleri geliştirme.