跳转至

消息队列

为什么要使用消息队列?

  1. 业务解耦
  2. 异步处理
  3. 流量削峰

kafka是什么?

Kafka是高吞吐低延迟的高并发、高性能的消息中间件,配置良好的Kafka集群甚至可以做到每秒几十万、上百万的超高并发写入。Kafka是**一个分布式消息队列**。Kafka对消息保存时根据Topic进行归类,发送消息者称为Producer,消息接受者称为Consumer,此外kafka集群有多个kafka实例组成,每个实例(server)称为broker。无论是kafka集群,还是consumer都依赖于zookeeper集群保存一些meta信息,来保证系统可用性。

kafka如何做到高可用的?

从topic的Partition的副本来看:

上图中只有一个Topic,它有3个Partition。

Kafka 为什么不支持读写分离?

自 Kafka 2.4 之后,Kafka 提供了有限度的读写分离,也就是说,Follower 副本能够对外提供读服务。

  1. 业务场景不适用。读写分离适用于那种读负载很大,而写操作相对不频繁的场景,可 Kafka 不属于这样的场景。
  2. 同步机制。Kafka 采用 PULL 方式实现 Follower 的同步,因此Follower 与 Leader 存 在不一致性窗口。如果允许读 Follower 副本,就势必要处理消息滞后(Lagging)的问题。

如何解决kafka消息重复消费问题?

将消息的唯一标识保存到外部介质中,每次消费时判断是否处理过即可。这个解决办法适合其他消息系统。

Kafka消息是采用Pull模式,还是Push模式?

kafka遵循了一种大部分消息系统共同的传统的设计:producer将消息推送(push)到broker,consumer从broker拉取(pull)消息。同redis的bpop命令类似,Kafka有个参数可以让consumer阻塞知道新消息到达,可以防止consumer不断在循环中轮询。

kafka中如何防止消息丢失?

Kafka消息发送有两种方式:同步(sync)和异步(async),默认是同步方式,可通过producer.type属性进行配置。Kafka通过配置request.required.acks属性来确认消息的生产:

  • 0

    表示producer不等待来自broker同步完成的确认继续发送下一条消息;

  • 1

    表示producer在leader已成功收到的数据并得到确认后发送下一条message,默认状态

  • -1

    表示producer在header,follower副本确认接收到数据后才算一次发送完成;

综上所述,有6种消息生产的情况,下面分情况来分析消息丢失的场景:

(1)acks=0,不和Kafka集群进行消息接收确认,则当网络异常、缓冲区满了等情况时,消息可能丢失;

(2)acks=1、同步模式下,只有Leader确认接收成功后但挂掉了,副本没有同步,数据可能丢失;

可见在同步模式下,ack=-1时候,可以防止消息丢失。但这牺牲了吞吐量。

kafka中的 zookeeper 起到什么作用,可以不用zookeeper吗?

早期版本的kafka用zk做meta信息存储,consumer的消费状态,group的管理以及 offset的值。新的consumer使用了kafka内部的group coordination协议,也减少了对zookeeper的依赖,但是broker依然依赖于ZK,zookeeper 在kafka中还用来选举controller 和 检测broker是否存活等等。

kafka 为什么那么快?

  1. Page cache技术

    Kafka每次接收到数据都会往磁盘上去写。但并不是直接写入磁盘的,而是写入OS cache上面,然后在写到磁盘

  2. 顺序读写磁盘

    磁盘读写时候,是顺序读写的。此时数据在磁盘上存取代价为O(1)。

  3. 零拷贝技术

    Customer从broker读取数据,采用零拷贝技术。将磁盘文件读到OS内核缓冲区后,直接转到socket buffer进行网络发送。

    传统的数据发送需要发送4次上下文切换,采用sendfile系统调用之后,数据直接在内核态交换,系统上下文切换减少为2次。

Kafka中是怎么体现消息顺序性的?

kafka每个partition中的消息在写入时都是有序的,消费时,每个partition只能被每一个group中的一个消费者消费,保证了消费时也是有序的。整个topic不保证有序。如果为了保证topic整个有序,那么将partition调整为1。

