springboot-集成flink最佳实践和打包部署
admin
2024-02-20 23:21:38
0

引入flink依赖

//stream api和table api
org.apache.flinkflink-table-api-java-bridge_2.111.14.2provided

org.apache.flinkflink-clients_2.111.14.2provided

编写入口

目录结构

  • com.example.demo
    • auto
      • ChildApplication
    • task
      • Task
      • AbstractTask
      • TaskManager
    • time
      • TimeSource
      • TimeTask
    • Demo2Application

子容器初始化类

@EnableAutoConfiguration
public class ChildApplication {
}

任务接口

public interface Task {void run(String... args) throws Exception;
}

抽象任务类

@Slf4j
public abstract class AbstractTask implements Task {@Overridepublic void run(String... args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();ParameterTool parameterTool = ParameterTool.fromArgs(args);configTask(env, parameterTool);JobClient jobClient = env.executeAsync(getClass().getSimpleName());if (jobClient instanceof WebSubmissionJobClient) {return;}jobClient.getJobExecutionResult().whenComplete(new BiConsumer() {@Overridepublic void accept(JobExecutionResult jobExecutionResult, Throwable throwable) {log.error("time {}", jobExecutionResult.getNetRuntime(TimeUnit.SECONDS));}});}public abstract void configTask(StreamExecutionEnvironment env, ParameterTool tool);}

任务管理器

@Slf4j
@Service
public class TaskManager implements CommandLineRunner {@ResourceList taskList;@Overridepublic void run(String... args) throws Exception {ParameterTool parameterTool = ParameterTool.fromArgs(args);log.info("程序参数 {}", parameterTool);String runTaskName = parameterTool.get("task");if (CollectionUtils.isEmpty(taskList) || StringUtils.isBlank(runTaskName)) {return;}for (Task task : taskList) {if (Objects.equals(runTaskName, task.getClass().getName())) {task.run(args);}}}}

一个计时任务数据源

@Slf4j
@Service
public class TimeSource extends RichSourceFunction {volatile boolean running = true;private JdbcTemplate jdbcTemplate;@Overridepublic void open(Configuration parameters) throws Exception {//创建一个容器,并拿到需要的beanString[] args = new String[]{String.format("--spring.application.admin.jmx-name=org.springframework.boot:type=Admin,name=%s", getClass().getName()),String.format("--spring.jmx.default-domain=%s", getClass().getName())};ConfigurableApplicationContext applicationContext = SpringApplication.run(ChildApplication.class, args);jdbcTemplate = applicationContext.getBean(JdbcTemplate.class);}@Overridepublic void run(SourceContext ctx) throws Exception {while (running) {Date date = DataAccessUtils.uniqueResult(jdbcTemplate.queryForList("select now()", Date.class));ctx.collect(date);TimeUnit.SECONDS.sleep(1);}}@Overridepublic void cancel() {running = false;}}

写这个数据源类花了很长时间,期间报了很多错,一直不符合预期:

