文章目录
-
- [1. 核心架构 ⭐⭐⭐⭐⭐](#1. 核心架构 ⭐⭐⭐⭐⭐)
- [2. 消息模型 ⭐⭐⭐⭐⭐](#2. 消息模型 ⭐⭐⭐⭐⭐)
- [3. 消息确认机制 ⭐⭐⭐⭐⭐](#3. 消息确认机制 ⭐⭐⭐⭐⭐)
- [4. 消息持久化 ⭐⭐⭐⭐⭐](#4. 消息持久化 ⭐⭐⭐⭐⭐)
- [5. 事务消息 ⭐⭐⭐⭐](#5. 事务消息 ⭐⭐⭐⭐)
- [6. 消息可靠性 ⭐⭐⭐⭐⭐](#6. 消息可靠性 ⭐⭐⭐⭐⭐)
- [7. 性能优化 ⭐⭐⭐⭐](#7. 性能优化 ⭐⭐⭐⭐)
- [8. 高可用方案 ⭐⭐⭐⭐⭐](#8. 高可用方案 ⭐⭐⭐⭐⭐)
-
- [Master-Slave 主从模式](#Master-Slave 主从模式)
- [Network of Brokers(集群模式)](#Network of Brokers(集群模式))
- 核心要点
- [9. ActiveMQ vs RocketMQ ⭐⭐⭐⭐⭐](#9. ActiveMQ vs RocketMQ ⭐⭐⭐⭐⭐)
- [10. 常见问题 ⭐⭐⭐⭐⭐](#10. 常见问题 ⭐⭐⭐⭐⭐)
-
- [Q1: 消息丢失怎么办?](#Q1: 消息丢失怎么办?)
- [Q2: 消息重复消费怎么办?](#Q2: 消息重复消费怎么办?)
- [Q3: 消息堆积怎么办?](#Q3: 消息堆积怎么办?)
- [Q4: ActiveMQ vs Kafka 如何选择?](#Q4: ActiveMQ vs Kafka 如何选择?)
- [Q5: 如何保证消息顺序?](#Q5: 如何保证消息顺序?)
- 面试核心总结
- 快速记忆要点
1. 核心架构 ⭐⭐⭐⭐⭐
基本架构
┌─────────────┐ ┌─────────────┐
│ Producer │ │ Consumer │
│ (生产者) │ │ (消费者) │
└──────┬──────┘ └──────┬──────┘
│ │
├────────────────────┤
↓ ↓
┌─────────────────────────────────┐
│ ActiveMQ Broker │
│ ┌─────────────────────────┐ │
│ │ Queue/Topic │ │
│ │ 消息存储(KahaDB/JDBC) │ │
│ └─────────────────────────┘ │
└─────────────────────────────────┘
核心组件:
- Broker:消息服务器,负责接收、存储、转发消息
- Producer:消息生产者
- Consumer:消息消费者
- Destination:消息目的地(Queue或Topic)
核心要点
"ActiveMQ是基于JMS规范的消息中间件,采用Broker-Client架构。
核心是Broker服务器,负责消息的接收、存储和转发。支持多种存储方式,默认使用KahaDB文件存储,也可以使用MySQL、PostgreSQL等数据库存储。
Producer和Consumer 通过TCP、NIO、STOMP等多种协议与Broker通信。Producer将消息发送到Queue或Topic,Consumer从Queue或Topic接收消息。
与RocketMQ的区别是,ActiveMQ是单机或主从架构,没有NameServer这样的路由中心,相对简单但扩展性不如RocketMQ。
ActiveMQ支持JMS规范的所有特性,包括事务、持久化、消息确认等,在中小规模应用中使用广泛。"
2. 消息模型 ⭐⭐⭐⭐⭐
Queue(队列模型)
点对点(P2P)模型:
Producer → Queue → Consumer
↓
一条消息只能被一个Consumer消费
多个Consumer场景:
Producer → Queue → Consumer1
├──> Consumer2 → 负载均衡
└──> Consumer3
特点:
- ✅ 一条消息只能被一个Consumer消费
- ✅ 多个Consumer负载均衡消费
- ✅ 消息被消费后从队列删除
- ✅ 支持消息持久化
使用场景:
- 订单处理
- 任务分发
- 异步解耦
Topic(主题模型)
发布订阅(Pub/Sub)模型:
┌──> Consumer1(全量)
Producer → Topic ──> Consumer2(全量)
└──> Consumer3(全量)
一条消息可以被多个Consumer消费
特点:
- ✅ 一条消息可以被多个订阅者消费
- ✅ 每个订阅者都收到全量消息
- ✅ 支持持久订阅和非持久订阅
- ❌ 非持久订阅:Consumer离线期间的消息会丢失
使用场景:
- 广播通知
- 事件分发
- 消息复制
核心要点
"ActiveMQ支持JMS规范的两种消息模型:Queue和Topic。
Queue是点对点模型,一条消息只能被一个消费者消费,多个消费者之间是竞争关系,实现负载均衡。消息被消费后会从队列删除。适用于订单处理、任务分发等场景。
Topic是发布订阅模型,一条消息可以被多个订阅者消费,每个订阅者都会收到全量消息。分为持久订阅和非持久订阅:持久订阅会保存离线期间的消息,非持久订阅则会丢失。适用于广播通知、事件分发等场景。
实际项目中,订单、支付等业务用Queue保证消息只被处理一次;配置更新、缓存刷新用Topic实现广播通知。"
3. 消息确认机制 ⭐⭐⭐⭐⭐
三种确认模式
| 模式 | 说明 | 性能 | 可靠性 |
|---|---|---|---|
| AUTO_ACKNOWLEDGE | 自动确认 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| CLIENT_ACKNOWLEDGE | 客户端手动确认 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| DUPS_OK_ACKNOWLEDGE | 延迟批量确认 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| SESSION_TRANSACTED | 事务模式 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
代码示例
java
// 1. 自动确认(消息一接收就确认)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Message msg = consumer.receive();
// 自动确认,无需手动调用
// 2. 客户端确认(手动确认)
Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Message msg = consumer.receive();
// 处理成功后手动确认
msg.acknowledge();
// 3. 延迟确认(批量确认,可能重复)
Session session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
// 批量确认,性能高,但可能收到重复消息
// 4. 事务模式
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
// 批量接收处理
session.commit(); // 或 session.rollback();
核心要点
"ActiveMQ提供四种消息确认机制:
自动确认是默认模式,消息一旦被接收就立即确认,性能最高但可能丢失消息。适合日志收集等允许丢失的场景。
客户端确认需要手动调用acknowledge方法,可以精确控制确认时机。业务处理成功才确认,失败就不确认,消息会重新投递。适合订单处理等需要可靠消费的场景。需要注意的是,acknowledge会确认该session中所有未确认的消息。
延迟确认是批量确认模式,性能介于自动和客户端之间,但可能收到重复消息,需要业务幂等。
事务模式用于批量操作,多条消息一起提交或回滚,保证原子性。
我们项目中一般用客户端确认,既保证可靠性又能精确控制。"
4. 消息持久化 ⭐⭐⭐⭐⭐
持久化方式对比
| 存储方式 | 性能 | 可靠性 | 适用场景 |
|---|---|---|---|
| KahaDB | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 默认推荐 |
| LevelDB | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 高性能场景 |
| JDBC | ⭐⭐ | ⭐⭐⭐⭐⭐ | 企业级、事务要求高 |
| Memory | ⭐⭐⭐⭐⭐ | ⭐ | 测试环境 |
消息持久化模式
java
// 1. 持久化消息(默认)
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
// 消息会写入磁盘,Broker重启不丢失
// 2. 非持久化消息
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// 消息只存在内存,Broker重启会丢失
配置示例
xml
<!-- activemq.xml 配置 -->
<broker xmlns="..." brokerName="localhost">
<!-- KahaDB持久化(默认) -->
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
<!-- JDBC持久化 -->
<!-- <persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds"/>
</persistenceAdapter> -->
</broker>
核心要点
"ActiveMQ支持多种持久化方式,默认使用KahaDB。
KahaDB 是基于文件的高性能存储,使用日志文件和索引文件分离的设计,性能和可靠性都不错,是生产环境推荐的方式。
LevelDB 性能更高,但已经不再维护。
JDBC持久化 将消息存储到数据库,可靠性最高,支持事务,但性能相对较差。适合对消息可靠性要求极高的场景,比如金融系统。
消息本身也分持久化和非持久化。发送消息时可以设置DeliveryMode,PERSISTENT表示持久化到磁盘,Broker重启不会丢失;NON_PERSISTENT只存在内存,性能高但Broker重启会丢失。
我们项目中用KahaDB,重要消息设置为PERSISTENT,日志类消息用NON_PERSISTENT提高性能。"
5. 事务消息 ⭐⭐⭐⭐
JMS本地事务
java
// 创建事务Session
Session session = connection.createSession(
true, // transacted = true
Session.SESSION_TRANSACTED // 事务模式
);
MessageProducer producer = session.createProducer(destination);
try {
// 批量发送消息
for (int i = 0; i < 10; i++) {
Message msg = session.createTextMessage("消息" + i);
producer.send(msg);
}
// 提交事务
session.commit(); // ✅ 所有消息投递成功
} catch (Exception e) {
// 回滚事务
session.rollback(); // ❌ 所有消息回滚
}
XA分布式事务(了解即可)
java
// ActiveMQ支持XA事务(两阶段提交)
XAConnectionFactory xaFactory = new ActiveMQXAConnectionFactory(url);
XAConnection xaConn = xaFactory.createXAConnection();
XASession xaSession = xaConn.createXASession();
// 获取XA资源
XAResource xaResource = xaSession.getXAResource();
// 开始XA事务
Xid xid = createXid();
xaResource.start(xid, XAResource.TMNOFLAGS);
// 发送消息
MessageProducer producer = xaSession.createProducer(queue);
producer.send(message);
// 提交两阶段事务
xaResource.end(xid, XAResource.TMSUCCESS);
xaResource.prepare(xid);
xaResource.commit(xid, false);
核心要点
"ActiveMQ支持JMS本地事务和XA分布式事务。
JMS本地事务用于批量发送或消费消息,保证原子性。创建Session时设置transacted为true,然后通过commit提交或rollback回滚。比如批量发送10条消息,要么全部成功,要么全部失败。
XA分布式事务遵循两阶段提交协议,可以将消息发送和数据库操作放在一个分布式事务中。但是XA事务性能很差,实际很少使用,一般用最终一致性方案替代。
需要注意的是,ActiveMQ的事务是本地事务,只能保证单个Session内的操作原子性,无法像RocketMQ的事务消息那样解决分布式事务问题。
实际项目中,我们用JMS事务做批量发送,提高吞吐量。分布式事务则用RocketMQ的事务消息或Seata等分布式事务框架。"
6. 消息可靠性 ⭐⭐⭐⭐⭐
三个维度保证可靠性
1. 生产端可靠性
├─ 持久化消息(DeliveryMode.PERSISTENT)
├─ 同步发送(等待响应)
└─ 异常重试
2. Broker可靠性
├─ 消息持久化到磁盘(KahaDB)
├─ 主从复制(Master-Slave)
└─ 集群模式(Network of Brokers)
3. 消费端可靠性
├─ 客户端确认(CLIENT_ACKNOWLEDGE)
├─ 事务消费(SESSION_TRANSACTED)
└─ 消息重投递(Redelivery Policy)
消息重投递策略
java
// 配置重投递策略
RedeliveryPolicy policy = new RedeliveryPolicy();
policy.setMaximumRedeliveries(5); // 最多重投5次
policy.setInitialRedeliveryDelay(1000); // 首次延迟1秒
policy.setRedeliveryDelay(5000); // 后续延迟5秒
policy.setUseExponentialBackOff(true); // 使用指数退避
policy.setBackOffMultiplier(2.0); // 退避倍数2
// 应用到连接工厂
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
factory.setRedeliveryPolicy(policy);
防止消息丢失的完整方案
java
// 生产端
producer.setDeliveryMode(DeliveryMode.PERSISTENT); // 持久化
SendResult result = producer.send(msg); // 同步发送
if (!isSuccess(result)) {
// 记录失败日志,后续补偿
}
// Broker端
// activemq.xml 配置
<persistenceAdapter>
<kahaDB directory="..." /> // 持久化存储
</persistenceAdapter>
// 消费端
Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Message msg = consumer.receive();
try {
processMessage(msg);
msg.acknowledge(); // 处理成功才确认
} catch (Exception e) {
// 不确认,消息会重投递
}
核心要点
"ActiveMQ从三个层面保证消息可靠性:
生产端:使用持久化模式发送消息,确保消息写入磁盘。同步发送方式可以等待Broker响应,确认发送成功。发送失败可以记录日志,后续补偿。
Broker端:通过KahaDB持久化存储消息,即使Broker重启消息也不会丢失。支持主从模式,Master负责读写,Slave实时同步数据,Master宕机可以切换到Slave。
消费端:使用客户端确认模式,只有业务处理成功才手动确认消息。如果处理失败不确认,消息会自动重投递。可以配置重投递策略,包括重投次数、延迟时间、指数退避等。
需要注意的是,要防止重复消费,业务层要实现幂等性,可以通过消息ID去重或数据库唯一约束来保证。"
7. 性能优化 ⭐⭐⭐⭐
生产端优化
java
// 1. 异步发送
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
factory.setUseAsyncSend(true); // 开启异步发送
// 2. 批量发送
for (int i = 0; i < 100; i++) {
producer.send(msg);
}
// 不要每次都创建连接和Session
// 3. 连接池优化
PooledConnectionFactory poolFactory = new PooledConnectionFactory(factory);
poolFactory.setMaxConnections(10); // 最大连接数
poolFactory.setMaximumActiveSessionPerConnection(500);
// 4. 非持久化(性能要求高的场景)
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
消费端优化
java
// 1. 预取策略(Prefetch)
String url = "tcp://localhost:61616?jms.prefetchPolicy.queuePrefetch=1000";
// 预取1000条消息到客户端缓存
// 2. 并发消费
ExecutorService executor = Executors.newFixedThreadPool(20);
consumer.setMessageListener(msg -> {
executor.submit(() -> processMessage(msg));
});
// 3. 批量确认(事务模式)
Session session = conn.createSession(true, Session.SESSION_TRANSACTED);
for (int i = 0; i < 100; i++) {
Message msg = consumer.receive();
processMessage(msg);
}
session.commit(); // 批量确认
// 4. 优化消费逻辑
// - 数据库批量操作
// - 使用缓存
// - 异步化外部调用
Broker端优化
xml
<!-- activemq.xml -->
<broker xmlns="..." brokerName="localhost">
<!-- 内存限制 -->
<systemUsage>
<memoryUsage>
<memoryUsage limit="512 mb"/> <!-- 内存限制 -->
</memoryUsage>
<storeUsage>
<storeUsage limit="100 gb"/> <!-- 存储限制 -->
</storeUsage>
<tempUsage>
<tempUsage limit="50 gb"/> <!-- 临时文件限制 -->
</tempUsage>
</systemUsage>
<!-- 异步发送 -->
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">" producerFlowControl="false"/>
</policyEntries>
</policyMap>
</destinationPolicy>
</broker>
核心要点
"ActiveMQ性能优化主要从三个方面入手:
生产端优化:使用异步发送提高吞吐量,避免阻塞等待。使用连接池复用连接,减少连接创建开销。对于非重要消息使用非持久化模式,跳过磁盘IO。
消费端优化:调整预取策略,增大prefetchSize,一次性预取更多消息到客户端缓存,减少网络交互。使用并发消费,创建线程池并行处理消息。优化消费逻辑,比如数据库批量操作、增加缓存、外部调用异步化等。
Broker端优化:增加内存限制,减少磁盘IO。关闭生产者流控,提高生产速度。使用NIO或NIO+SSL传输协议,性能优于默认的TCP。
需要注意的是,性能和可靠性往往是矛盾的,要根据业务场景选择合适的配置。"
8. 高可用方案 ⭐⭐⭐⭐⭐
Master-Slave 主从模式
架构:
┌─────────┐ 消息复制 ┌─────────┐
│Master │ ────────> │Slave │
│读写 │ │只读 │
└─────────┘ └─────────┘
工作原理:
1. Producer发送消息到Master
2. Master存储并复制到Slave
3. Consumer从Master或Slave消费
优点:
✅ 数据备份,防止丢失
✅ 读写分离,提高性能
缺点:
❌ Master宕机需手动切换
❌ 不支持自动故障转移
Network of Brokers(集群模式)
架构:
┌─────────┐ ┌─────────┐
│Broker-1 │ <──> │Broker-2 │
└─────────┘ └─────────┘
↑ ↓ ↑ ↓
└──────────────┘
Network Bridge
工作原理:
1. Broker之间通过Network Connector连接
2. 消息可以在Broker间转发
3. Consumer可以从任意Broker消费
优点:
✅ 水平扩展
✅ 负载均衡
✅ 高可用
配置示例:
<networkConnectors>
<networkConnector uri="static:(tcp://broker2:61616)"/>
</networkConnectors>
核心要点
"ActiveMQ提供两种高可用方案:
Master-Slave主从模式:Master负责读写,Slave实时同步Master的数据。Master宕机后,可以手动切换到Slave。这种模式简单可靠,但不支持自动故障转移,需要人工介入。有三种实现方式:共享文件系统、共享数据库、基于ZooKeeper的Replicated LevelDB,后者已废弃。
Network of Brokers集群模式:多个Broker通过Network Connector互联,形成网状结构。消息可以在Broker间转发,Consumer可以从任意Broker消费。这种模式支持水平扩展和负载均衡,但配置相对复杂。
与RocketMQ对比,ActiveMQ的高可用机制相对简单,适合中小规模应用。大规模高并发场景建议用RocketMQ或Kafka。
我们项目用的是Master-Slave模式,搭配负载均衡器实现简单高可用。"
9. ActiveMQ vs RocketMQ ⭐⭐⭐⭐⭐
详细对比
| 特性 | ActiveMQ | RocketMQ |
|---|---|---|
| 架构 | Broker-Client | NameServer-Broker-Client |
| 扩展性 | 中(单机或主从) | 高(分布式) |
| 性能 | 万级TPS | 十万级TPS |
| 顺序消息 | 不支持 | 支持(分区顺序) |
| 事务消息 | JMS本地事务 | 分布式事务消息 |
| 延迟消息 | 支持任意延迟 | 18个固定等级 |
| 消息查询 | 支持 | 支持(按Key/时间) |
| 消息回溯 | 不支持 | 支持 |
| 死信队列 | 支持 | 支持 |
| 协议 | JMS、STOMP、MQTT等 | 自定义协议 |
| 管理界面 | Web Console | Dashboard |
| 适用场景 | 中小规模、JMS标准 | 大规模、高并发 |
性能对比
TPS(消息/秒):
ActiveMQ: 1万-3万
RocketMQ: 10万-50万
Kafka: 100万+
延迟:
ActiveMQ: 10-50ms
RocketMQ: 1-10ms
Kafka: <5ms
核心要点
"ActiveMQ和RocketMQ的主要区别:
架构层面:ActiveMQ是传统的Broker-Client架构,单机或主从部署。RocketMQ是分布式架构,有NameServer做路由中心,Broker可以水平扩展。
性能方面:ActiveMQ的TPS在万级,适合中小规模应用。RocketMQ可以达到十万级甚至百万级TPS,适合大规模高并发场景。
功能方面:ActiveMQ支持完整的JMS规范,支持任意时间的延迟消息。RocketMQ的顺序消息、事务消息、消息回溯等功能更强大,但延迟消息只支持18个固定等级。
选型建议:如果是传统企业应用,需要JMS标准支持,用ActiveMQ。如果是互联网应用,高并发、大数据量,用RocketMQ或Kafka。
我们项目从ActiveMQ迁移到RocketMQ,主要是性能需求,原来ActiveMQ在大促时经常消息堆积,换成RocketMQ后性能提升了10倍以上。"
10. 常见问题 ⭐⭐⭐⭐⭐
Q1: 消息丢失怎么办?
原因分析:
1. 生产端:发送失败未处理
2. Broker端:非持久化 + Broker宕机
3. 消费端:自动确认 + 处理失败
解决方案:
java
// 生产端:持久化 + 同步发送 + 异常处理
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
try {
producer.send(msg);
} catch (JMSException e) {
// 记录失败日志,后续补偿
saveToFailTable(msg);
}
// Broker端:持久化存储 + 主从复制
// activemq.xml
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
// 消费端:客户端确认
msg.acknowledge(); // 处理成功才确认
Q2: 消息重复消费怎么办?
原因:
- 消费失败后重投递
- 网络抖动导致重复投递
- Broker故障恢复后重复投递
解决方案:
java
// 方案1:基于消息ID去重(推荐)
Set<String> processedIds = new ConcurrentHashSet<>();
public void consume(Message msg) {
String msgId = msg.getJMSMessageID();
if (processedIds.contains(msgId)) {
msg.acknowledge(); // 重复消息,直接确认
return;
}
processMessage(msg);
processedIds.add(msgId);
msg.acknowledge();
}
// 方案2:使用Redis去重
public void consume(Message msg) {
String msgId = msg.getJMSMessageID();
Boolean success = redis.setNX("msg:" + msgId, "1", 24, TimeUnit.HOURS);
if (!success) {
return; // 重复消息
}
processMessage(msg);
}
// 方案3:数据库唯一约束
// 在订单表设置订单号唯一索引,重复插入会失败
Q3: 消息堆积怎么办?
处理方案:
1. 扩容消费者(最快)
启动更多Consumer实例,负载均衡消费
2. 增加消费线程
使用线程池并发处理消息
3. 优化消费逻辑
- 数据库批量操作
- 异步化外部调用
- 增加缓存
4. 临时队列转移
将消息快速转移到新队列,修复bug后重新消费
5. 丢弃过期消息
根据消息时间戳,丢弃超过一定时间的消息
Q4: ActiveMQ vs Kafka 如何选择?
| 场景 | 推荐 | 原因 |
|---|---|---|
| 企业应用、中小规模 | ActiveMQ | JMS标准、功能完整 |
| 互联网、高并发 | RocketMQ/Kafka | 高性能、高可用 |
| 日志收集、大数据 | Kafka | 超高吞吐量 |
| 需要事务消息 | RocketMQ | 分布式事务支持 |
| 需要延迟消息 | ActiveMQ/RocketMQ | Kafka不支持 |
Q5: 如何保证消息顺序?
ActiveMQ的限制:
ActiveMQ不支持分区顺序消息!
只能通过以下方式保证:
1. Queue只有一个Consumer(性能差)
2. Consumer内单线程处理(性能差)
3. 使用消息优先级(不保证绝对顺序)
推荐:
如果业务需要严格顺序,建议使用RocketMQ的顺序消息功能
面试核心总结
必问问题(按重要性排序)
| 排名 | 问题 | 核心要点 |
|---|---|---|
| 1 | 消息模型 | Queue/Topic、P2P/发布订阅 |
| 2 | 消息确认机制 | 4种模式、使用场景、可靠性 |
| 3 | 消息可靠性 | 3个维度、持久化、重投递 |
| 4 | 消息丢失/重复 | 原因、解决方案、幂等性 |
| 5 | 性能优化 | 异步发送、预取、连接池 |
| 6 | 高可用 | 主从模式、集群模式 |
| 7 | ActiveMQ vs RocketMQ | 性能、功能、场景选型 |
| 8 | 消息堆积 | 原因、处理方案 |
综合面试回答示例
"我们项目中使用ActiveMQ作为消息中间件,主要用于系统解耦和异步处理。
架构上采用主从模式部署,Master负责读写,Slave实时同步做备份。
消息模型上,订单、支付等业务用Queue实现点对点消息,确保每条消息只被处理一次;配置更新、缓存刷新用Topic实现广播通知。
可靠性保证通过持久化消息、客户端手动确认、消息重投递机制来实现。重要消息使用同步发送,确认发送成功;一般消息用异步发送提高性能。
性能优化方面,开启异步发送、使用连接池、调大预取大小,消费端用线程池并发处理,优化了数据库批量操作和缓存使用。
遇到过消息堆积问题,当时通过扩容消费者实例、增加消费线程、优化消费逻辑三管齐下解决的。现在建立了监控告警机制,堆积超过阈值立即通知。
后续考虑迁移到RocketMQ,主要是性能和分布式事务的需求。"
快速记忆要点
架构设计: Broker作为中心节点负责消息存储转发,支持主从备份提高可用性,Network of Brokers实现集群互联
消息模型: Queue点对点模型一条消息只被一个消费者处理,Topic发布订阅模型支持多个订阅者接收全量消息
确认机制: 自动确认性能高但可能丢失,客户端手动确认可靠可控,延迟确认批量提交性能好,事务模式保证批量原子性
持久化: KahaDB文件存储是默认推荐方式,JDBC数据库存储可靠性最高,内存存储性能最快但会丢失
可靠保证: 消息持久化防止Broker重启丢失,同步发送等待确认成功,客户端手动确认保证消费成功,三重保障确保可靠
性能优化: 异步发送避免阻塞,调大预取数量减少网络交互,连接池复用避免频繁创建,消费端并发处理提升吞吐
高可用: 主从模式Master写Slave读备份,Master宕机需手动切换,Network集群通过桥接实现消息转发
场景选型: 中小规模应用和传统企业适合ActiveMQ,大规模高并发场景推荐RocketMQ或Kafka