必威体育Betway必威体育官网
当前位置:首页 > IT技术

Stream Processing: Apache Kafka的Exactly-once的定义 原理和实现

时间:2019-07-05 15:46:20来源:IT技术作者:seo实验室小编阅读:90次「手机版」
 

exactly

2018年,Apache Kafka以一种特殊的设计和方法实现了强语义的exactly-once和事务性。热泪盈眶啊!

这篇文章将讲解kafka中exactly-once和事务操作的原理,具体为

  • (1)exactly-once在kafka中的定义。
  • (2)数据生产者“幂等操作”,kafka的事务性以及exactly-once实现原理。
  • (3)exactly-once的流处理。

1. 什么是恰好一次exactly-once

exactly-once定义为: 不管在处理的时候是否有错误发生,计算的结果(包括所有所改变的状态)都一样。

所以,在计算的时候如果发生了一个错误,系统重新计算,重新计算的结果和没有错误发生所得到的结果是一样的,因为这些计算操作是“恰好一次的”。这有另外一个专业术语:“幂等操作”。

为什么exactly-once那么重要呢?(1)在流处理操作中,很多应用场景必须需要“恰好一次”的支持。比如生活着有一个很重要的使用场景:在转账给朋友的时候,用户只希望一次转账,如果不支持“恰好一次”,那么就无法保障在违背用户本意的情况下重复转账。(2)对于kafka而言,其是流处理平台的核心部件,因为kafka通常作为公司内部的消息系统中间件,是其他系统的消息传输的桥梁。(3)支持exactly-once操作可以解锁更过的应用,比如金融行业应用。

使用Kafka进行流处理通常主要包含三个步骤:根据topic读取数据 - 流操作 - 将结果保存到指定的topic下。Kafka的流处理支持无状态的流操作(stateless)和有状态的流操作(stateful),无状态的意思是流处理的时候只需要针对某一条消息进行处理,结果只受到这条消息的影响,比如在每一条消息后面追加字符“a”;有状态指的是在消息处理的时候需要保存前后多条消息的相关信息,结果受到多条消息的影响,比如count,average操作。所以有状态操作更加强大但是实现起来更加困难,特别是当它也支持“恰好一次”的时候。

在这里插入图片描述

如果不支持exactly-once操作,那么可能出现下面的错误:

(1)重复写入。下图所示左边为输入数据,中间为数据处理,右边是结果写入。现在计算出了结果并且成功写入,但是由于某些原因,系统没有正确识别成功写入结果这个信号,所以系统重试了,这样就导致了下面第二张图所示的结果:也就是计算结果重复写入。

在这里插入图片描述

在这里插入图片描述

(2)计算状态被多次更新。

如下图所示,箭头所指的是一个有状态的操作(前面已经讲到无状态操作和有状态操作),第一次计算的时候更新了该处的状态。那么如果因为某些原因第一次的计算有问题需要重新计算,箭头所指的状态会被再次更新,从而导致最终的计算结果不正确。因为正确的计算是状态只被更新一次。这里所说的状态似乎有一点抽象,举一个例子,在统计操作中,count++,可以表示成一个状态,每次来一个数据,就增加1个量。

在这里插入图片描述

(3)重复读入

第一个数据已经顺利读取,处理和结果写入,但是由于数据读取的原因,系统没有正确识别到第一次数据的读取,所以再次读取了相同的数据,再次计算并输出结果。此时如下面第二张图所示。这样同样的输入数据就产生了两个结果写入,而且如果中间的流操作是有状态的,这两个结果很可能是不一样的。

在这里插入图片描述

在这里插入图片描述

上面所阐述的问题,进一步说明了exactly-once的重要性。kafka提供了自己的exactly-once保证。

2. 要么都做,要么都不做

要么都做,要么都不做。做什么呢?体现在:(1)写出所有的计算结果 (计算结果写入到kafka指定的topic中).(2)所有状态的更新。(3)把输入的消息标记为已消费(这里的输入数据理解为kafka的消费者broker中pull数据)。对上面这三个,kafka使用另一种具有相同语义的方式表示,分别为:(1)将计算结果写入输出topic中(2)把更新操作写入“更新日志changelog”中(注意,操作的状态能够根据“更新日志”进行回滚,类似于mysql的更新日志,这个有别于普通的系统操作日志)(3)把消费的消息偏移量写入相应的topic中。这也就是Apache Kafka实现“要么都做,要么都不做”和exactly-once的总体设计思路

在这里插入图片描述

具体地,上面阐述关系到三个操作,分别为:

  1. 消息生产者提交数据到broker
  2. broker进行消息处理,
  3. 消费者消费数据