  • xxx is not serializable:flink的算子可能会在不同的机器上运行,所以类信息会序列化之后传输。所以算子不能有任何不能序列化的字段(字段为null除外)
  • 有些需要的字段没有实现Serializable,但是又确实要用到,比如JdbcTemplate,如果是mybatis的话,就是各种mapper;像这些字段,只能在open方法里面初始化。有两种方法做这个初始化:一是,通过全局参数把一些连接信息传到算子,然后在open方法中初始化JdbcTemplate;二是,在open方法中重新创建一个容器,然后从容器中拿到JdbcTemplate。第一种方法,比较容易实现,但是要手动装配JdbcTemplate;第二种方法,要重新创建一个容器,装配的任务全都交给容器;想法是很nice,但在一个容器中创建另一个容器,比想象中的要复杂一些。
  • 在一个容器中初始化另一个容器:
    • 需要一个容器初始化类:因为毕竟不需要注入所有对象,所以不能用主程序启动类Demo2Application;但是又要autoconfigure里面的很多对象,所以考虑加@EnableAutoConfiguration注解,同时放入单独的auto包,避免扫到不需要的bean定义;如果需要mybatis的mapper,考虑加@MapperScan注解
    • 定义好容器初始化类之后,启动报错:Error creating bean with name ‘springApplicationAdminRegistrar’ defined in class path resource [org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.class]: Invocation of init method failed; nested exception is javax.management.InstanceAlreadyExistsException: org.springframework.boot:type=Admin,name=SpringApplication。看错误信息是实例重复了,这个有两种解决办法:
      • 容器初始化类直接排除掉SpringApplicationAdminJmxAutoConfiguration.class:@EnableAutoConfiguration(exclude = {SpringApplicationAdminJmxAutoConfiguration.class})
      • 子容器启动时修改spring.application.admin.jmx-name:–spring.application.admin.jmx-name=org.springframework.boot:type=Admin,name=%s
    • 再启动,还是报错:Unable to register MBean [HikariDataSource (HikariPool-2)] with key ‘dataSource’; nested exception is javax.management.InstanceAlreadyExistsException: com.zaxxer.hikari:name=dataSource,type=HikariDataSource。又是个实例重复的问题,这个问题百度了下,需要给spring.jmx.default-domain配置个新的值:–spring.jmx.default-domain=%s
    • 再启动,子容器正常创建,程序运行发现ok
    • 打包上传flink web,提交运行,正常!

一个计时任务

@Slf4j
@Service
public class TimeTask extends AbstractTask {@Resourceprivate TimeSource timeSource;@Overridepublic void configTask(StreamExecutionEnvironment env, ParameterTool tool) {env.getConfig().setAutoWatermarkInterval(0);env.addSource(timeSource).setParallelism(1).print().setParallelism(1);}}

主程序启动类

@SpringBootApplication
public class Demo2Application {public static void main(String[] args) {SpringApplication.run(Demo2Application.class, args);}}

打包程序

设置parent

org.springframework.bootspring-boot-starter-parent2.7.5 

直接使用spring-boot-maven-plugin?

org.springframework.bootspring-boot-maven-plugin

因为spring-boot-maven-plugin打包区分了main-class和start-class,打包之后main-class是org.springframework.boot.loader.JarLauncher引导类,上传到flink web执行报错。

考虑使用maven-shade-plugin

参考SpringBoot超详细讲解集成Flink的部署与打包方法的方法二写了一版:

org.apache.maven.pluginsmaven-shade-plugin3.3.0packageshadefalsecom.google.code.findbugs:jsr305org.slf4j:*log4j:**:*module-info.classMETA-INF/*.SFMETA-INF/*.DSAMETA-INF/*.RSAMETA-INF/spring.handlersreference.confMETA-INF/spring.factoriesMETA-INF/spring.schemas${start-class}

结果报错:

Cannot find ‘resource’ in class org.apache.maven.plugins.shade.resource.ServicesResourceTransformer

纠结了半天,也没找到原因

再试试maven-assembly-plugin

  org.apache.maven.pluginsmaven-assembly-plugin3.3.0${start-class}jar-with-dependenciesmake-assemblypackagesingle

可以正常打包,本地也能运行,但是上传到flink web报错

LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.apache.logging.slf4j.Log4jLoggerFactory loaded from file:/opt/flink/lib/log4j-slf4j-impl-2.16.0.jar)

很明显,日志相关的jar冲突了。那么问题就是怎么配置maven-assembly-plugin,打包的时候移出org.apache.logging.log4j或ch.qos.logback?这个也比较困难,需要自定义assembly.xml文件,相对来说成本比较大。

重回maven-shade-plugin

找到很多资料,包括flink官方的maven打包方式也是用maven-shade-plugin,所以决定还是使用maven-shade-plugin。

那怎么解决Cannot find 'resource' in class org.apache.maven.plugins.shade.resource.ServicesResourceTransformer的问题呢?

恰好最近在看maven pom文件的相关知识,不小心打开了spring-boot-starter-parentpluginManagement,发现里面定义很多插件,其中就包括maven-shade-plugin

按照pom依赖的逻辑,只要在build->plugins声明maven-shade-plugin就行:

org.apache.maven.pluginsmaven-shade-plugin

mvn clean package

打包成功了!

仔细翻看spring-boot-starter-parent声明的maven-shade-plugin,发现executions->execution->configuration->transformers的内容在spring-boot的不同版本是不同的。难怪找不到resource。

后续打包上传到flink web,也是报日志相关的jar冲突,不过maven-shade-plugin打包排除依赖比maven-assembly-plugin简单多了。由于flink运行时包含/opt/flink/lib/log4j-slf4j-impl-2.16.0.jar,所以果断排除logback,完整plugin配置如下:

org.apache.maven.pluginsmaven-shade-plugincom.google.code.findbugs:jsr305ch.qos.logback:*

相关内容

热门资讯

安卓系统最强定位手机版,最强定... 你有没有想过,在茫茫人海中,如何让你的手机定位功能像侦探一样精准无误?今天,就让我带你一探究竟,揭秘...
安卓运行环境选哪个系统,And... 你有没有想过,你的安卓手机到底是在哪个运行环境下才能发挥出最佳性能呢?这可是个技术活儿,选对了系统,...
zui15系统是安卓系统吗,揭... 亲爱的读者,你是否曾好奇过,那些在手机上运行得风生水起的系统,它们究竟是不是安卓的呢?今天,就让我带...
ios系统和安卓系统权限区别,... 你有没有发现,无论是手机还是平板,我们用的最多的就是那些APP了。而这些APP,它们在手机里可是有着...
荣耀手环6安卓版系统,智能生活... 你有没有注意到,最近你的手腕上是不是多了一抹亮丽的色彩?没错,说的就是荣耀手环6安卓版系统!这款智能...
极品奴隶系统下载安卓版,体验独... 你有没有听说过那个超级火的“极品奴隶系统”安卓版?最近,这款游戏在朋友圈里可是炸开了锅,大家都说它好...
安卓手机苹果系统扣费,揭秘扣费... 你有没有遇到过这种情况?手机里突然多了一笔扣费,而且还是那种你完全没意识到的扣费?尤其是当你用的是安...
安卓系统智能电视刷机,焕新体验 亲爱的电视迷们,你是否曾为你的安卓智能电视的性能所困扰?是不是觉得它运行缓慢,功能受限?别担心,今天...
安卓系统无法安装applica... 最近是不是遇到了安卓系统无法安装application的烦恼?别急,让我来帮你一探究竟,解决这个让人...
怎么取消安卓系统锁屏,解锁锁屏... 手机锁屏功能虽然能保护我们的隐私,但有时候也会让人头疼,比如忘记密码或者想快速查看信息时。那么,怎么...
安卓系统高德怎么下载,轻松获取... 你有没有发现,现在手机上导航软件真是越来越方便了?尤其是安卓系统的用户,高德地图这款神器简直成了出行...
安卓系统的开源部分,开源代码背... 你知道吗?安卓系统,这个在我们手机上无处不在的小家伙,竟然有一部分是开源的!是不是觉得有点神奇?别急...
小米下载安卓13系统,畅享智能... 亲爱的手机控们,你是否已经迫不及待想要体验最新的操作系统呢?没错,我说的就是安卓13系统!而今天,我...
安卓系统如何设置拍月亮,捕捉夜... 月亮,那轮皎洁的夜空明珠,总是让人心生向往。你是否也想用你的安卓手机捕捉到它的美丽瞬间呢?别急,今天...
安卓v8以上系统,探索安卓V8... 你知道吗?最近手机界可是掀起了一股新潮流,那就是安卓V8以上系统。这可不是什么小打小闹,而是实实在在...
安卓系统兼容哪个版本好,哪个版... 你有没有想过,你的安卓手机到底兼容哪个版本的系统最好呢?这可是个技术活儿,得好好研究研究。别急,今天...
安卓平板安装linux桌面系统... 你有没有想过给你的安卓平板来个变身大法?没错,就是给它安装一个Linux桌面系统!想象原本只能刷刷剧...
安卓什么手机系统bug最少,揭... 你有没有发现,用安卓手机的时候,有时候会遇到一些小麻烦,比如系统突然卡顿,或者某个应用突然崩溃,真是...
手机软件安卓下载系统,解锁手机... 你有没有发现,现在的生活越来越离不开手机了?手机里装满了各种各样的软件,让我们的生活变得更加便捷。今...
微软系统和安卓系统的cad软件... 你有没有想过,为什么你的电脑里装的是微软系统,而朋友的手机上却是安卓系统?这背后其实隐藏着一场关于操...