项目场景:
可参考资讯现有代码,搭建一套资讯系统的框架,使用spring boot框架。
oracle数据库,可继续使用t_user_info做示例,接口同步可使用上个spring boot demo的用户查询接口示例。
1、http数据接收服务:接收第三方推送过来的数据,存mongodb,推kafka
2、数据库同步服务:定时同步指定oracle库指定表,存mongodb,推kafka
3、http数据同步服务:定时同步指定http接口数据,存mongodb,推kafka
4、storm实时计算服务:接收1,2,3的kafka数据,数据处理,存redis
5、flink实时计算服务:接收1,2,3的kafka数据,数据处理,存redis
6、http接口服务:提供资讯数据服务,读redis输出
storm实时计算服务踩坑记录
(相比其他几个模块,该模块借鉴的代码年代较为久远,使用的底层storm代码由zhangwenqiang大佬所写,目前该版本的storm缺少说明文档,故搭建该模块有很多坑- - )
1、不能使用springboot的ioc性质注入对象:(具体原因待研究
2、properities配置文件读取config.groovy失败:由于不能使用ioc注入获取配置,所以用工具类先读取特定路径的properities文件,而properities文件中的部分字段需要在项目build时动态地从config.groovy文件中读取,可能是由于版本问题,负责解析config.groovy的
ConfigSlurper类的解析规则可能会和参考项目(dcnews-master\dcnews-storm)有所不同。在参考项目中,properities文件使用${xxxxxx}获取config.groovy文件中的参数,但是较新的代码版本中需要使用@xxxxx@才能获取config.groovy文件中的参数
3、storm和spring的日志类冲突:Spring Boot Starter引入的日志组件是log4j-to-slf4j,Storm1.2.2引入的日志组件是log4j-slf4j-impl:两个放一起就会冲突,默认两个都引入了,就会报如下错误
“No matching field found: getConfiguration for class org.apache.logging.slf4j.SLF4JLoggerContext”:
为了解决这种冲突,此时的解决方案是去掉spring boot中的默认日志组件的引入,与storm模块相关的springboot依赖可能来自主项目,也能是由storm模块自己引入。如果想在主项目的build.gradle中直接排除:
subprojects {
configurations {
// 所有需要忽略的包定义在此
all*.exclude group: 'org.apache.logging.log4j'
}
}
这样storm模块会报找不到log4j的错误
如果想要在主项目用另一种方式排除log4j:
dependencies {
//通用库
// implementation rootProject.ext.libraries['spring-boot-starter']
//在这里排除依赖没有用
implementation (rootProject.ext.libraries['spring-boot-starter-actuator']){
exclude group:'',module:''
}
}
这样也不可行,通过依赖分析相关工具,发现这样并不能将子模块的相关依赖进行排除
最后解决,在子模块(即storm模块)build.gradle文件中加入排除语句
configurations {
// 所有需要忽略的包定义在此
compile.exclude module: 'spring-boot-starter-logging'
}
4、引入log4j成功后,可能会报错:
19/06/14 16:08:22 ERROR executor.Executor: Exception in task 2.0 in stage 1.0 (TID 5)
com.google.common.util.concurrent.ExecutionError: java.lang.NoSuchMethodError: com.lmax.disruptor.dsl.Disruptor.<init>(Lcom/lmax/disruptor/EventFactory;ILjava/util/concurrent/ThreadFactory;Lcom/lmax/disruptor/dsl/ProducerType;Lcom/lmax/disruptor/WaitStrategy;)V
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2232)
at com.google.common.cache.LocalCache.get(LocalCache.java:3965)
at com.google.common.cache.LocalCache$LocalManualCache.get(LocalCache.java:4764)
at org.apache.phoenix.jdbc.PhoenixDriver.getConnectionQueryServices(PhoenixDriver.java:241)
at org.apache.phoenix.jdbc.PhoenixEmbeddedDriver.createConnection(PhoenixEmbeddedDriver.java:147)
at org.apache.phoenix.jdbc.PhoenixDriver.connect(PhoenixDriver.java:221)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:208)
at org.apache.phoenix.mapreduce.util.ConnectionUtil.getConnection(ConnectionUtil.java:113)
at org.apache.phoenix.mapreduce.util.ConnectionUtil.getOutputConnection(ConnectionUtil.java:97)
at org.apache.phoenix.mapreduce.util.ConnectionUtil.getOutputConnection(ConnectionUtil.java:92)
at org.apache.phoenix.mapreduce.util.ConnectionUtil.getOutputConnection(ConnectionUtil.java:71)
at org.apache.phoenix.mapreduce.util.PhoenixConfigurationUtil.getUpsertColumnMetadataList(PhoenixConfigurationUtil.java:306)
at org.apache.phoenix.spark.DataFrameFunctions$$anonfun$1.apply(DataFrameFunctions.scala:49)
at org.apache.phoenix.spark.DataFrameFunctions$$anonfun$1.apply(DataFrameFunctions.scala:45)
at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:801)
at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:801)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:52)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:324)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:288)
at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:90)
at org.apache.spark.scheduler.Task.run(Task.scala:121)
at org.apache.spark.executor.Executor$TaskRunner$$anonfun$10.apply(Executor.scala:403)
at org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1405)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:409)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
因为disruptor包的版本低导致,使用新版本的包即可,先在相应依赖旁添加排除语句:
implementation (rootProject.ext.libraries['log4j-core']){
exclude group:'com.lmax', module:'disruptor'
}
在https://mvnrepository.com/中找较新的disruptor版本,并引入:
implementation rootProject.ext.libraries['disruptor']