特性
消息中间件一般要解决的问题:
- 发布订阅
- 优先级消息队列
- 如果是在内存中的队列,可以用堆做数据结构;
- 因为消息中间件基本要存放磁盘,所以难以实现;
- 消息中间件可以通过设置多种不同的队列,然后把不同的优先级放到不同的队列中;
- 消息顺序消费
- 消息完全按顺序可以单队列,单消费者
- 消息按照事务有顺序,可以支持多队列实现,用事务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),以便客户能够购订阅。订阅者必须保持持续的活动状态以接收消息,除非订阅者创建了持久的订阅。在那种情况下,在订阅者未连接时发布的消息将在订阅者重新连接时重新发布。