Flink特点
- 批流统一
- 高吞吐
- 低延迟
- 保证Eactly-Once
- 丰富的编程API
时间语义
时间语义 是flink中用于时间推进和时间判断的机制
时间推进和时间判断 以什么为标准 就产出了两种不同的时间语义
- 以processing time为依据 则叫做处理时间语义
- 以event time为依据 则叫做事件时间语义
时间语义的设计意义
process(EventLog eventlog){Long eventTime = eventLog.getTimestamp();Long processTime = System.currentMillimise()//用户完全可以自己根据需求中的时间定义来进行相应的计算}
处理时间(processing time)语义
Processing Time 是指数据被Operator处理时所在机器的系统时间
处理时间遵循客观世界中时间的特性:单调递增 恒定速度 永不停滞 永不回退
事件时间(event time)语义
Event Time 是指在数据本身的业务时间(如用户行为日志中的用户行为时间戳):
Event Time 语义中 时间的推进完全由流入flink系统的数据来驱动:
数据中的业务时间推进到哪 flink就认为自己的时间推进到了哪:
它可能停滞 也可能速度不恒定 但也一定是单调递增不可回退
并行度相关概念和API
- 用户通过算子api所开发的代码 会被flink任务提交客户端解析成jobGraph
- 然后 jobGraph提交到集群JobManager 转化成ExecutionGraph(并行化后的执行图)
- 然后 ExecutionGraph中的各个task会以多并行实例(subTask)部署到taskmanager上执行
- subTask运行的位置是taskmanager所提供的槽位(task slot) 槽位简单理解就是线程
提示:
- 一个算子的逻辑 可以封装在一个独立的task中(可以有多个运行时实例:subTask);
- 也可以把多个算子的逻辑chain在一起后封装在一个独立的task中(可以有多个运行实例)
- 同一个task的不同运行实例 必须放在不同的task slot上运行
- 同一个task slot 可以运行多个不同task的各一个并行实例
- setParallelism 设置算子的并行度
- slotSharingGroup 设置算子的槽位共享组
- disableChaining 对算子禁用前后链合并
- startNewChain 对算子开启新链(即禁用算子前链合并)
分区算子:用于指定上游task的各并行subtask与下游task的subtask之间如何传输数据;
- 设置数据传输策略时 不需要显式指定partitioner 而是调用封装好的算子即可
- dataStream.global();全部发往第1个task
- broadcast广播
- forward上下游并发度一样时一对一发送
- shuffle随机均匀分配
- rebalance Round-Robin(轮流分配)
- recale Local Round-Robin(本地轮流分配)
- partitionCustom 自定义单播
- keyBy 根据key的hashcode来进行hash分发
- 默认情况下 flink会优先使用REBALANCE分发策略
Flink Transformation
- Map算子:对DataStream中的数据依次取出来进行处理(做映射)
- 底层调用的是transformation方法 传入Operator名称(Map 返回数据类型和StreamMap并将自定义的计算逻辑传入到StreamMap)
- StreamMap类实现OneInputStreamOperator接口 必须重写processElement方法 数据是封装在StreamRecord 使用OutPut将处理完的数据输出
- StreamMap类还实现了AbstractUdfStreamOperator接口 用来约束该类传入的计算逻辑的类型(接口的类型) 只能传入MapFunction类型
- Filter算子 对数据过滤 保留计算逻辑返回为true的数据
- 底层调用的是transform方法 传入Operator名称(Fileter) 返回数据类型和StreamMap实例并将自定义的过滤逻辑传入到StreamFilter
- StreamMap类实现了OneInputStreamOperator接口 必须重写processElement方法 应用过滤逻辑 返回true就使用OutPut输出
- StreamMap类还实现了AbstractUdfStreamOperator接口 用来约束该类传入的计算逻辑的类型(接口的类型),只能传入FilterFunction类型
- FlatMap算子 对数据进行扁平化映射 可以 输出0到多条数据 输出数据用Collector的collect方法
- 底层调用的是transform方法 传入Operator名称(FlatMap) 返回数据类型和StreamFlatMap实例并将自定义的过滤逻辑传入到StreamFlatMap
- StreamMap类实现了OneInputStreamOperator接口 必须重写processElement方法 应用计算逻辑 如果一条返回多条 用Collector结合for循环将数据输出
- StreamMap类还实现了AbstractUdfStreamOperator接口 用来约束该类传入的计算逻辑的类型(接口的类型) 只能传入FlatMapFunction类型
- KeyBy按照key的hash对数据进行分区
- 可以保证key相同的一定进入到一个分区内 但是一个分区内可以有多key的数据
- 是对数据进行实时的分区 不是上游发送给下游 而是将数据写入到对应的channel的缓存中 下游到上游实时拉取
- KeyBy底层是new KeyedStream 然后将父DataStream包起来 并且传入keyBy的条件(keySelector)
- 最终会调用KeyGroupStreamPartitioner的selectChannel方法 将KeyBy的条件返回值传入到该方法中
- 步骤
- 先计算key的HashCode值(有可能会是负的)
- 将key的HashCode值进行特殊的hash处理 MathUtils.murmurHash(keyHash) 一定返回正数 避免返回的数字为负
- 将返回特殊的hash值模除以默认最大并行的 默认是128 得到keyGroupId
- keyGroupId * parallelism(下游的并行度) / maxParallelism(默认最大并行) 返回分区编号
- 步骤
- 优点:可以将数据尽量均匀分配到多个分区 并且避免key的hashCode为负数
- 注意: 1如果将自定义POJO当成key 必须重写hashcode方法 不能将数组当成keyBy的key
- Reduce将KeyedStream数据进行聚合
- 传入ReduceFunction 输入跟输出的类型保持一致
- 如果这个key在该分区中第一次出现 不会调用自定义的reduce方法
- 底层调用的是StreamGroupReduceOperator的processElement方法
- 将初始值或累计的中间结果以ValueState方法保存起来 如果状态不为null 然后通过多态的方式调用自定义的reduce方法 将reduce方法的返回值在更新到ValueState
- 然后使用OutPut将数据输出
- Sum对KeyedStream的数据进行聚合
- 底层先调用的是aggregate方法 传入SumAggregator 然后再调用reducefangfa
- 在reduce方法中 会根据数据的类型 调用具体的相加的方法 例如 IntSum LongSum
- Sum只能对数字类型的数据进行相加 有六种实现
- Min Max
- 只会返回KeyBy的字段和最小值 最大值 如果还有其他字段 返回的是第一次出现的值
- 底层也是调用reduce方法
- MinBy MaxBy
- 不但返回KeyBy的字段 还会返回最小值或最大值 如果有多个字段 还会返回最小值 或最大值所在数据的全部字段
- 底层也是调用reduce方法
- Union多个类型一样的DataStream合并到一起 使用同样的方式进行处理
- 可以union一到多个DataStream
- 如果自己Union自己 是将数据double
- Union后的DataStream没用指定分区 分区的数量为默认的并行度
- Connect可以将两个相同或不同类型的数据流包装到一起 得到一个新的数据流
- 分别调用两个方法对两个数据流中的数据进行操作
- 重要:可以让两个数据流共享状态
- 可以实现高级的功能 比如广播状态 inverval join
- Iterate用来做迭代计算 类似一个分布式for循环
- 可以指定一个更新模型 对输入的数据进行运算
- 还可以指定两个过滤判断条件
- 继续迭代的条件
- 退出迭代计算 输出数据的条件
- Project投影
- 功能类似于map 选择出你想要的数据
- 只能针对Tuple类型的DataStream
- 功能是取出想要的全部或部分字段 而且还可以改变字段的顺序
