目录

一 数据乱序场景

1 数据源乱序

2 ETL造成乱序

二 Flink处理乱序数据方案

1 Watermark 和 Event Time 模式

2 提前创建保序任务

3 使用事务性 Sink保证下游数据时序

三 结语

       在数据处理领域,无论离线批处理领域还是实时流处理领域,数据时序性对于最终数据的准确性有着比较大的影响,因此乱序场景处理就显得很必要。在离线处理领域,典型的乱序数据会造成迟到的事实和迟到的维度场景发生,只不过相比于实时数据处理场景来说,离线数据对于乱序的忍耐性要明显高出很多。在实时处理领域,数据时序性的保证重要性进一步提升,乱序数据不仅对于ETL逻辑有着较大的影响,同时乱序数据还可能造成数据不一致、数据延迟以及数据丢失场景发生,进而影响数据可信度乃至可用性。由于乱序数据在数据处理领域影响深远,那么处理乱序数据就成为不可逃避的现实。乱序数据产生场景多种多样,对于不同乱序情况的处理手段也不尽相同,但总归一点,想要更好的处理乱序数据,我们要更清晰的认识乱序数据产生的情况。在本文中,笔者将结合个人工作经验对乱序场景及解决方案尝试进行归纳总结,目标站在更高的角度来审视数据时序性及衍生的解决方案,以便更好的服务业务,提升数据价值。

一 数据乱序场景

        数据乱序根据产生端不同可以分为”源端乱序“和”ETL乱序“两种情况。

1 数据源乱序

日志端乱序 日志端数据乱序是指在日志记录系统过程中,日志消息的顺序与其发生的实际顺序不一致的情况。造成日志乱序的原因可以是多方面的,主要包括:并发问题、异步处理、分布式系统、程序bug、写入异常、网络故障、缓冲区溢出、服务器故障等多种原因。由此可知,日志端数据乱序是无法完全避免的,同时也是数据处理必须面对的问题。 日志记录包含数据发生时间戳,消费端通过适度等待根据时间戳可以处理乱序数据。 Kafka乱序 为了保证发送kafka topic数据有序,一般情况我们会根据数据key将相同key的消息发送到不同分区,这在正常情况下可以保证kafka topic内数据有序性,但特殊情况下可能导致数据乱序。

生产端发送数据没有按key分区(比如生产端发送数据按照hash规则分配数据),造成kafka数据乱序; 当生产端是异步发送时,此时有消息发送失败,造成kafka数据乱序; 当 Broker 宕机出现问题,此时生产端有可能会把顺序消息发送到不同的分区,这时会发生短暂消息顺序不一致的现象。 kafka topic分区变更,增加分区或者减少分区后生产端发送数据到下游的hash规则改变,导致相同key数据前后不能发往同一个分区。 kafka topic分区单副本,当副本宕机,发送端发送消息失败,经过尝试过后还未及时恢复,生产端会将剩余消息路由到其他分区。

2 ETL造成乱序

        除了数据源本身乱序,对于一些特定的ETL动作也会对下游产生乱序数据,这种属于技术本身问题,无技术解决方案。

Join乱序 Flink SQL Join 左右流 一对多关系,右流使用的是 NoUniqueKey,NoUniqueKey 使用的是 MapState,而 MapState 无法保证数据顺序,所以查询这类结果会有乱序的情况。 聚合乱序 Flink SQL 中如果存在多次 Keyby 并且 Key 字段不一致也会导致乱序问题。 异步操作 在 Flink 中执行异步操作可能导致数据乱序。例如,在异步 I/O 操作中,处理元素的顺序可能与它们被发送到 Sink 的顺序不一致。

二 Flink处理乱序数据方案

        乱序数据无法避免,那么合理设置处理数据逻辑就成了必要方案,基于Flink来说,常规用来解决数据乱序的方案有以下几种情况。

1 Watermark 和 Event Time 模式

        在 Flink 中,合理设计Watermark规则,根据数据的事件时间戳推进水位线,使得系统能够正确处理乱序数据。同时可以考虑设置允许延时最大间隔和侧输出流能力进一步处理乱序数据。

2 提前创建保序任务

        

对于乱序数据,可以在处理之前对数据进行重排,使得数据按照事件时间顺序排列(最好的保序任务利用下游OLAP引擎的更新能力对迟到数据进行动态更新,只有这样才能保证数据的时效性和最终一致性)。针对FlinkSQL任务可以根据row_number创建保序任务,保证发送下游数据的顺序性,对于出现的已经发送下游数据,回撤之前数据,发送新数据替换。在后续处理中,考虑回撤对业务逻辑影响。

FlinkSQL保序任务:

set table.exec.state.ttl = 3600;

select

t.*

from (

select

t.*,

row_number()over(partition by order_id order by create_time asc) as rn

from tbl_order t

where t.status = 1

) t

where t.rn = 1

;

3 使用事务性 Sink保证下游数据时序

        对于 Sink 操作,可以选择使用支持事务性写入的 Sink,例如 Flink 提供的 Kafka 事务性 Sink 或者 Flink 提供的 TwoPhaseCommitSinkFunction,以确保数据写入的原子性和顺序性。

三 结语

        在数据处理领域面临乱序数据带来的ETL挑战是不可避免的,充分理解乱序发生场景才能更好的处理乱序数据。对于有哪些场景需要补充,读者可以留言或加微信,保证及时更新文档。

参考阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。