kafka exactly-once
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的总体设计思路。
具体地,上面阐述关系到三个操作,分别为:
消息生产者提交数据到broker
broker进行消息处理,
消费者消费数据
对于第一点,需要实现幂等操作以及多分区地原子写入。这里的“写入”指的是消息的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
kafka exactly-once的更多相关文章
- Spark踩坑记——Spark Streaming+Kafka
[TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...
- 消息队列 Kafka 的基本知识及 .NET Core 客户端
前言 最新项目中要用到消息队列来做消息的传输,之所以选着 Kafka 是因为要配合其他 java 项目中,所以就对 Kafka 了解了一下,也算是做个笔记吧. 本篇不谈论 Kafka 和其他的一些消息 ...
- kafka学习笔记:知识点整理
一.为什么需要消息系统 1.解耦: 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余: 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险. ...
- .net windows Kafka 安装与使用入门(入门笔记)
完整解决方案请参考: Setting Up and Running Apache Kafka on Windows OS 在环境搭建过程中遇到两个问题,在这里先列出来,以方便查询: 1. \Jav ...
- kafka配置与使用实例
kafka作为消息队列,在与netty.多线程配合使用时,可以达到高效的消息队列
- kafka源码分析之一server启动分析
0. 关键概念 关键概念 Concepts Function Topic 用于划分Message的逻辑概念,一个Topic可以分布在多个Broker上. Partition 是Kafka中横向扩展和一 ...
- Kafka副本管理—— 为何去掉replica.lag.max.messages参数
今天查看Kafka 0.10.0的官方文档,发现了这样一句话:Configuration parameter replica.lag.max.messages was removed. Partiti ...
- Kafka:主要参数详解(转)
原文地址:http://kafka.apache.org/documentation.html ############################# System ############### ...
- kafka
2016-11-13 20:48:43 简单说明什么是kafka? Apache kafka是消息中间件的一种,我发现很多人不知道消息中间件是什么,在开始学习之前,我这边就先简单的解释一下什么是消息 ...
- Spark Streaming+Kafka
Spark Streaming+Kafka 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端, ...
随机推荐
- shell脚本,awk 根据文件某列去重并且统计该列频次。
a文件为 a a a s s d .怎么把a文件变为 a s d .怎么把a文件变为 a a a s s d 解题方法如下: 解题思路 [root@localhost study]# awk 'NR= ...
- XML解析(一) DOM解析
XML解析技术主要有三种: (1)DOM(Document Object Model)文档对象模型:是 W3C 组织推荐的解析XML 的一种方式,即官方的XML解析技术. (2)SAX(Simple ...
- (46)zabbix报警媒介:Jabber
Jabber有第三方插件,能让Jabber用户和MSN.YahooMessager.ICQ等IM用户相互通讯.因为Google遵从Jabber协议,并且Google已经将Gtalk的服务器开放给了其它 ...
- linux设备驱动程序 - 待解决问题记录
1.每个模式都有自己的内存映射,也即自己的地址空间?(P26) http://www.cnblogs.com/wuchanming/p/4360277.html (不知道是不是,没时间看)
- syslog命令
更多请关注 Linux命令大全 syslog 介绍 syslog是Linux系统默认的日志守护进程.默认的syslog配置文件是/etc/syslog.conf文件.程序,守护进程和内核提供了访问系统 ...
- Python日志(logging)模块,shelve,sys模块
菜鸟学python第十七天 1.logging 模块 logging模块即日志记录模块 用途:用来记录日志 为什么要记录日志: 为了日后复查,提取有用信息 如何记录文件 直接打开文件,往里写东西 直接 ...
- 数据结构( Pyhon 语言描述 ) — — 第7章:栈
栈概览 栈是线性集合,遵从后进先出原则( Last - in first - out , LIFO )原则 栈常用的操作包括压入( push ) 和弹出( pop ) 栈的应用 将中缀表达式转换为后缀 ...
- POJ:2753-Seek the Name, Seek the Fame
Seek the Name, Seek the Fame Time Limit: 2000MS Memory Limit: 65536K Description The little cat is s ...
- STM32中如何对printf函数重定向
通过USART1向计算机的串口调试助手打印数据,或者接收计算机串口调试助手的数据,接下来我们现STM32工程上的printf()函数,方便用于程序开发中调试信息的打印. 方法一:使用MicroLIB库 ...
- 03005_Tomcat
1.Tomcat下载 (1)Tomcat解压版:链接:Tomcat解压版 密码:0iw0 : (2)源码:链接:源码 密码:3o43 . 2.Tomcat的目录结构 (1)bin:脚本目录 ①启动 ...