分布式消息队列 NSQ 和 Kafka 对比

谈谈分布式消息队列的一些特性,比较两种比较常用的消息队列——NSQ和Kafka

消息队列的作用

  1. 解耦,将一个流程加入一层数据接口拆分成两个部分,上游专注通知,下游专注处理
  2. 缓冲,应对流量的突然上涨变更,消息队列有很好的缓冲削峰作用
  3. 异步,上游发送消息以后可以马上返回,处理工作交给下游进行
  4. 广播,让一个消息被多个下游进行处理
  5. 冗余,保存处理的消息,防止消息处理失败导致的数据丢失

NSQ

组件

NSQ主要包含3个组件:

  • nsqd:在服务端运行的守护进程,负责接收,排队,投递消息给客户端。能够独立运行,不过通常是由 nsqlookupd 实例所在集群配置的
  • nsqlookup:为守护进程,负责管理拓扑信息并提供发现服务。客户端通过查询 nsqlookupd 来发现指定话题(topic)的生产者,并且 nsqd 节点广播话题(topic)和通道(channel)信息
  • nsqadmin:一套WEB UI,用来汇集集群的实时统计,并执行不同的管理任务

特性

  1. 消息默认不可持久化,虽然系统支持消息持久化存储在磁盘中(通过 –mem-queue-size ),不过默认情况下消息都在内存中
  2. 消息最少会被投递一次,假设成立于 nsqd 节点没有错误
  3. 消息无序,是由重新队列(requeues),内存和磁盘存储的混合导致的,实际上,节点间不会共享任何信息。它是相对的简单完成疏松队列
  4. 支持无 SPOF 的分布式拓扑,nsqd 和 nsqadmin 有一个节点故障不会影响到整个系统的正常运行
  5. 支持requeue,延迟消费机制
  6. 消息push给消费者

流程

单个nsqd可以有多个Topic,每个Topic又可以有多个Channel。Channel能够接收Topic所有消息的副本,从而实现了消息多播分发;而Channel上的每个消息被分发给它的订阅者,从而实现负载均衡,所有这些就组成了一个可以表示各种简单和复杂拓扑结构的强大框架。

Kafka

整体架构

角色

  • Producer:消息发布者,负责发布消息到Kafka broker
  • Consumer:消息消费者,向Kafka broker读取消息的客户端
  • Broker:Kafka集群中的一个服务器
  • Topic:每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。(物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)
  • Partition:Parition是物理上的概念,每个Topic包含一个或多个Partition
  • 每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)

Topic & Partition

Topic在逻辑上可以被认为是一个queue,每条消费都必须指定它的Topic,可以简单理解为必须指明把这条消息放进哪个queue里。为了使得Kafka的吞吐率可以线性提高,物理上把Topic分成一个或多个Partition,每个Partition在物理上对应一个文件夹,该文件夹下存储这个Partition的所有消息和索引文件。

Producer消息路由

Producer发送消息到broker时,会根据Paritition机制选择将其存储到哪一个Partition。如果Partition机制设置合理,所有消息可以均匀分布到不同的Partition里,这样就实现了负载均衡。
在发送一条消息时,可以指定这条消息的key,Producer根据这个key和Partition机制来判断应该将这条消息发送到哪个Parition。

Consumer Group

使用Consumer high level API时,同一Topic的一条消息只能被同一个Consumer Group内的一个Consumer消费,但多个Consumer Group可同时消费这一消息。

这是Kafka用来实现一个Topic消息的广播(发给所有的Consumer)和单播(发给某一个Consumer)的手段。一个Topic可以对应多个Consumer Group。如果需要实现广播,只要每个Consumer有一个独立的Group就可以了。要实现单播只要所有的Consumer在同一个Group里。用Consumer Group还可以将Consumer进行自由的分组而不需要多次发送消息到不同的Topic。

Consumer API

Low Level API/Assign

  • 指定目标 Partition
  • 指定消费的起始Offset
  • 指定每次消费的消息长度
  • 只能消费特定Topic中特定Partition中的消息

High Level API/Subscribe

  • 每个Consumer实例属于Consumer Group
  • 默认情况下,Consumer Group会顺序消费某Topic的所有信息
  • Offset存于Zookeeper或者Kafka或者自定义存储
  • 实现Rebalance机制

特性

  • 支持Replica持久化
  • 投递保证支持 at least one / at most one / exactly once
  • Partition / Comsumer Group内消息保证有序