我们知道 Flink 作业的配置一般都是通过在作业启动的时候通过参数传递的,或者通过读取配置文件的参数,在作业启动后初始化了之后如果再想更新作业的配置一般有两种解决方法:
- 改变启动参数或者改变配置文件,重启作业,让作业能够读取到修改后的配置
- 通过读取配置流(需要自定义 Source 读取配置),然后流和流连接起来
这两种解决方法一般是使用的比较多,对于第一种方法,其实是不太建议的,重启作业会带来很多影响,Flink 作业完整的重启流程应该是:当作业停掉的时候需要去做一次 Savepoint(相当于把作业的状态做一次完整的快照),启动的时候又需要将作业从 Savepoint 启动,整个流程如果状态比较大的话,做一次 Savepoint 和从 Savepoint 初始化的时间会比较久,然而流处理的场景下通常数据量都是比较大的,那么在这段时间内,可能会造成不少的数据堆积(可能分钟内就上千万或者更多),当作业启动后再去追这千万量级的数据,对作业来说压力自然会增大。
对于第二种方法也是一种用的很多的方式,是比较推荐的。
案例一:
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* flink nacos 整合测试
*/
public class FlinkNacosTest {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.getConfig().setGlobalJobParameters(ParameterTool.fromArgs(args));
env.setParallelism(1);
env.addSource(new RichSourceFunction<String>() {
ConfigService configService;
String config;
String dataId = "cbsp-data-platform-service.yaml";
String group = "cbsp-data-platform-service-group";
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
String serverAddr = "192.168.2.51";
String namespaceId = "0b416873-252c-4792-9464-c88da4da72a2";
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
properties.put("namespace", namespaceId);
configService = NacosFactory.createConfigService(properties);
config = configService.getConfig(dataId, group, 5000);
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
config = configInfo;
}
});
}
@Override
public void run(SourceContext<String> ctx) throws Exception {
while (true) {
Thread.sleep(3000);
System.out.println("run config = " + config);
ctx.collect(String.valueOf(System.currentTimeMillis()));
}
}
@Override
public void cancel() {
}
}).print();
env.execute();
}
}
案例二:
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.streaming.api.CheckpointingMode;
import org.apache.flink.streaming.api.environment.CheckpointConfig;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* Desc: 测试 nacos 动态更改配置后,Flink 是否可以获取到更改后的值,并生效?
*
* 结论是:不生效,因为 Flink 是 Lazy Evaluation(延迟执行),当程序的 main 方法执行时,数据源加载数据和数据转换等算子不会立马执行,
* 这些操作会被创建并添加到程序的执行计划中去,只有当执行环境 env 的 execute 方法被显示地触发执行时,整个程序才开始执行实际的操作,所以
* 在一开始初始化后等程序执行 execute 方法后再修改 env 的配置其实就不起作用了。
*/
public class FlinkNacosTest2 {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.getConfig().setGlobalJobParameters(ParameterTool.fromArgs(args));
env.setParallelism(1);
String serverAddr = "192.168.2.51";
String dataId = "cbsp-data-platform-service.yaml";
String group = "cbsp-data-platform-service-group";
String namespaceId = "0b416873-252c-4792-9464-c88da4da72a2";
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
properties.put("namespace", namespaceId);
ConfigService configService = NacosFactory.createConfigService(properties);
final String[] content = {configService.getConfig(dataId, group, 5000)};
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
content[0] = configInfo;
}
});
env.addSource(new SourceFunction<Tuple2<String, Long>>() {
@Override
public void run(SourceContext<Tuple2<String, Long>> ctx) throws Exception {
while (true) {
ctx.collect(new Tuple2<>(content[0], System.currentTimeMillis()));
Thread.sleep(1000);
}
}
@Override
public void cancel() {
}
}).print();
env.execute();
}
}