Kafka消息队列

什么是消息队列?

消息队列中间件是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削锋等问题。实现高性能、高可用、可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。

市面上主流的消息队列有:ActiveMQ、RabbitMQ、ZeroMQ、Kafka、MetaMQ、RocketMQ等。

消息队列应用场景

场景分为异步处理、应用解耦、流量削锋和消息通讯四个场景。

异步处理

场景说明:用户注册后,需要发送注册邮件和发送注册信息,传统的做法有两种:串行方式、并行方式

串行方式:

将注册信息写入数据库成功后,发送注册邮件,然后发送注册短信,而所有任务执行完成后,返回信息给客户端

Kafka消息队列

并行方式:

将注册信息写入数据库成功后,同时进行发送注册邮件和发送注册短信的操作。而所有任务执行完成后,返回信息给客户端。同串行方式相比,并行方式可以提高执行效率,减少执行时间。

Kafka消息队列

使用消息队列:

Kafka消息队列

根据上述的流程,用户的响应时间基本相当于将用户数据写入数据库的时间,发送注册邮件、发送注册短信的消息在写入消息队列后,即可返回执行结果,写入消息队列的时间很快,几乎可以忽略,也有此可以将系统吞吐量提升至20QPS,比串行方式提升近3倍,比并行方式提升2倍。

应用解耦

场景说明:用户下单后,订单系统需要通知库存系统。

传统方式:

传统的做法为:订单系统调用库存系统的接口。如下图所示:

Kafka消息队列

传统方式具有如下缺点:

  1. 假设库存系统访问失败,则订单减少库存失败,导致订单创建失败
  2. 订单系统同库存系统过度耦合

使用消息队列:

Kafka消息队列

  • 订单系统:用户下单后,订单系统进行数据持久化处理,然后将消息写入消息队列,返回订单创建成功
  • 库存系统:使用拉/推的方式,获取下单信息,库存系统根据订单信息,进行库存操作。

假如在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其后续操作了。由此实现了订单系统与库存系统的应用解耦。

流量削峰

流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。

应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。
  1. 可以控制参与活动的人数;
  2. 可以缓解短时间内高流量对应用的巨大压力, 服务器在接收到用户请求后,首先写入消息队列。这时如果消息队列中消息数量超过最大数量,则直接拒绝用户请求或返回跳转到错误页面;

消息通讯

消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列、聊天室等。

点对点通讯:

Kafka消息队列

在点对点通讯架构设计中,客户端A和客户端B共用一个消息队列,即可实现消息通讯功能。

聊天室通讯

Kafka消息队列

客户端A、客户端B、直至客户端N订阅同一消息队列,进行消息的发布与接收,即可实现聊天通讯方案架构设计。

消息队列的两种模式

点对点模式

一对一,消费者主动拉取数据,消息收到后消息清除

消息生产者生产消息发送到Queue中,然后消息消费者从Queue中取出并且消费消息。消息被消费以后,queue 中不再有存储,所以消息消费者不可能消费到已经被消费的消息。Queue 支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费

Kafka消息队列

发布/订阅模式

一对多,消费者消费数据之后不会清除消息

消息生产者(发布)将消息发布到 topic 中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到 topic 的消息会被所有订阅者消费。

Kafka消息队列

市面上主流消息队列比较

性能比较

测试目的

对比Kafka、RabbitMQ、RocketMQ发送小消息(124字节)的性能。这次压测我们只关注服务端的性能指标

压测的标准

不断增加发送端的压力,直到系统吞吐量不再上升,而响应时间拉长。这时服务端已出现性能瓶颈,可以获得相应的系统最佳吞吐量。

Kafka消息队列

在同步发送场景中,三个消息中间件的表现区分明显:

Kafka的吞吐量高达17.3w/s,不愧是高吞吐量消息中间件的行业老大。这主要取决于它的队列模式保证了写磁盘的过程是线性IO。此时broker磁盘IO已达瓶颈。

RocketMQ也表现不俗,吞吐量在11.6w/s,磁盘IO %util已接近100%。RocketMQ的消息写入内存后即返回ack,由单独的线程专门做刷盘的操作,所有的消息均是顺序写文件。

RabbitMQ的吞吐量5.95w/s,CPU资源消耗较高。它支持AMQP协议,实现非常重量级,为了保证消息的可靠性在吞吐量上做了取舍。我们还做了RabbitMQ在消息持久化场景下的性能测试,吞吐量在2.6w/s左右。

测试结论

在服务端处理同步发送的性能上,Kafka>RocketMQ>RabbitMQ。

测试环境

服务端为单机部署,机器配置如下:

Kafka消息队列

应用版本

Kafka消息队列

测试脚本

Kafka消息队列

系统可靠性比较

测试目的

在消息收发的过程中,分别模拟Broker服务进程被Kill、物理机器掉电的异常场景,多次实验,查看极端情况下消息系统的可靠性。

测试场景

以下场景使用多个发送端向一个Topic发送消息,发送方式为同步发送,分区数为8,只启动一个订阅者。

