1 项目中是怎么用消息队列的?

项目中有两处使用到了Kafka

  1. 就是做授信操作的时候, 授信的原始数据通过 写日志的方式 写入日志系统, flented读取日志,将信息发送到kafka, 然后做原始数据处理的 ganglia项目通过 拉取指定kafka消息, 处理数据
  2. ganglia系统会对源数据做存储,提取有用信息(分类,实时,非实时), 非实时直接计算存库, 实时的会通过kafka消息 发送到 vessel ,做一个,解耦,异步操作
    消息队列存在的意义也是其优点就三个: 解耦 异步 削峰
    消息队列的缺点:(1) 系统可用性降低; (2) 系统复杂性提高 (3) 一致性问题

Kafka的吞吐量大, 但是kafka缺点也很明显就是有可能消息重复消费(重复消费问题引出下面的幂等操作)

2 Kafka 怎样保证数据不丢失?怎样保证幂等?有哪些方法保证业务幂等?

保证数据不丢失
生产者有丢失数据的可能,但是我们可以通过配置保证消息的不丢失,而且在Kafka发送数据的时候,每次发送消息都会有一个确认反馈机制,确保消息正常被收到;
消费者通过offset commit 来保证数据的不丢失,kafka自己记录了每次消费的offset数值,下次继续消费的时候,接着上次的offset进行消费;

Kafka中的幂等
Producer在生产发送消息时,难免会重复发送消息。Producer进行retry时会产生重试机制,发生消息重复发送。而引入幂等性后,重复发送只会生成一条有效的消息。Kafka作为分布式消息系统,它的使用场景常见与分布式系统中,比如消息推送系统、业务平台系统(如物流平台、银行结算平台等),所以保证生产者最终只生产一条数据就特别重要,否则造成重复存储和计算,后果 比较严重。
影响Kafka幂等性的因素
使用Kafka时,需要确保Exactly-Once语义。分布式系统中,一些不可控因素有很多,比如网络、OOM、FullGC等。在Broker确认Ack时,出现网络异常、FullGC、OOM等问题时导致Ack超时,Producer会进行重复发送。
Kafka的幂等性是如何实现的

  1. 单会话幂等性: Kafka为了实现幂等性,它在底层设计架构中引入了ProducerID和SequenceNumber。
    ProducerID(pid):在每个新的Producer初始化时,会被分配一个唯一的ProducerID,这个ProducerID对客户端使用者是不可见的。
    SequenceNumber(seq):对于每个PID,该Producer发送数据的每个<Topic, Partition>都对应一个从0开始单调递增的Sequence Number

Kafka通过为每条消息增加一个Sequence Numbler,通过Sequence Numbler来区分每条消息。每条消息对应一个分区,不同的分区产生的消息不可能重复。所有Sequence Numbler对应每个分区
Broker端在缓存中保存了这seq number,对于接收的每条消息,如果其序号比Broker缓存中序号大1则接受它,否则将其丢弃。这样就可以实现了消息重复提交了。但是,只能保证单个Producer对于同一个<Topic, Partition>的Exactly Once语义。不能保证同一个Producer一个topic不同的partion幂等。

  1. 多会话幂等性: Kafka事务通过隔离机制来实现多会话幂等性;

为了使用事务,应用程序必须提供唯一的transactionalId,这个transactionalId通过客户端参数transactional.id来显式设置。事务要求生产者开启幂等特性,因此通过将transactional.id参数设置为非空从而开启事务特性的同时需要将enable.idempotence设置为true

3 如何保证消息队列的高可用?

项目中用的是kafka:
kafka是分布式架构,一般kafka会部署成集群,即部署多台broker。
Kafka集群的高可用
broker启动会尝试向zookeeper创建临时节点:/controller,第一个broker选举成功成为集群的controller,其余节点都会在/controller注册watcher监控controller状态;当controller挂掉,所有broker感知到,重新尝试选举controller
controller节点通过zookeeper监控各broker状态,如果有broker挂掉,也没事儿,因为那个broker上面的partition在其他机器上都有副本的,那么此时会重新选举一个新的leader出来,大家继续读写那个新的leader即可。这就有所谓的高可用性了

4 Kafka 如何保证消息的可靠性传输,顺序性传输啊?消息丢了怎么办?

Kafka数据的高可用,可保证消息的可靠性传输
kafka写入消息时,同一个topic的数据1、数据2、数据3写入不同的partion中。kafka的每个partion都会在其它机器上存储一个副本,作为这个partion的follower,当某个broker宕机时,会从ISR(kafka动态维护的一组同步副本)中取出一个follower作为leader,完成切换。

Kafka消息的顺序性传输:
kafka本身可以保证消息的顺序性传输, 在每个partition中, 消息存储是有序的.
topic里面的每个partition只会由一个线程消费,在分配的时候就已经指定好,如果有消费者线程加入或者退出,则会重新开始分配。

Kafka消息丢失问题

Kafka可以通过配置, 对 已提交的消息,做有限度的持久化保证

  • 消费端丢失数据:关闭自动提交offset,处理完之后手动提交移位
  • 生产端丢失数据:
    可以用的方式:
  1. acks 确认机制设置为1, producer等待Leader Broker的确认反馈, 成功即认为发送成功
  2. acks 确认机制设置为all, Producer同样需要等待Broker的确认,但是确认更为严格,需要所有的Partition(Leader + Replicas)都持久化数据后才返回确认信息;
  3. 当producer 发送的消息迟迟未得到acks反馈, 可能是因为缓冲区数据已经满了, 这个时候如果不希望数据丢失,那么我们需要将阻塞等待超时时间关闭, 让数据一直保持阻塞的状态才能保证数据的丢失(这属于消息积压, 需要增加消费者数量和Topic分区)

5 如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?

过期失效问题

kafka通过消息时间配置来决定 消息保留多久,默认是一周. 这kafka的吞吐量保证了系统中kafka队列中不可能会有失效的问题.

消息队列积压

出现这个情况的原因就是Kafka消费能力不足导致的, 我们可以通过增加Topic的分区数,并且同时提升消费者组的消费者数量, 消费者数=分区数

6 Kafka 吞吐量大的原因

  • 顺序读写

kafka的消息是不断追加到本地磁盘文件末尾的, 而不是随机的写入;

  • Page Cache

为了优化读写性能, Kafka利用了操作系统本身的 Page Cache, 就是利用操作系统自身的内存而不是JVM的空间内存, 读写速度可以得到极大的提升;

  • 零拷贝

** linux操作系统 “零拷贝” 机制使用了sendfile方法, 允许操作系统将数据从Page Cache 直接发送到网络,只需要最后一步的copy操作将数据复制到 NIC 缓冲区, 这样避免重新复制数据 **

  • 分区分段+索引

Kafka的message是按topic分类存储的,topic中的数据又是按照一个一个的partition即分区存储到不同broker节点。每个partition对应了操作系统上的一个文件夹,partition实际上又是按照segment分段存储的。这也非常符合分布式系统分区分桶的设计思想。
通过这种分区分段的设计,Kafka的message消息实际上是分布式存储在一个一个小的segment中的,每次文件操作也是直接操作的segment。为了进一步的查询优化,Kafka又默认为分段后的数据文件建立了索引文件,就是文件系统上的.index文件。这种分区分段+索引的设计,不仅提升了数据读取的效率,同时也提高了数据操作的并行度

  • 批量读写,批量压缩