前言
入坑大数据之前,一直在做业务开发,必然是少不了用springboot。springboot 可以根据 spring.profiles.active
来指定启动的环境信息,一个包可以运用多个环境,也在一定程度上避免了线上和开发测试不一致的情况,那么在Flink 中该如何实现再加载环境时指定环境信息呢,是否有flink.profiles.active
?
当然Flink 没有提供类似的功能,我们针对Flink 提供的工具方法稍加加工即可实现。
实现
针对于flink读取配置ParameterTool 提供了很多取配置的方法,使用env.getConfig().setGlobalJobParameters(parameterTool)
它可以传递 Configuration 中的参数到 Rich 函数中,使用open() 可以获取到配置中的参数。 我们可以从ParameterTool
入手,我们可以根据启动指定的args[],来决定加载什么环境的配置,当然我们需要约定好,比如说启动时指定--flink.profiles.active test
来读取我们test对应的环境信息 , 利用ParameterTool.fromArgs(args).get("flink.profiles.active")
可以获取到 flink.profiles.active 值,如果没有值就读取默认位置的配置文件。如果有值我们可以采用路径区来分环境,读取不同环境下的配置信息,当然springboot 还有配置优先级,可以meger 默认配置文件中的配置,ParameterTool
提供了ParameterTool#mergeWith()
方法。具体代码实现如下:
/**
* @author liweigao
* @date 2021/7/28 下午6:13
*/
@Slf4j
public class EnvOperation {
private EnvOperation() {
throw new RuntimeException("not support instantiation by other!");
}
private static final String ENV = "flink.profiles.active";
private static final String FILE_CHARACTER = "/";
/**
* @param args 参数
* @param tclass class
* @param name name of the desired resource
* @return inputStream
*/
public static InputStream getEnvStream(String[] args, Class tclass, String name) {
ParameterTool fromArgs = fromArgs(args);
String path = getEnvPath(fromArgs);
return getEnvStream(path, tclass, name);
}
/**
* 解析文件
*
* @param path 解析激活的环境变量
* @param tclass class
* @param name 文件名称
* @return inputStream
*/
private static InputStream getEnvStream(String path, Class tclass, String name) {
if (Strings.isBlank(path)) {
log.info("profiles active is : default");
return getDefaultEnvStream(tclass, name);
} else {
if (!name.startsWith(FILE_CHARACTER)) {
name = FILE_CHARACTER + name;
}
log.info("profiles active is : {}", path);
return tclass.getResourceAsStream(FILE_CHARACTER + path + name);
}
}
/**
* 获取指定环境的配置信息
*
* @param path 路径
* @param tclass class
* @param name 文件名称
* @return inputStream
*/
private static InputStream getSpeciallyEnvStream(String path, Class tclass, String name) {
if (!name.startsWith(FILE_CHARACTER)) {
name = FILE_CHARACTER + name;
}
return tclass.getResourceAsStream(FILE_CHARACTER + path + name);
}
/**
* @param tclass class
* @param name 文件名称
* @return inputStream
*/
private static InputStream getDefaultEnvStream(Class tclass, String name) {
return tclass.getResourceAsStream(name);
}
/**
* @param args 参数
* @param name name of the desired resource
* @return inputStream
*/
public static InputStream getEnvStream(String[] args, String name) {
return getEnvStream(args, EnvOperation.class, name);
}
/**
* 获取指定环境路径
*
* @param tool args
* @return path
* @see {@link Utils#getKeyFromArgs(String[], int)}
*/
private static String getEnvPath(ParameterTool tool) {
return tool.get(ENV);
}
private static ParameterTool fromArgs(String[] args) {
return ParameterTool.fromArgs(args);
}
public static ParameterTool getParameterToolMergeDefault(String[] args, Class tclass, String name) throws IOException {
ParameterTool fromArgs = fromArgs(args);
String path = getEnvPath(fromArgs);
ParameterTool defaultTool = getParameterToolForInputStream(getDefaultEnvStream(tclass, name));
if (Strings.isBlank(path)) {
log.info("profiles active is : default");
log.info("default config mergeWith args config");
// formArgs data is UnmodifiableMap
Map<String, String> map = fromArgs.toMap();
map = Maps.newHashMap(map);
map.put(ENV, "default");
fromArgs = ParameterTool.fromMap(map);
return defaultTool.mergeWith(fromArgs);
} else {
log.info("profiles active is : {}", path);
ParameterTool active = getParameterToolForInputStream(getSpeciallyEnvStream(path, tclass, name));
log.info("default config mergeWith {} config", path);
active = defaultTool.mergeWith(active);
log.info("{} config is mergeWith args config", path);
return active.mergeWith(fromArgs);
}
}
private static ParameterTool getParameterToolForInputStream(InputStream inputStream) throws IOException {
ParameterTool parameterTool = ParameterTool.fromArgs(new String[0]);
if (Objects.nonNull(inputStream)) {
parameterTool = ParameterTool.fromPropertiesFile(inputStream);
} else {
log.debug("profiles path is non-existent");
}
return parameterTool;
}
}
获取配置时:
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
ParameterTool parameterTool = EnvOperation.getParameterToolMergeDefault(args, Application.class,
"/application.properties");
//设置全局配置
env.getConfig().setGlobalJobParameters(parameterTool);;
parameterTool 对象即为指定 flink.profiles.active
对应的环境信息。
配置目录结构
├── application.properties
├── test
│ └── application.properties
└── dev
└── application.properties
当我们部署standalone 、yarn(session 、 per job or application moudle)时 启动命令需要加–flink.profiles.active [环境信息], 即可实现启动指定环境信息
总结
以上拙见,毕竟才入坑,欢迎交流,本次实现为不同环境按照目录来区分,当然我们也可以完全做到跟springboot 加载环境信息一样的功能,当然目前已经满足我们目前的需求了~点到为止,不做复杂的轮子。