场景1:模拟进程退出

在消息收发过程中,利用Kill -9 命令使Broker进程终止,然后重新启动,得到可靠性数据如下:

Kafka消息队列

注:以上测试场景中Kafka的异步刷盘间隔为1秒钟,同步发送需设置request.required.acks=1,否则会出现消息丢失。

在Broker进程被终止重启,Kafka和RMQ都能保证同步发送的消息不丢,因为进程退出后操作系统能确保将该进程遗留在内存的数据刷到磁盘上。实验中,Kafka出现了极少量的消息重复。再次可以确定此场景中,二者的可靠性都很高。

场景2:模拟机器掉电

在消息收发过程中,直接拔掉Broker所在的宿主机电源,然后重启宿主机和Broker应用。因受到机房断电限制,我们在本场景测试中使用的是普通PC机器。得到可靠性数据如下:

Kafka消息队列

异步刷盘

测试发现,即使在并发很低的情况下,Kafka和RMQ都无法保证掉电后不丢消息。这个时候,就需要改变刷盘策略了。我们把刷盘策略由“异步刷盘”变更为“同步刷盘”,就是说,让每一条消息都完成存储后才返回,以保证消息不丢失。

注:关于两种刷盘模式的详细区别可以参照文档最下方的说明

重新执行上面的测试,得到数据如下:

Kafka消息队列

同步刷盘

首先,设置同步刷盘时,二者都没出现消息丢失的情况。限于我们使用的是普通PC机器,两者吞吐量都不高。此时Kafka的最高TPS仅有500条/秒,RMQ可以达到4000条/秒,已经是Kafka的8倍。

为什么Kafka的吞吐量如此低呢?因为Kafka本身是没有实现任何同步刷盘机制的,就是说在这种场景下测试,Kafka注定是要丢消息的。但要想做到每一条消息都在落盘后才返回,我们可以通过修改异步刷盘的频率来实现。设置参数log.flush.interval.messages=1,即每条消息都刷一次磁盘。这样的做法,Kafka也不会丢消息了,但是频繁的磁盘读写直接导致性能的下降。

另外,二者在服务恢复后,均出现了消息重复消费的情况,这说明消费位点的提交并不是同步落盘的。不过,幸好Kafka和RMQ都提供了自定义消费位点的接口,来避免大量的重复消费。

测试结论

  1. 在Broker进程被Kill的场景, Kafka和RocketMQ都能在保证吞吐量的情况下,不丢消息,可靠性都比较高。
  2. 在宿主机掉电的场景,Kafka与RocketMQ均能做到不丢消息,此时Kafka的吞吐量会急剧下跌,几乎不可用。RocketMQ则仍能保持较高的吞吐量。
  3. 在单机可靠性方面,RocketMQ综合表现优于Kafka。

测试环境

服务端为单机部署,机器配置如下:

Kafka消息队列

应用版本:

Kafka消息队列

测试脚本:

Kafka消息队列

同步刷盘和异步刷盘的区别

Kafka消息队列

同步刷盘是在每条消息都确认落盘了之后才向发送者返回响应;而异步刷盘中,只要消息保存到Broker的内存就向发送者返回响应,Broker会有专门的线程对内存中的消息进行批量存储。所以异步刷盘的策略下,当机器突然掉电时,Broker内存中的消息因无法刷到磁盘导致丢失。

Kafka与其他消息中间件对比

数据可靠性

卡夫卡使用异步刷盘方式,异步复制/同步复制。Kafka的数据以分区为单位组织,意味着一个Kafka实例上会有几百个数据分区,Kafka同步Replication理论上性能会降低。

性能对比

卡夫卡单机写入TPS约在百万条/秒,消息大小10个字节。Kafka的TPS跑到单机百万,主要是由于Producer端将多个小消息合并,批量发向Broker。

单机支持的队列数

Kafka单机超过64个队列/分区,Load会发生明显的飙高现象,队列越多,load越高,发送消息响应时间变长。

消息投递实时性

Kafka使用短轮询方式,实时性取决于轮询间隔时间,0.8以后版本支持长轮询。

卡夫卡消费失败不支持重试。

严格的消息顺序

卡夫卡支持消息顺序,但是一台代理宕机后,就会产生消息乱序

定时消息

卡夫卡不支持定时消息

分布式事务消息

卡夫卡不支持分布式事务消息

消息查询

卡夫卡不支持消息查询

消息回溯

卡夫卡理论上可以按照偏移来回溯消息

消费并行度

Kafka的消费并行度依赖Topic配置的分区数,如分区数为10,那么最多10台机器来并行消费(每台机器只能开启一个线程),或者一台机器消费(10个线程并行消费)。即消费并行度和分区数一致。

消息轨迹

卡夫卡不支持消息轨迹

开源社区活跃度

卡夫卡社区更新较慢

券商端消息过滤

卡夫卡不支持代理端的消息过滤

消息堆积能力

消息堆积能力较强

开发语言友好性

卡夫卡采用斯卡拉编写

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!