kafka的一些问题总结笔记

kafka的一些问题总结笔记

1.kafka在高并发的情况下,如何避免消息丢失和消息重复?

kafka动态维护了一个同步状态的副本的集合(a set of In-Sync Replicas),简称ISR。

在这个集合中的节点都是和leader保持高度一致的,任何一条消息只有被这个集合中的每个节点读取并追加到日志中,才会向外部通知说“这个消息已经被提交”。

只有当消息被所有的副本加入到日志中时,才算是“committed”,只有committed的消息才会发送给consumer,这样就不用担心一旦leader down掉了消息会丢失。

消息从leader复制到follower, 我们可以通过决定producer是否等待消息被提交的通知(ack)来区分同步复制和异步复制。

同步发送:

发出消息后,必须阻塞等待收到通知后,才发送下一条消息。

特点:同步发送模式虽然吞吐量小,但是发一条收到确认后再发下一条,既能保证不丢失消息,又能保证顺序。

异步发送:

一直往缓冲区写,然后一把写到队列中去。

特点:异步的可能会丢失数据。

1)使用同步模式的时候,有3种状态保证消息被安全生产,在配置为1(只保证写入leader成功)的话,如果刚好leader partition挂了,数据就会丢失。
2)还有一种情况可能会丢失消息,就是使用异步模式的时候,当缓冲区满了,如果配置为0(还没有收到确认的情况下,缓冲池一满,就清空缓冲池里的消息),数据就会被立即丢弃掉。

#####在数据生产时避免数据丢失的方法:

只要能避免上述两种情况,那么就可以保证消息不会被丢失。
1)就是说在同步模式的时候,确认机制设置为-1,也就是让消息写入leader和所有的副本。
2)还有,在异步模式下,如果消息发出去了,但还没有收到确认的时候,缓冲池满了,在配置文件中设置成不限制阻塞超时的时间,也就说让生产端一直阻塞,这样也能保证数据不会丢失。
在数据消费时,避免数据丢失的方法:如果使用了storm,要开启storm的ackfail机制;如果没有使用storm,确认数据被完成处理之后,再更新offset值。低级API中需要手动控制offset值。

2.kafka怎么保证数据消费一次且仅消费一次

kafka支持3种消息投递语义:

  • At most once——最多一次,消息可能会丢失,但不会重复
  • At least once——最少一次,消息不会丢失,可能会重复
  • Exactly once——只且一次,消息不丢失不重复,只且消费一次。

但是整体的消息投递语义需要Producer端和Consumer端两者来保证。

Exactly Once实现原理

下面详细说说exactly once的实现原理。

Producer端的消息幂等性保证

每个Producer在初始化的时候都会被分配一个唯一的PID,
Producer向指定的Topic的特定Partition发送的消息都携带一个sequence number(简称seqNum),从零开始的单调递增的。

Broker会将Topic-Partition对应的seqNum在内存中维护,每次接受到Producer的消息都会进行校验;
只有seqNum比上次提交的seqNum刚好大一,才被认为是合法的。比它大的,说明消息有丢失;比它小的,说明消息重复发送了。

以上说的这个只是针对单个Producer在一个session内的情况,假设Producer挂了,又重新启动一个Producer被而且分配了另外一个PID,
这样就不能达到防重的目的了,所以kafka又引进了Transactional Guarantees(事务性保证)。

Transactional Guarantees 事务性保证

kafka的事务性保证说的是:同时向多个TopicPartitions发送消息,要么都成功,要么都失败。

为什么搞这么个东西出来?我想了下有可能是这种例子:
用户定了一张机票,付款成功之后,订单的状态改了,飞机座位也被占了,这样相当于是
2条消息,那么保证这个事务性就是:向订单状态的Topic和飞机座位的Topic分别发送一条消息,
这样就需要kafka的这种事务性保证。

这种功能可以使得consumer offset的提交(也是向broker产生消息)和producer的发送消息绑定在一起。
用户需要提供一个唯一的全局性TransactionalId,这样就能将PID和TransactionalId映射起来,就能解决
producer挂掉后跨session的问题,应该是将之前PID的TransactionalId赋值给新的producer。

Consumer端

以上的事务性保证只是针对的producer端,对consumer端无法保证,有以下原因:

  1. 压实类型的topics,有些事务消息可能被新版本的producer重写
  2. 事务可能跨坐2个log segments,这时旧的segments可能被删除,就会丢消息
  3. 消费者可能寻址到事务中任意一点,也会丢失一些初始化的消息
  4. 消费者可能不会同时从所有的参与事务的TopicPartitions分片中消费消息

如果是消费kafka中的topic,并且将结果写回到kafka中另外的topic,
可以将消息处理后结果的保存和offset的保存绑定为一个事务,这时就能保证
消息的处理和offset的提交要么都成功,要么都失败。

如果是将处理消息后的结果保存到外部系统,这时就要用到两阶段提交(tow-phase commit),
但是这样做很麻烦,较好的方式是offset自己管理,将它和消息的结果保存到同一个地方,整体上进行绑定,
可以参考Kafka Connect中HDFS的例

