跳至主要内容

🧣 持久訂閱

本章節解析 ActiveMQ Topic 模式下最關鍵的可靠性機制——持久訂閱(Durable Subscription)。它讓訂閱者在離線期間錯過的訊息,在重新上線後仍能被完整接收。

環境

1. 非持久 vs 持久訂閱

類型離線期間訊息需要 clientId典型場景
非持久訂閱遺失即時股價、即時通知
持久訂閱保留系統事件、審計日誌

2. JMS 程式範例

2.1 建立持久訂閱

ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
connection.setClientID("billing-service-01"); // 必須唯一且固定
connection.start();

Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("BILLING.EVENTS");

// subscriptionName 在 Broker 端識別此訂閱
MessageConsumer consumer = session.createDurableSubscriber(topic, "billing-sub");
consumer.setMessageListener(message -> {
System.out.println("Received: " + ((TextMessage) message).getText());
});

2.2 取消持久訂閱

session.unsubscribe("billing-sub");
警告

clientId 在同一 Broker 上必須唯一。若兩個應用實例使用相同 clientId,後連線者會踢掉先連線者。

3. Spring Boot 持久訂閱

spring:
activemq:
broker-url: tcp://localhost:61616
@Bean
public DefaultJmsListenerContainerFactory durableTopicFactory(
ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setPubSubDomain(true);
factory.setSubscriptionDurable(true);
factory.setClientId("billing-service-01");
return factory;
}

@JmsListener(
destination = "BILLING.EVENTS",
containerFactory = "durableTopicFactory",
subscription = "billing-sub"
)
public void onBillingEvent(String event) {
processEvent(event);
}

4. Broker 端:離線訂閱者回收

持久訂閱者長期離線會佔用 Broker 資源。可透過 offlineDurableSubscriberTimeout 自動清理:

<broker xmlns="http://activemq.apache.org/schema/core"
brokerName="localhost"
dataDirectory="${activemq.data}"
offlineDurableSubscriberTimeout="86400000"
offlineDurableSubscriberTaskSchedule="30000">
</broker>

詳見 setGC

5. 常見問題與排查

現象可能原因處理方式
離線後收不到歷史訊息未設 clientId 或非持久訂閱使用 createDurableSubscriber
InvalidClientIDExceptionclientId 重複每個實例使用不同 clientId
堆積訊息過多消費者長期離線啟用離線訂閱者回收或加快消費
Web Console 看不到訂閱尚未建立連線持久訂閱在首次連線後才會出現

6. 與其他文章的關聯