Spring Cloud Data Flow
1 Spring Cloud Data Flow 介绍
1.Data flow 是一个用于开发和执行大范围数据处理其模式包括ETL,批量运算和持续运算的统一编程模型和托管服务。
2.对于在现代运行环境中可组合的微服务程序来说,spring cloud data flow是一个原生云可编配的服务。
使用spring cloud data flow,开发者可以为像数据抽取,实时分析,和数据导入/导出这种常见用例创建和编配数据通道 (data pipelines)。
3.Spring cloud data flow 是基于原生云对 spring XD的重新设计,该项目目标是简化大数据应用的开发。
Spring XD 的流处理和批处理模块的重构分别是基于 spring boot的stream 和 task/batch 的微服务程序。
这些程序现在都是自动部署单元而且他们原生的支持像 Cloud Foundry、Apache YARN、Apache Mesos和Kubernetes 等现代运行环境。
4.Spring cloud data flow 为基于微服务的分布式流处理和批处理数据通道提供了一系列模型和最佳实践。
特点
1.使用DSL,REST-APIs,Dashboard,和 drag-and-drop gui开发
2.独立的创建,单元测试,故障排除,和管理微服务程序
3.使用开箱即用的stream和task/batch应用迅速的构建数据通道
4.把微服务作为maven或者docker的构件
5.在不中断数据流的情况下扩展数据通道
6.在现代运行环境平台上编配以数据为中心的应用程序
7.利用度量,健康检查远程管理每一个微服务程序
架构
Spring cloud data flow 简化了应用程序的开发和部署 将精力集中到数据处理的用例上
主要的架构概念在 应用程序、data flow 服务器和目标运行环境上
应用程序有两个特点:
1.周期长的流处理,程序通过消息中间件消费和产生连续不断的数据
2.短周期的任务处理,程序处理有限的数据集合然后中断
取决于运行环境,应用程序可以有两种打包方式
1.spring boot 打成jar包可以托管在一个maven仓库,文件,http或者是其他spring资源实现
2.Docker
运行环境支持:
Cloud Foundry
Apache YARN
Kubernetes
Apache Mesos
2 Local Server for development
部署商提供了服务接口可以允许你拓展到其他平台(Docker Swarm)。
Data flow server 负责部署应用程序到运行环境。Data flow server为运行环境提供一个可执行的jar包。
Server主要职能
1.stream DSL(领域特定语言)用来描述多个应用数据流的流转逻辑
2.部署清单 用来描述应用程序在运行环境的映射(初始化实例数量,内存配置,数据分区)
多个应用之间的交互是通过消息来实现的
支持的消息中间件:
1.Apache Kafka
2.RabbitMQ
微服务的架构风格
Data flow server部署应用程序到目标运行环境遵从一致的微服务架构风格。
举例来说,流应用代表了高级别的应用程序 它由多个分别运行在自己进程的小微服务程序组成。每个微独 立于其他微服务进行扩展或者缩减,每个服务有自己的版本控制生命周期
Streaming 和 task都是基于微服务将spring boot作为基础类库。它让所有的微服务都支持像健康检查,安全,可配置日志,监控和管理以及打包可执行JAR包
对比其他架构平台:
Spring Cloud Data Flow的架构风格不同于其他流处理和批处理平台。例如Apache Spark,Apache Flink,和Google Cloud Dataflow 应用程序运行在特定的计算引擎集群里。
相比Spring Cloud Data Flow,这些计算引擎原生的给平台提供一个丰富的环境去执行复 杂的数据运算,但是在别的运行环境引入复杂性,往往是不需要的。这不意味着你用 Spring Cloud Data Flow 就不能做实时数据计算。
类似的,Apache Storm,Hortonworks DataFlow 和Spring Cloud Data Flow的前身,Spring XD,都指定了程序运行集群,每个产品的独特性,决定了你的代码要在平台上运行并进行健康检查确保长周期应用在运行失败的时候可以重新启动。通常,我们为了能正确的嵌入到集群执行框架需要实现框架指定接口。
流处理应用
然而Spring boot 为创建DevOps(开发运维)友好的微服务提供了基础,在spring生态系统中其他类库帮助我们创建基于微服务的流处理程序。其中特别重要的是Spring Cloud Stream。
Spring Cloud Stream 编程模型本质是为我们提供简单的方式去描述一个基于消息中间件的通讯的多输入输出应用程序。这些输入输出映射到kafka的topics 或者是 rabbitMq 的 exchange 和 queue上。通常程序配置会作为类库一部分提供一个source用来生成数据,一个process 用来消费和生产数据,一个sink来消费数据。
1.命令式编程模型
Spring Cloud Stream 是最紧密的整合了 Spring Integration 的命令事件模型。
这意味着你写代码去处理一个单一的事件回调
@EnableBinding(Sink.class)
public class LoggingSink {
@StreamListener(Sink.INPUT)
public void log(String message) {
System.out.println(message);
}
}
在例子中字符串消息来自输入频道,传送到log方法,@EnableBinding 注解是 用来将外部消息中间件跟输入频道结合起来。
2.功能编程模型
Spring Cloud Stream 可以支持其他的编程风格。使用反应式api传入传出的数据被处理为持续的数据流,它还定义了如何去处理独立的消息。你也可以使用运算符去描述从入站到出战数据流的功能性转变。在未来的版本将会支持Apache Kafka的KStream API的编程模型。
流
a)拓扑结构
Stream DSL 描述了系统中数据流转送的线性序列。例如,在stream定义中 http | transfomer | cassandra ,每一个管道符表示链接左右的应用程序.命名的频道可以用来路由或者分发数据到多个消息定义。
b) 并发性
程序会消费事件,Spring Cloud Stream暴露一个并发性设置去控制用来派发传入消息的线程池的大小
C) 分区
在数据处理中存在一个通用的模式,将程序间传送的数据进行分区。分区在状态式处理中是很重要的一个概念,无论是性能还是一致性的原因,都要保证所有相关数据在一块处理。
Spring Cloud Data Flow可以通过配置Spring Cloud Stream的输出输入的绑定来支持分区。Spring Cloud Stream 提供了一个通用的方式,用于将不同类型的中间件以统一的方式进行分区处理的用例。因此无论代理是否进行分区,都可以实现分区。
在Spring Cloud Data Flow中使用简单的分区策略,你只需要在部署stream的时候在stream中设置每个程序的实例数量和 partitionKeyExpression 生产者属性。partitionKeyExpression 识别在中间件上的消息的哪一部分用来作为key。一个数据抽取Stream可以定义成 http | averageprocessor | cassandra. 假定要发送给 http source的负载是一个json格式并且有一个字段名字叫 sensorId.用shell命令部署stream stream deploy ingest –propertiesFile ingestStream.properties 。内容为:
Deployer.http.count=3
Deployer.averageprocessor.count=2
app.http.producer.partitionKeyExpression=payload.sensorId
将会部署流,所有的数据按照配置的输入输出目标流过程序,而且保证独立的数据集合总是被运送到对应的average processor实例。
在这种情况下,默认算法是评估payload.sensorId%partitionCount,其中partitionCount是RabbitMQ的情况下的应用程序计数,以及Kafka情况下的主题的分区计数
D) 消息交付保证
streams是由使用spring Cloud Steam类库作为与底层消息中间件通讯的基础的程序所组成的。Spring cloud stream 会提供多个供应商的消息中间件进行选择配置。
在spring cloud stream 中binder是对程序跟中间件链接的抽象。
对消费应用来说,在消息处理过程中产生异常会有一个重试的策略。
Spring cloud stream 还支持一个为kafka 和rabbitmq binder实现的配置项,会将失败的消息和堆栈踪迹发送到一个死信队列
其他的消息交付保证是由供生产消费应用选择的消息中间件提供的。
分析
Spring Cloud Data Flow 了解到某些Sink应用程序会将计数数据写入到redis并且提供一个读取计数数据的REST端。计数器的类型支持:
Counter 计数接收的消息数量,可选择的将计数数据记录到分离的仓库中例如redis
Field Value Counter 计算消息有效内容中指定字段的唯一值得出现次数
Aggregate counter 存储总计数而且还会记录每分钟 每小时 每天 每月的总计数
重要的是要注意,聚合计数器中使用的时间戳可以来自消息本身的一个字段,所以无序的消息也可以被统计
Task应用程序
Spring Cloud Task 编程模型提供:
1.Task生命周期时间的持久化和退出状态码
2.生命周期钩子函数在任务执行前后执行
3.在任务周期中发出一个task事件到一个Stream
4.与Spring Batch Job集成
3 Data Flow Server
1.端
Data Flow Server使用一个嵌入式的servlet容器并且暴露REST端去创建,部署,卸载,销毁Streams和Tasks,查询运行状态,数据分析等等。
Data Flow Server的实现是使用spring mvc框架和遵从HATEOAS原则的spring HATEOAS库去创建REST表现
2.定制化
我们提供一个可执行的Data Flow Server jar包指向一个单一的运行环境。Data Flow Server 委托到ClassPath去寻找部署商的SPI实现。
虽然我们为每一个目标运行环境提供了一个可执行jar的服务器,
你也可以使用spring initialzr创建你自己的定制化服务器这可以让你在我们提供的可执行jar包添加或删除相关功。
3.安全
Data Flow Server 可执行jar包支持基于http, LDAP(S), File-based, and OAuth 2.0 authentication 的方式去访问他。
运行环境
1.容错
Data Flow支持的所有运行环境都应该有在失败后重启应用的能力。
Spring Data Flow在部署程序的时候设置运行环境的健康检查无论如何都是需要的。
应用的集合状态构成了stream的状态。如果一个程序失败了,stream的状态将由deployed变成 partial
2.资源管理
每一个运行环境允许你控制分配给每个程序的内存硬盘和CPU。
这个是通过每个运行环境中使用唯一关键名称的部署清单的配置文件。
3.运行时扩展
部署stream时,你可以为组成Stream的独立的应用设置实例的数量。
Stream部署后,每个目标运行环境允许你控制个别的应用的实例的数量。
使用APIs,UIs或者是命令行工具,你可以根据需要为运行环境扩展或者是减少实例数量。
4 demo
4.1 环境准备
a)Java1.8及以上
b)关系型数据库用来存储stream task和程序的状态(默认使用内嵌的H2)
c)Redis
d)Message broker (rabbitMq,kafka)
e)Maven
f)为了方便spring组件的使用建议使用(sts),以下操作基于sts
4.2 Data Flow Server
Spring Cloud Data Flow 支持多种运行环境(Cloud Foundry 、Apache YARN 、Kubernetes 、Apache Mesos、Local Server for development )本例中使用spring 的 LocalServer.
1.新建一个spring start project
2.输入项目信息
3.选择spring版本及项目依赖
Boot version : 1.4.4
项目依赖选择 Local Data Flow server
选下一步等待maven包及项目构建完成
4.在 spring boot main class上添加@EnableDataFlowServer 注解
@EnableDataFlowServer
@SpringBootApplication
public class DfServerApplication {
public static void main(String[] args) {
SpringApplication.run(DfServerApplication.class, args);
}
}
5.现在Data Flow服务器就搭建好了 (需要redis的支持)
6.然后到项目路径下边 执行 mvn spring-boot:run 服务器以端口9393启动
4.3 Data Flow shell
a)项目构建与Data Flow Server一致
b)第三步选择依赖的时候选择 data flow shell
c) 修改代码添加@EnableDataFlowShell注解
@EnableDataFlowShell
@SpringBootApplication
public class DfShellApplication {
public static void main(String[] args) {
SpringApplication.run(DfShellApplication.class, args);
}
}
d) 项目路径下执行 mvn spring-boot:run
dataflow config server http://localhost:9393
若server 在本地 且 已经启动则会直接连接。
4.4 创建streams
a)创建source
i.项目创建与server一致
ii.第三步选择依赖的时候选择 stream rabbit(若你使用的是kafka 择选择kafka)
iii.修改代码
@EnableBinding(Source.class)
@SpringBootApplication
public class LoggingSourceApplication {
@Bean
@InboundChannelAdapter(
value = Source.OUTPUT,
poller = @Poller(fixedDelay = “10000”, maxMessagesPerPoll = “1”)
)
public MessageSource timeMessageSource() {
System.out.println(new Date() +“logging-source==== execued”);
return () -> MessageBuilder.withPayload(new Date().getTime()).build();
}
public static void main(String[] args) {
SpringApplication.run(LoggingSourceApplication.class, args);
}
}
iv.到项目路径 执行mvn clean install
b). 创建processor
i.所有步骤跟source一样
ii.代码修改
@EnableBinding(Processor.class)
@SpringBootApplication
public class LoggingProcessorApplication {
@Transformer(inputChannel = Processor.INPUT,
outputChannel = Processor.OUTPUT)
public Object transform(Long timestamp) {
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:yy");
String date = dateFormat.format(timestamp);
System.out.println(date + "------------------------------logging-proccessor------------------------------- executed");
return date;
}
public static void main(String[] args) {
SpringApplication.run(LoggingProcessorApplication.class, args);
}
}
c). 创建sink
i.所有步骤跟source创建一样
ii.代码修改
@EnableBinding(Sink.class)
@SpringBootApplication
public class LoggingSinkApplication {
@MessageEndpoint
public static class LoggingMessageEndpoint {
@ServiceActivator(inputChannel = Sink.INPUT)
public void logIncomingMessages(@Payload String msg, @Headers Map<String, Object> headers) {
System.out.println("logging-sink**************"+ msg);
headers.entrySet().forEach(e -> System.out.println(e.getKey() + '=' + e.getValue()));
}
}
@StreamListener(Sink.INPUT)
public void loggerSink(String date) {
System.out.println("logging-sink Received: " + date);
}
public static void main(String[] args) {
SpringApplication.run(LoggingSinkApplication.class, args);
}
}
4.5 注册Stream app
执行 app register --name “demo” --type type --uri maven://:[:[:]]:
注册完毕后 可执行 app list 查看注册列表
4.6 创建stream并部署
1.创建stream
执行stream create --name “name” --definiation ‘a | b | c’
然后执行 stream list 就可以看到刚才定义的stream
2.部署stream
执行命令 stream deploy --name ‘name’
4.7 创建Task
a)项目创建步骤同source
b)第三步选择依赖时选择 Cloud Task
c).修改相关代码
@EnableTask
@EnableBatchProcessing
@SpringBootApplication
public class MyTaskApplication {
public static void main(String[] args) {
SpringApplication.run(MyTaskApplication.class, args);
}
}
创建jobConfiguration
@Configuration
public class JobConfiguration {
private static Log logger
= LogFactory.getLog(JobConfiguration.class);
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Bean
public Job job() {
return jobBuilderFactory.get(“job”)
.start(stepBuilderFactory.get(“jobStep1”)
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
logger.info("my Job was run");
return RepeatStatus.FINISHED;
}
}).build()).build();
}
}
d).到项目路径下执行 mvn spring-boot:run
4.8 部署task
a)注册app
app register --name my-job --type task --uri maven://:[:[:]]:
执行app list可以看到注册的task程序
b).创建task
task create myjob --difination ‘appname’
task list 可以看到刚刚创建的 task
c).运行task
task launch ‘taskname’
然后执行 task execution list 就可以看到执行过的task
具体文档加图示 可下载文档查看