3.kafka保证数据一致性和可靠性

数据可靠性保证

当Producer向Leader发送数据时,可以通过acks参数设置数据可靠性的级别:

  • 0: 不论写入是否成功,server不需要给Producer发送Response,如果发生异常,server会终止连接,触发Producer更新meta数据;
  • 1: Leader写入成功后即发送Response,此种情况如果Leader fail,会丢失数据
  • 1: 等待所有ISR接收到消息后再给Producer发送Response,这是最强保证仅设置acks=-1也不能保证数据不丢失,当Isr列表中只有Leader时,同样有可能造成数据丢失。要保证数据不丢除了设置acks=-1, 还要保 证ISR的大小大于等于2

request.required.acks:设置为-1 等待所有ISR列表中的Replica接收到消息后采算写成功; min.insync.replicas: 设置为大于等于2,保证ISR中至少有两个Replica Producer要在吞吐率和数据可靠性之间做一个权衡

数据一致性保证

一致性定义:若某条消息对Consumer可见,那么即使Leader宕机了,在新Leader上数据依然可以被读到

  • HighWaterMark简称HW: Partition的高水位,取一个partition对应的ISR中最小的LEO作为HW,消费者最多只能消费到HW所在的位置,另外每个replica都有highWatermark,leader和follower各自负责更新自己的highWatermark状态,highWatermark <= leader. LogEndOffset
  • 对于Leader新写入的msg,Consumer不能立刻消费,Leader会等待该消息被所有ISR中的replica同步后,更新HW,此时该消息才能被Consumer消费,即Consumer最多只能消费到HW位置

这样就保证了如果Leader Broker失效,该消息仍然可以从新选举的Leader中获取。对于来自内部Broker的读取请求,没有HW的限制。同时,Follower也会维护一份自己的HW,Folloer.HW = min(Leader.HW, Follower.offset)

4.kafka到spark Streaming怎么保证数据完整性,怎么保证数据不重复消费?

保证数据不丢失(at-least)
spark RDD内部机制可以保证数据at-least语义。

Receiver方式
开启WAL(预写日志),将从kafka中接受到的数据写入到日志文件中,所有数据从失败中可恢复。

Direct方式
依靠checkpoint机制来保证。

保证数据不重复(exactly-once)
要保证数据不重复,即Exactly once语义。

  • 幂等操作:重复执行不会产生问题,不需要做额外的工作即可保证数据不重复。
  • 业务代码添加事务操作

5.kafka的消费者高阶和低阶API有什么区别?

​ Kafka消息消费有两个consumer接口,Low-level API和High-level API:

Low-level API:消费者自己维护offset等值,可以实现对Kafka的完全控制,各种消息传递语义;

High-level API:封装了对parition和offset的管理,不需要自己管理offset,默认实现最少一次消息传递语义(At least once)comsumer数量大于 partition数量,浪费 comsumer数量小于partition数量,一个comsumer对应多个partition,最好partition数目是consumer数目的整数倍;

如果使用高级接口High-level API,可能存在一个问题就是当消息消费者从集群中把消息取出来、并提交了新的消息offset值后,还没来得及消费就挂掉了,那么下次再消费时之前没消费成功的消息就“诡异”的消失了;

解决办法:

​ 针对消息丢失:同步模式下,确认机制设置为-1,即让消息写入Leader和Follower之后再确认消息发送成功;异步模式下,为防止缓冲区满,可以在配置文件设置不限制阻塞超时时间,当缓冲区满时让生产者一直处于阻塞状态;

​ 针对消息重复:将消息的唯一标识保存到外部介质中,每次消费时判断是否处理过即可。

6生产者和消费者时候如何保证数据不丢失

生产者如何保证数据的不丢失

kafka的ack机制:

在kafka发送数据的时候,每次发送消息都会有一个确认反馈机制,确保消息正常的能够被收到。

同步模式:

ack机制能够保证数据的不丢失,如果ack设置为0,风险很大,一般不建议设置为0

producer.type=sync

request.required.acks=1 //只leader

# 当所有的follower都同步消息成功后发送ack

request.required.acks=-1

异步模式:

通过buffer来进行控制数据的发送,有两个值来进行控制,时间阈值与消息的数量阈值,如果buffer满了数据还没有发送出去,如果设置的是立即清理模式,风险很大,一定要设置为阻塞模式。

结论:

生产者如何保证数据的不丢失

producer有丢数据的可能,但是可以通过配置保证消息的不丢失。

producer.type=async 异步模式

request.required.acks=1 需要ack校验机制

queue.buffering.max.ms=5000 队列最大缓存时间大一些5秒

queue.buffering.max.messages=10000 队列最大缓存消息数量大些10000

queue.enqueue.timeout.ms = -1 进入队列超时时间设置为永不超时

batch.num.messages=200 每一批处理消息的数量设置小些200

消费者如何保证数据的不丢失

设置不自动提交,通过offset commit 来保证数据的不丢失,kafka自己记录了每次消费的offset数值,下次继续消费的时候,接着上次的offset进行消费即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值