kafka如何实现延迟队列?

kafka基于**时间轮**可以将插入和删除操作的时间复杂度都降为O(1)。

kafka中consumer group 是什么概念?

consumer group是Kafka实现单播和广播两种消息模型的手段。同一个topic的数据,会广播给不同的group;同一个group中的worker,只有一个worker能拿到这个数据。换句话说,对于同一个topic,每个group都可以拿到同样的所有数据,但是数据进入group后只能被其中的一个worker消费。group内的worker可以使用多线程或多进程来实现,也可以将进程分散在多台机器上,worker的数量通常不超过partition的数量,且二者最好保持整数倍关系,因为Kafka在设计时假定了一个partition只能被一个worker消费(同一group内)。

Kafka 中位移(offset)的作用?

在 Kafka 中,每个 主题分区下的每条消息都被赋予了一个唯一的 ID 数值,用于标识它在分区中的位置。这个 ID 数值,就被称为位移,或者叫偏移量。一旦消息被写入到分区日志,它的位移值将不能 被修改。

阐述下Kafka 中的领导者副本(Leader Replica)和追随者副本 (Follower Replica)的区别?

Kafka 副本当前分为领导者副本和追随者副本。只有 Leader 副本才能 对外提供读写服务,响应 Clients 端的请求。Follower 副本只是采用拉(PULL)的方 式,被动地同步 Leader 副本中的数据,并且在 Leader 副本所在的 Broker 宕机后,随时准备应聘 Leader 副本。

自 Kafka 2.4 版本开始,社区通过引入新的 Broker 端参数,允许 Follower 副本有限度地提供读服务。

消息传递语义是什么概念?

message delivery semantic 也就是消息传递语义。通用的概念,也就是消息传递过程中消息传递的保证性。分为三种:

  • 最多一次(at most once)

    消息可能丢失也可能被处理,但最多只会被处理一次。可能丢失,不会重复。

    只管发送,不管对方收没收到。

  • 至少一次(at least once)

    消息不会丢失,但可能被处理多次。可能重复 不会丢失。

    发送之后,会等待对方确认之后才会停止发送。

  • 精确传递一次(exactly once)

    消息被处理且只会被处理一次。不丢失,不重复,就一次。

介绍一下beanstalk?

beanstalk是轻量级的,易使用的,C语言实现的消息队列中间件。支持特性有:

  • 延迟(delay)

    延迟意味着可以定义任务什么时间才开始被消费

  • 优先级(priority)

    优先级就意味 支持任务插队(数字越小,优先级越高,0的优先级最高)

  • 持久化(persistent data)

    Beanstalkd 支持定时将文件刷到日志文件里,即使beanstalkd宕机,重启之后仍然可以找回文件

  • 任务超时重发(time-to-run)

    消费者必须在指定的时间内处理完这个任务,否则就认为消费者处理失败,任务会被重新放到队列,等待消费

Beanstalk由四部分构成:

  • 管道(tube)

    相当于kafka的Topic概念,是消息的归类。

  • 任务(job)

    相当于kafka中的消息

  • producer

    job的生产者,通过put命令来将一个job放到一个tube中

  • consumer

    job的消费者,通过reserve、release、bury、delete命令来获取job或改变job的状态

任务从进入管道到离开管道一共有5个状态(ready,delayed,reserved,buried,delete):

  1. 生产者将任务放到管道中,任务的状态可以是ready(表示任务已经准备好,随时可以被消费者读取),也可以是delayed(任务在被生产者放入管道时,设置了延迟,比如设置了5s延迟,意味着5s之后,这个任务才会变成ready状态,才可以被消费者读取)

  2. 消费者消费任务(消费者将处于ready状态的任务读出来后,被读取处理的任务状态变为reserved),可以设置reserved的时间,若在这段时间没有处理完成,那么任务会重新放回消息队列中,再次被别人消费

  3. 消费者处理完任务后,任务的状态可能是delete(删除,处理成功),可能是buried(预留,意味着先把任务放一边,等待条件成熟还要用),可能是ready,也可能是delayed,需要根据具体业务场景自己进行判断定义