对于第一点,需要实现幂等操作以及多分区地原子写入。这里的“写入”指的是消息的producer向broker传入消息。这里不多讲“幂等”操作,可以简单理解为同一个消息,producer一次或者多次重复向broker传输,对broker的影响是一样的。多分区原子写入指的是,producer将多条消息一次向broker中的多个partition传输,原子性体现在要么这些消息都成功传入了,要么都没有传入。

在下面第一张图片中展示了kafka实现消息传输的幂等操作的原理。每一条消息除了消息的key和消息的值,还增加了两个字段,分别是producer的ID和一个全局唯一的序列号。这个序列号由broker生成,类似于流水号。在图片中,闪电表示消息的ack失败,消息重传,kafka根据消息的pid和seq来判断这条消息是否已经传过。因为pid和seq也同消息一样存在kafka的patition中的,所以不需要当心丢失问题。要启动kafka的幂等性,无需修改代码,默认为关闭,需要修改配置文件:enable.idempotence=true 同时要求 ack=all 且 retries>1。

在这里插入图片描述

对于第二点,需要实现:将模式“消息读入->消息处理->结果写出”作为事务操作,并且整个操作满足exactly-once。所谓的事务操作,也就是这个操作需要满足原子性,完整性,一致性和持久性。kafka在支持事务性的同时也保证了系统性能,这体现在它简单但是高效的设计和实现上面。下面分析kafka实现事务的原理。在下面第一张图片中,左下角表示事务日志,系统存在一个事务锁,在某一个事务开始之前需获取这个锁。左上角的T1,T2表示两个topic,P1和P2表示两个partition,也就是这个事务往两个不同的topic和两个不同的partition上面存储数据。看图片的右上角,第一行代码,首先告诉系统要开始一个事务,接着发送消息到broker相应topic和partition中,所有都正常且完成之后,提交这个事务。所有的这个过程都另外有相应的log。只有成功完成了这个事务之后,消费者才能消费这个事务所提交的消息。

在这里插入图片描述

实现事务的回滚需要借助changelogs的帮助,如下面第一张图片所示。changelogs是存储在相应的topic中。

在这里插入图片描述

对于第三点,需要实现,kafka消费者只读取已经标记为“成功提交”的数据,这句话隐含了另外一层意思,消息提交的状态有多种,而成功提交只是其中之一。这里的“提交”指的是producer向broker提交的消息。那么什么才能算是成功提交了呢?消息被partition的leader和其所有的follower成功记录了,才能算是成功提交了。成功提交所带来的好处就是不怕断电不怕机器故障,也就是高容错性。下面图片展示了kafka如何解决消费者重复读的问题。(1)消息的消费,(2)消息的处理,(3)把消息的处理结果发送到某一个topic中和(4)把偏移量的发送某一个topic中,它们被放到一个事务中,当所有这些成功之后,才能算是成功。注意到,消费者的偏移量是使用一个producer发送的,也就是把偏移量当成了一种消息在kafka集群中保存起来。这样的话,只要这个事务完成了,那么偏移量也成功保存了。

在这里插入图片描述

所以,对应下面第一张图片,不仅仅有changelogs,还有__consumer_offsets

在这里插入图片描述

默认情况下kafka的事务是关闭的,通过配置文件开启,需要

transactional.id=“unique-id”, 要求enable.idempotence=true.

启动exactly-once需要配置:processing.guarantee="exactly-once ", 默认是最少一次。

3. 脏数据

脏数据指的是producer把消息数据提交到了broker中,但是它们没有成功,此时这些数据依然存在broker中。为了避免让消费者消费这些脏数据,kafka设置了消息的隔离等级,可以通过配置文件,指定只有成功提交的数据才能被消费。配置为isolation.level=“read_committed”。默认是read_uncommitted。

参考

HTTPs://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/

https://www.confluent.io/blog/transactions-apache-kafka/

https://www.confluent.io/blog/enabling-exactly-kafka-streams/

https://www.confluent.io/kafka-summit-london18/dont-repeat-yourself-introducing-exactly-once-semantics-in-apache-kafka

https://www.youtube.com/watch?v=zm5A7z95pdE

相关阅读

java实现文件下载的两种方式

public HttpServletResponse download(String path, HttpServletResponse response) { try { // path是指欲

html实现画板

<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas width="500" height="500"id=

微信域名防封防屏蔽系统的API接口实现原理

近常常听到搞微商,微信项目的在叫苦,由于微信域名屏蔽,哀鸿遍野。微信官方在对微信中推广活动的第三方网页内容管控越来越严格,如果活

25行代码实现完整的RSA算法

25行代码实现完整的RSA算法   python3.X版本的请点击这里25行代码实现完整的RSA算法  网络上很多关于RSA算法的原理介绍,但是

python实现K_mean算法

# encoding: utf-8 ''' #!/usr/bin/env python @author: yudian @contact: [email protected] @file: k_means.py @time: 2018/12

分享到:

栏目导航

推荐阅读

热门阅读