人们想要高吞吐,低延迟处理数据,以前的storm只能低延迟,做不到高吞吐,spark Streaming可以高吞吐,但是更多的场景是要根据事件数据切割,或者说要实现比较复杂。
deploy 部署,可以单机,基于yarn,基于云
core 分布式数据流处理
CEP 就是复杂事件处理,一般就是比如说一条流中的两个数据有关联才用到。
Flink 的分布式特点体现在它能够在成百上千台机器上运行,它将大型的计算
任务分成许多小的部分,每个机器执行一部分
TaskManager JobManager 都第三次了不再细说
在数据流方面 spark 面对批处理和流处理是两套框架 flink则是全是流(把批当成流的一种特殊形式)
我的非官方理解:第一,slot相当于是把taskManager分成了多分,比如说,当把map算子的并行度设置成2时,那么就有两个slot中包含该算子,第二,每一个taskManager是一个JVM进程,但是taskManager有时会有多个,这是因为你的slot设置数量小于你设置的最大并行度的数量, 即taskManager的数量是Job的最大并行度除以每个TaskManager分配的任务槽数。
StreamExecutionEnvironment.getExecutionEnvironment
创建一个执行环境,表示当前执行程序的上下文。 如果程序是独立调用的,则
此方法返回本地执行环境;如果从命令行客户端调用程序以提交到集群,则此方法
返回此集群的执行环境,也就是说,getExecutionEnvironment 会根据查询运行的方
式决定返回什么样的运行环境,是最常用的一种创建执行环境的方式。
StreamExecutionEnvironment.createLocalEnvironment
StreamExecutionEnvironment.createRemoteEnvironment
返回集群执行环境,将 Jar 提交到远程服务器。需要在调用时指定 JobManager
的 IP 和端口号,并指定要在集群中运行的 Jar 包。
readTextFile(path)
readFile(fileInputFormat, path)
env.socketTextStream(“localhost”, 11111)
env.fromCollection(list)
env.fromCollection(iterator)
env.fromElement(对象)
map filter 简单的不再说
//KeyBY
KeyStream<类,tuple> a=data.keyBy("id")
KeyStream<类,T> a=data.keyBy(data->data.getId)
KeyStream<类,T> a=data.keyBy(类::getId)
//max
DataStream<类> resultStream=a.max("temperature");
//maxBy 和max的区别就是maxBy返回的值带着该数据的全部值,而max除了那个求最大那个数据,其他数据都是流中接收的第一个数据
reduce向这种需要有界的进行聚和必修要先聚合,group by key by 这两个先聚合,至于这两个有啥区别,俺也不太清楚,用的时候group by针对的是DataSet ,keyBy针对的是DataStream分流:filter , split(过期,不建议),outputTag;
聚合流:Connect(只能连接两条流,但流的类型可以不一样ConnectedStreams会对两个流的数据应用不同的处理方法,且双流之间可以共享状态。connect经常被应用在对一个数据流使用另外一个流进行控制处理的场景上。)
connect如何用呢?先把他们都放到connect,然后再开始通过其他算子进行合并操作。
union(可连接多条流,但是流的类型必须一样)
滚动聚合算子 sum min max minBy maxBy
时间
Processsing,IngestionTime,EventTime
第一个,过程 就是说到达算子的时间,也是flink默认时间
第二个,摄取时间 就是说到达source的时间
第三个,事件时间,一般在数据流中包含,这个时间是自己定义的呢。
window api
1滚动窗口
简单的用法就不说了
“windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5), Time.seconds(2) ))”
正常情况下,滚动只传一个参数,但是这个却传入了两个参数,第二个参数表示的偏移量
举个例子,拿上面那个数据简单来说首先要知道,0,5,10,15…60,0,5 flink是在这些整秒进行关窗操作,即使你是从第三秒开始计时,那么第一次关窗也就是第五秒。但是当你设置第二个参数的话,那么就是从2,7,12开始关窗。
所以是不是觉得这个参数大部分呢情况下没有卵用,但是这个官方说了
input
.keyBy()
.window(TumblingEventTimeWindows.of(Time.days(1), Time.hours(-8)))
.();
2滑动窗口
3会话窗口
4全局窗口
计数窗口(.countWindow(10,2))10个数统计一次,划动两个,再统计一次。
窗口函数
增量聚合函数(ReduceFunction)AggregateFunction和reduceFunction区别是,他这个里边可以传个累加器。
全窗口函数
先把所有窗口函数数据收集起来,等到计算的时候会遍历所有的数据
processWindowFunction
WindowFunction
apply
.trigger()触发器
.evictor移除器
.allowedLateness允许处理迟到的数据
.sideOutputLateData将迟到的数据放入测输出流
.getSideOutput获取侧输出流。
watermark水位线
针对于事件时间
如何传递的呢?
上游广播给下游,
简单来说,每个算子有多个分区,然后有个partitionWM用来保存水位线,每到一个水位线,就判断是否广播,然后每次广播的是最小的水位线。广播过的不再广播。
第一个就不用说了,常用的,就是来一个数据,这个数据带着watermark;
第二个周期性,等于说是过一定的时间,生成个watermark;
第三个是断点式,就是来个数据,我判断一下是不是要生成watermark;
状态:干啥子?
1 数据流中的数据有重复,想对重复数据去重,需要记录哪些数据已经流入过应用,当新数据流入时,根据已流入过的数据来判断去重。
2 检查输入流是否符合某个特定的模式,需要将之前流入的元素以状态的形式缓存下来。比如,判断一个温度传感器数据流中的温度是否在持续上升。
3 对一个时间窗口内的数据进行聚合分析,分析一个小时内某项指标的75分位或99分位的数值。
托管状态(Managed State)和原生状态(Raw State)。从名称中也能读出两者的区别:Managed State是由Flink管理的,Flink帮忙存储、恢复和优化,Raw State是开发者自己管理的,需要自己序列化。
我的理解:本来你运行这个项目并行度3,现在重启了,设置并行度为4,Managed就自己把状态搞好了,不用你考虑传输和分配问题,所以平时用ManagedState就行了,row别用,用了也不会。
在之前各算子的介绍中曾提到,为了自定义Flink的算子,我们可以重写Rich Function接口类,比如RichFlatMapFunction。使用Keyed State时,我们也可以通过重写Rich Function接口类,在里面创建和访问状态。对于Operator State,我们还需进一步实现CheckpointedFunction接口。
算子状态的存储 Liststate(列表状态) unionListState(联合列表状态) BroadcastState(广播状态)
区别:比如说两个分区 ,然后重启后设置为3个分区,那么这些状态该怎么从两个分区给三个分区呢? liststate 是先一一对应后把多出来的放到第三个分区里,unionListState是把这几个分区的算子状态合并到一块,然后都发给三个分区,然后这三个分区分别取他们需要的。
各个例子博客:https://blog.csdn.net/gym02/article/details/105755814
键控算子例子 valuestate例子
总结
1 open里定义state Descriptor
2 flatmap实现更新
public class CountWindowAverage extends RichFlatMapFunction<Tuple2<Long, Long>, Tuple2<Long, Long>> {
/**
* ValueState状态句柄. 第一个值为count,第二个值为sum。
*/
private transient ValueState<Tuple2<Long, Long>> sum;
@Override
public void flatMap(Tuple2<Long, Long> input, Collector<Tuple2<Long, Long>> out) throws Exception {
// 获取当前状态值
Tuple2<Long, Long> currentSum = sum.value();
// 更新
currentSum.f0 += 1;
currentSum.f1 += input.f1;
// 更新状态值
sum.update(currentSum);
// 如果count >=2 清空状态值,重新计算
if (currentSum.f0 >= 2) {
out.collect(new Tuple2<>(input.f0, currentSum.f1 / currentSum.f0));
sum.clear();
}
}
@Override
public void open(Configuration config) {
ValueStateDescriptor<Tuple2<Long, Long>> descriptor =
new ValueStateDescriptor<>(
"average", // 状态名称
TypeInformation.of(new TypeHint<Tuple2<Long, Long>>() {}), // 状态类型
Tuple2.of(0L, 0L)); // 状态默认值
sum = getRuntimeContext().getState(descriptor);
}
}
// ...
env.fromElements(Tuple2.of(1L, 3L), Tuple2.of(1L, 5L), Tuple2.of(1L, 7L), Tuple2.of(1L, 4L), Tuple2.of(1L, 2L))
.keyBy(0)
.flatMap(new CountWindowAverage())
.print();
// the printed output will be (1,4) and (1,5)
Flink on Yarn 在新版本新增了一种模式 flink on yarn application 模式 特定 原本在客户端要做的事放在了jobManager中执行,main()方法在集群中执行。客户端只需要负责发起部署请求即可。
flink on yarn application的优点在哪,不管是yarn-per-job 还是yarn-session模式,都是在客户端获取作业所需的依赖项,2通过执行环境分析逻辑得到JobGraph,这就导致了当多个用户在一个客户端上提交造成会吃掉更多的cpu和内存。
1 逻辑 2 指标 3 ETL
yarn可以通过8088上获取监控,也可以通过8081上调用;
例如 http://localhost:8081/jobmanager/metrics
flink Metrics提供了几种监控指标类型
Counter:计数器统计的一个指标的总量。只针对与int和long。
class MyCounter extend RichMapFunction[Long,Long]{
@tarnsient private var counter: Counter = _
override def open(parameters:Configuration):Unit={}
counter =getRuntimeContext()
.getMetricGroup()
.counter("MyCounter")
override def map(input :Long):Long={
if(input>0){counter.inc}
input;
}
}
Gauges(给旧思):Gauges: 可以支持任何类型的数据记录和统计,一般对map进行累加
class gaugeMapper extends RichMapFunction(String ,String){
@transient private var countValue=0
override def open(parameters:Configration):Unit={
getRuntimeContext()
.getMertricGroup()
.gauge[Int,ScalaGauge[Int]]("MyGauge",ScalaGauge[Int](()=>countValue))}
override def map(value :String):String={
countValue +=1
value
}
}
}
meter(米ter):记录算子接受数据的平均值
Histogram(黑丝tei grams): 直方图 主要是为了Long类型监控指标的分布情况。
特点:易于管理(单独的二进制文件,需要本地磁盘)
架构: pull(服务发现)
能够监控到内部情况,数据存在磁盘,同时他有个TSDB(时序数据库)
proQL特别牛,能够比如说(预测cpu4小时后的运行情况)
性能 : 数以百万的监控指标 每秒处理数十万的数据点。
架构可以这样理解 :中间是服务,左边是要拉取的指标,右边是监控和报警,retrieval拉取先到时序数据库TSDB中然后落到本地磁盘,通过HTTPserver提供给监控和Grafana 如果有网关则pushgateway,没网关,比如说服务器(Node Exporter) 就用jobs/ exporters
和普通的有一点不一样,需要分别从官网上,下载 普罗米修斯,pushgateway ,node_exporter
读取flink的指标
需要在conf中配置
vim flink-conf.yaml
把普罗米修斯中的 flink-metrics prometheus-1.12.0.jar 放到flink的lib中。
如果是session,一直启动的集群,必须是集群启动之前 per-job 或者application提交job时加载的类。
为什么不用flink webUI 第一,因为任务失败的时候,那个指标东西都没了,不能持久化存储,普罗米修斯也不能。
下载grafana
http_requests_total{instance="localhost:9090"}
范围查询
瞬时向量表达式和区间向量表达式。
http_requests_total{instance=“localhost:9090”}[5m] 5分钟内的
http_requests_total offset 5m 迁移5分。
聚合操作sum(http_requests_total)
(flink_jobmanager_job_uptime)-(flink_jobmanager_job_uptime offset 30s)
1 flink on yarn节点不固定,怎么监控的
通过pushgateway
2 监控有哪些?
job重启,失败,网络延迟
jobmanager,jvm,内存,io
taskmanager jvm 内存 io
背压 checkpoint rocksdb kafka
目的:保证数据的健康性
数据质量标准分类:1数据完整性 2数据一致性 3数据不重复性
如果是那种数仓 ods-dwd-dws-dwt-ads的话,
重复值
JVM原空间 taskmanager.memory.jvm-metaspace.size 默认256mb
jvm执行开销 taskmanager.memory.jvm-overhead.fraction 默认192mb
taskmanager.memory.jvm-overhead.max 默认1gb
总进程内存 *fraction
### 案例分析
基于Yarn模式,一般参数指定的是总进程内存,taskmanager.memory.process.size,比如指定为4G,每一块内存得到大小如下:
(1)计算Flink内存
首先,一个slot,一般是用一个cpu的核心数,要知道,当并行度设置为4,但是slot设置为2时,就会有两个taskManager,此时应该用4个cpu核心数,但是如果yarn是容量调度的时候就会出现问题,公平调度就没问题。如何改变呢?
这个4是咋来的呢?有4个container,因为jobmanager占用一个,仨个taskmanager
在capacity-scheduler.xml中进行配置。设置成Domin就行了,可以看到。这样cpu的数目就是slot的数目了。
配置文件:默认并行度
提交参数
代码
算子
全局并行度:
先让kafka积攒点数据,然后消费,看每秒多少数据,然后用总QPS/单并行度的处理能力=并行度
最好根据高峰时期QPS进行测压。
Source端并行度配置
数据源端是kafka Source的并行度设置为Kafka的topic的分区
Transform并行度配置
keyBy之前的算子和source一致
keyBy之后的算子 最好2的整数次幂
Sink端配置并行度,设置kafka topic.
开启增量检查点和本地恢复
具体调优,加上这两行代码,或者运行程序的时候配置
这里边会自动配置成他认为合适的配置,这个具体配置什么呢?
(State)就是啥意思呢?,flink运行的时候会有多个状态,比如分组多出来的状态呀啥的,这里具体我也没太明白。到底列族名表示啥玩意
1增大block块缓存 默认8M
这些在预定义里都定义过,也可以自己定义
1 检查点自增
2 本地恢复
3 预定义
4 块缓存
5 writebuffer的大小 每个列簇名对应一个writebuffer
6 level阈值大小 (配置writebuffer需要调整这个值,如果这个值小,则会导致索引太多)
7 writebuffer的数量,每个列簇对应的writebuffer的数量
8 4线程
9 合并数3个
10 开启索引分区功能
11 状态监测
checkpoint时间间隔一般设置分钟,
间隔 分钟,秒 (这个要根据需求判断,sink端是两提交模式,要想实时性好,就得一直保存点)
最小等待间隔:参考间隔,一半
超时时间:默认10分钟
保留ck,这样就可以把ck当作savapoint用了。
1 先关闭操作链,在mertics就可以看到了
上图中,NetworkBufferPool 就是floatingBuffersUsage ResultSubpartition就是ExclusiveBuffersUsage
除了in和out,也可以根据下表
第一:直接点mertics,就是上边说的那些
第二 : 开启或火焰图找看哪个类占用cpu时间长
第三:下面数据倾斜导致的反压
用GCViewer这个软件打开日志查看(日志从taskManagerUi那个页面下载)
解决的第一个方法 localKeyBy 在keyBy之前先进行一个本地预聚合。(主要就是先批量聚合一下)
我个人感觉这个和两阶段提交思想上没啥区别…
也就是说map,fliter就数据倾斜
这时候让flink任务强制进行shuffle.使用shuffle,rebalance或rescale算子即可将数据均匀分配,从而解决数据倾斜的问题。
因为使用了窗口,变成了有界数据(赞批)的处理,窗口默认是触发时才会输出一条结果发往下游,所以可以使用两阶段聚合的方式。
具体做法就是先打散再聚合。
当恢复的时候,如果增删算子,那不得必须指定一个UUID? 建议每个算子都给个UUID.
env.getconfig.enableObjectReuse
这个具体啥意思呢? 就是说默认对象重用不开启,比如说一个Stream流但是下方有两个map算子给他对接时,要关闭对象重用,因为每个map都是可能要改变这个值的,若开启对象重用,则会导致线程安全。
总结: 如果只有一条流的话可以开启对象重用,两条或者多流的话,得看看是不是其他流修改了对象数值,其他流不修改的话才能重用,比如说(filter)
比如说窗口为1天,划动1分钟,这样就会造成大量数据重叠
比如说内存为负呀啥的
就是配置呗
就是配置呗
就是配置呗
就是配置呗
这个没有预留足够的本机内存,这个比较难解决
1decline衰退
2expire
安装个插件MavenHelper
(1)flink的metrics 监控可以用普罗米修斯 加 grafa或者InfluxDB + grafa
(2) 程序写完后,造测试数据的工具DataFactory,datafaker,DBMonster,Data-Processer,Nexmark,Jmeter
总结 :FLINK SQL是未来主题
理想汽车:两个问题:一 T+1 离线计算出前面的,1是flink算的 二 生产线上两个流join,当两个事件的间隔时间不确定多大怎么处理,
设置一个合适的TTL,关联不到就直接关联表。这个想法和美团一样,冷热数据,
美团:实时数仓 Nau(钠五)
19年调研实时数仓 FLINKSQL
20年给业务对接 发现对FLINKSQL运维不太好
21年主要针对FLINkSQL运维
问题:两个流join大状态问题,采用冷热处理, (两天内叫热数据,直接用flinkSQL,其他的保存至kv中)
有状态SQL变更后,状态如何恢复?(正常情况下,应该暂停业务,重新消费,但是很多时候不想让自己原有的业务暂停服务)解法一 采用备用链路(就是同一个业务搞两份,现在备用上做回溯,当他的输出合适的时候,再切换对应的表) 解法二 旁路状态生成(和第一种差不多吧,只不过是部分) 解法三 历史状态迁移(不能保证数据的完整性)
快手:
之前一个小公司面试我,问我flink一些简单的问题没有回答出来,几个月没用到flink都快忘完了,今天回顾一下。
2010-2014年德国柏林大学等几个学校联合,发表stratophere这个项目,后来这几个人离开学校共同创建了一家DataArtisana的公司,主要业务就是stratophere
2014年12月,成为apache顶级项目
1高吞吐 低延迟
2exactly-once语义
3基于流式计算引擎处理批量数据的计算能力
4支持事件时间
5支持状态计算
6支持高度灵活的窗口
7基于轻量级分布式快照实现的容错-通过checkpoints中进行任务的自动恢复
8基于JVM实现独立的内存管理 不会因为JVMGC等问题而影响整个应用的运行
9SavePoints(保存点)
第一次学建议https://www.bilibili.com/video/BV1yZ4y1A74d这个老师讲的好,适合入门。
第二次学再看 https://www.bilibili.com/video/BV1gp4y1e71T 武老师讲的不适合第一次学。
调优https://www.bilibili.com/video/BV1Q5411f76P?p=2&spm_id_from=pageDriver
还有张力兵的flink书
flink中文社区 https://flink-learning.org.cn/ (我还没仔细研究过,里边有好的文章)