首页 > 技术文章 > 【消息队列】【消息中间件】JMS,RocketMQ,Kafka

iCanhua 2019-05-07 13:37 原文

特性

消息中间件一般要解决的问题:

  • 发布订阅
  • 优先级消息队列
    • 如果是在内存中的队列,可以用堆做数据结构;
    • 因为消息中间件基本要存放磁盘,所以难以实现;
    • 消息中间件可以通过设置多种不同的队列,然后把不同的优先级放到不同的队列中;
  • 消息顺序消费
    • 消息完全按顺序可以单队列,单消费者
    • 消息按照事务有顺序,可以支持多队列实现,用事务id做哈希,同一个事务的在一个队列
  • 消息的过滤
    • broker端过滤,加大服务器负担,但是可以减少网络传输
    • consumer端过滤,无用的网络传输
  • 消息持久化
    • 数据库、KV系统、文件
    • 文件可以利用零拷贝,page cache提高性能
  • 消息高可用
  • 消息低延迟
    • pull模型,push模型,长轮训
  • 至少消费一次
  • 回溯消息
  • 堆积消息
  • 分布式事务
    • 如何保证事务,分布式一般可用几种都可以考虑,XA,TCC等
    • RocketMQ采用offset方式
  • 定时消息
    • 优先级做定时消息,磁盘难以实现
    • 可以按照精度,提供5s,10s等等在不同队列,FIFO实现
  • 消息重试
    • 失败原因是消息,那么可以让消息10s,20s,5min等间隔重试
    • 失败原因是下游系统,那么可以让topic sleep一段时间,减轻broker压力

高可用性

  镜像集群模式:其实这种不是真正的分布式,每台机器都需要存全量的数据,而且必须要做同步双写/多写,十分影响性能

  分布式Partition模式:类似Kafka:

  • 就是一个Topic可以分成多个Partition,不同Partition存不同数据可以存在不同的Broker上面
  • 每个Partition都有他们的Replica副本,也存在在不同的Broker上面
  • 每个而且他们之中会选举一个Leader,多个Follower出来。

  Master/Slave模式:差不多同镜像集群模式,但是可以多个Master,从而也是分布式的

零拷贝

参考我的文章:https://www.cnblogs.com/iCanhua/p/14674602.html

主要是介绍mmap和sendfile两种零拷贝:

  • 用户态和内核态切换的成本,他们是不同进程、线程处理的,所以有调度成本
  • 数据多次在用户态和内核态copy的成本。零拷贝可以做到减少拷贝
  • mmap比较适合小块文件传输,所以适合consumer一个个消息发出去过程
  • sendfile很好的利用DMA技术,所以大块文件比较适合

RocketMQ

  角色:Producer,Consumer,NameService,Broker

  Broker的高可用主要是依靠把Broker分为Master和Slave,当然可以多个Master,而每个节点上面的一个topic也是可以分为多个物理队列的,这点和Kafka不同。

  NameServer无状态,主要作用是维护Broker的路由信息,并和Producer、Consumer使用长链接同步。

  Consumer的信息存储在Master上面,包括offset,所以NameService无状态,而且消息堆积能力可以实现。

  Broker逻辑结构图片

  优势:以上设计特点是:

  • 磁盘访问并行化,减少磁盘竞争冲突
  • 虽然做到了随机写,但是读会是随机读
    • 但这个问题不会影响很大,因为随机读其实是跳跃读,局部性原理。
    • 最好机器内存大一些,可以让pageCache也大一些,增加缓存命中率
  • 先读consumerQueue再读commitLog开销大

  ConsumerQueue:如上图所示,一个Topic对应多个分区队列,实际消费过程中,基本是一个消费者一个分配一个分区队列。所以当分区数量和消费者数量一致的时候,增加消费者无法提高消费速率。

  ProcessQueue:消费者属于Pull模式,可以自己控制消费速率,每一次Pull数据都会放在JVM中的ProcessQueue中,当ProcessQueue大小达到一定门槛(可配置)后,不会再去拉取消息。

  高性能:高性能常见主要针对多topic场景,所以适合集团中间件

  • 写文件是顺序写,因为都写commit log所以就算很多topic都不会有性能问题
  • Consumer消费读取使用零拷贝,因为消费是属于小块数据传输的要求,所以用mmap比sendfile的效果要好

  定时消息:不支持任意定义定时消息,只支持5s,10s,30s类似的定时。

  • 不支持的原因是定时消息一般要排序,磁盘无法排序
  • 实现原理简单,只需要分别为他们做一个队列,尾插法,然后定时每秒扫描一下就好了。

  事务消息:事务消息使用的是二阶段提交。

  

  负载均衡

  • 发送者负载均衡,是按照轮训方式,对不同的分区进行发送消息
  • 消费者负责均衡,一个分区只能对应一个消费者,所以增加消费者不能大于队列数量,因为大于也无法获取分区进行消息消费

  部署模式

  • 单台Master
  • 多台Master
    • 性能最高,单台宕机不影响可用性,但影响部分消息实时性
  • 多台Master多台Slave异步复制
    • 异步复制采用的是Slave拉取Master的CommitLog
    • 类似MySql主从同步
  • 多台Master多台Slave同步双写
    • 性能会比异步复制低一些
    • 可以保证不会数据丢失,可用性高

  消息堆积:消息堆积会不会对生产和消费性能有影响呢?这得看情况,但首先要明确,一般消息是不会堆积的,所以在内存就会被消费掉,然后慢慢落盘。

  • 有slave情况下,不会有影响,因为master发现consumer在消费磁盘的数据的情况下,就会下达指令给consumer让它重路由到slave中去读取消息。
  • 无slave情况下,会瘦影响

Kafka

  同样由多个 broker 组成,每个 broker 是一个节点;

  分布式:创建一个 topic,这个 topic 可以划分为多个 partition,每个 partition 可以存在于不同的 broker 上,每个 partition 就放一部分数据。  这就是天然的分布式消息队列,就是说一个 topic 的数据,是分散放在多个机器上的,每个机器就放一部分数据。

  逻辑结构图片

  高可用:Kafka 0.8 以后,提供了 HA 机制,就是 replica(复制品) 副本机制。每个 partition 的数据都会同步到其它机器上,形成自己的多个 replica 副本。所有 replica 会选举一个 leader 出来,那么生产和消费都跟这个 leader 打交道,然后其他 replica 就是 follower。写的时候,leader 会负责把数据同步到所有 follower 上去,读的时候就直接读 leader 上的数据即可。

  高性能:同样是零拷贝,因为kafka是每个topic单独一个队列,所以如果很多topic的场景,就会变成随机写,性能会下降,所以kafka适合topic少的场景

刷盘策略:

  同步刷盘:用户线程先写到PageCache中,然后等待内核线程刷盘,再唤醒用户线程返回

  异步刷盘:用户线程写到PageCahce后立马返回,内核异步刷盘

JMS介绍

  Java消息服务是一个在 Java标准化组织JCP)内开发的标准(代号JSR 914)。2001年6月25日,Java消息服务发布JMS 1.0.2b,2002年3月18日Java消息服务发布 1.1,统一了消息域。

  JMS由以下元素组成。

JMS提供者
连接面向消息中间件的,JMS接口的一个实现。提供者可以是Java平台的JMS实现,也可以是非Java平台的面向消息中间件的适配器。
JMS生产者
创建并发送消息的JMS客户。
JMS消费者
接收消息的JMS客户。
JMS消息
包括可以在JMS客户之间传递的数据的对象
JMS队列
一个容纳那些被发送的等待阅读的消息的区域。队列暗示,这些消息将按照顺序发送。一旦一个消息被阅读,该消息将被从队列中移走。
JMS主题
一种支持发送消息给多个订阅者的机制。

Java消息服务应用程序结构支持两种模型:

在点对点或队列模型下,一个生产者向一个特定的队列发布消息,一个消费者从该队列中读取消息。这里,生产者知道消费者的队列,并直接将消息发送到消费者的队列。这种模式被概括为:

  • 只有一个消费者将获得消息
  • 生产者不需要在接收者消费该消息期间处于运行状态,接收者也同样不需要在消息发送时处于运行状态。
  • 每一个成功处理的消息都由接收者签收

发布者/订阅者模型支持向一个特定的消息主题发布消息。0或多个订阅者可能对接收来自特定消息主题的消息感兴趣。在这种模型下,发布者和订阅者彼此不知道对方。这种模式好比是匿名公告板。这种模式被概括为:

  • 多个消费者可以获得消息
  • 在发布者和订阅者之间存在时间依赖性。发布者需要创建一个订阅(subscription),以便客户能够购订阅。订阅者必须保持持续的活动状态以接收消息,除非订阅者创建了持久的订阅。在那种情况下,在订阅者未连接时发布的消息将在订阅者重新连接时重新发布。

 

推荐阅读