SpringBoot rabbitmq長鏈接及域名TTL多機(jī)房切換配置重連能力(完整配置方案)
在Spring Boot中配置RabbitMQ以解決長連接穩(wěn)定性、域名TTL問題及機(jī)房切換后的自動重連能力,需結(jié)合 連接工廠參數(shù)優(yōu)化、DNS緩存刷新、自定義重連策略 三個核心方向。下面將介紹可直接落地的完整配置方案。
一、基礎(chǔ)依賴與核心配置
首先確保pom.xml 中引入Spring AMQP依賴(默認(rèn)集成RabbitMQ 客戶端):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>二、連接工廠配置(解決長連接穩(wěn)定性)
通過ConnectionFactory配置RabbitMQ連接參數(shù),重點(diǎn)優(yōu)化心跳檢測、自動恢復(fù)、超時控制等參數(shù),確保長連接穩(wěn)定。在application.yml中配置:
spring:
rabbitmq:
addresses: rabbitmq.example.com:5672 # 域名+端口(多節(jié)點(diǎn)用逗號分隔)
username: admin
password: your_password
virtual-host: /
# 連接超時設(shè)置
connection-timeout: 30000 # 連接超時30秒
# 心跳檢測(關(guān)鍵:檢測連接存活)
requested-heartbeat: 60 # 心跳間隔60秒,避免被防火墻/負(fù)載均衡器斷開
# 自動恢復(fù)配置(客戶端內(nèi)置重連機(jī)制)
publisher-confirm-type: CORRELATED # 確保消息發(fā)布確認(rèn)可靠性
publisher-returns: true # 開啟消息返回機(jī)制
listener:
simple:
retry:
enabled: true # 開啟消費(fèi)者重試(避免連接抖動導(dǎo)致消息丟失)
max-attempts: 3 # 最大重試次數(shù)
initial-interval: 1000 # 重試初始間隔1秒
# 連接工廠高級配置(通過Java代碼進(jìn)一步定制)三、解決域名 TTL(DNS 緩存)問題
JVM會緩存DNS解析結(jié)果,機(jī)房切換后域名IP變更時,需強(qiáng)制刷新解析。通過以下兩種方式實(shí)現(xiàn):
3.1.JVM 層面控制 DNS 緩存(全局生效)
在應(yīng)用啟動參數(shù)中添加JVM系統(tǒng)屬性,縮短DNS緩存時間:
java -Dsun.net.inetaddr.ttl=10 -Dsun.net.inetaddr.negative.ttl=5 -jar your-app.jar
- sun.net.inetaddr.ttl=10:正緩存(成功解析的 IP)10 秒后過期,強(qiáng)制重新解析。
- sun.net.inetaddr.negative.ttl=5:負(fù)緩存(解析失敗的記錄)5 秒后過期,避免長期無法連接。
3.2連接工廠層面主動刷新 DNS(精準(zhǔn)控制)
通過自定義ConnectionFactory,在每次創(chuàng)建連接前主動解析域名獲取最新IP,繞過本地緩存:
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.rabbitmq.client.Connection;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Configuration
public class RabbitMQConfig {
@Value("${spring.rabbitmq.addresses}")
private String addresses; // 原始配置的域名地址(如 rabbitmq.example.com:5672)
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Value("${spring.rabbitmq.virtual-host}")
private String virtualHost;
@Bean
public ConnectionFactory connectionFactory() {
// 1. 解析域名獲取最新IP(核心:繞過DNS緩存)
String resolvedAddresses = resolveDomainToIp(addresses);
// 2. 創(chuàng)建RabbitMQ連接工廠
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setAddresses(resolvedAddresses); // 使用解析后的IP地址
factory.setUsername(username);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setConnectionTimeout(30000); // 連接超時30秒
factory.setRequestedHeartbeat(60); // 心跳間隔60秒
// 3. 啟用自動恢復(fù)(關(guān)鍵:連接斷開后自動重建)
factory.setAutomaticRecoveryEnabled(true); // 開啟自動恢復(fù)
factory.setNetworkRecoveryInterval(5000); // 網(wǎng)絡(luò)恢復(fù)重試間隔5秒
factory.setTopologyRecoveryEnabled(true); // 恢復(fù)隊列/交換機(jī)綁定(拓?fù)浠謴?fù))
// 4. 注冊連接監(jiān)聽器(監(jiān)控連接狀態(tài),觸發(fā)自定義重連)
factory.addConnectionListener(new ConnectionListener() {
@Override
public void onClose(Connection connection) {
// 連接關(guān)閉時觸發(fā)(非主動關(guān)閉)
if (!connection.isOpen()) {
System.out.println("RabbitMQ連接已關(guān)閉,準(zhǔn)備重連...");
// 可在此處添加額外重連邏輯(如刷新IP后重建連接)
refreshConnection(factory);
}
}
@Override
public void onShutDown(ShutdownSignalException signal) {
// 處理服務(wù)端主動關(guān)閉信號
if (!signal.isInitiatedByApplication()) {
System.err.println("RabbitMQ連接被強(qiáng)制關(guān)閉,原因:" + signal.getReason());
refreshConnection(factory);
}
}
});
return factory;
}
// 解析域名獲取最新IP(替換域名中的主機(jī)為IP)
private String resolveDomainToIp(String addresses) {
try {
// 分割多節(jié)點(diǎn)地址(如 "host1:5672,host2:5672")
String[] addressArray = addresses.split(",");
StringBuilder resolved = new StringBuilder();
for (String addr : addressArray) {
String[] hostPort = addr.split(":");
String host = hostPort[0];
String port = hostPort.length > 1 ? hostPort[1] : "5672";
// 解析域名獲取最新IP
InetAddress[] inetAddresses = InetAddress.getAllByName(host);
String latestIp = inetAddresses[0].getHostAddress(); // 取第一個IP(多IP可輪詢)
resolved.append(latestIp).append(":").append(port).append(",");
}
// 移除最后一個逗號
return resolved.substring(0, resolved.length() - 1);
} catch (UnknownHostException e) {
System.err.println("域名解析失敗,使用原始地址:" + e.getMessage());
return addresses; // 解析失敗時 fallback 到原始域名
}
}
// 刷新連接(重建連接工廠)
private void refreshConnection(CachingConnectionFactory factory) {
try {
// 1. 關(guān)閉舊連接
factory.destroy();
// 2. 重新解析域名獲取新IP
String newAddresses = resolveDomainToIp(addresses);
// 3. 更新連接工廠地址并重建連接
factory.setAddresses(newAddresses);
factory.createConnection(); // 主動創(chuàng)建新連接
System.out.println("RabbitMQ重連成功,新地址:" + newAddresses);
} catch (Exception e) {
System.err.println("重連失敗,5秒后重試:" + e.getMessage());
// 延遲重試(避免頻繁失敗)
try {
Thread.sleep(5000);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
refreshConnection(factory); // 遞歸重試
}
}
}四、機(jī)房切換重連能力增強(qiáng)(關(guān)鍵機(jī)制)
上述配置已實(shí)現(xiàn)基礎(chǔ)重連,若需應(yīng)對極端場景(如機(jī)房完全切換、多節(jié)點(diǎn)故障),可補(bǔ)充以下增強(qiáng)策略:
4.1多機(jī)房節(jié)點(diǎn)優(yōu)先級配置
若RabbitMQ部署在多機(jī)房(如主機(jī)房rabbitmq-primary.example.com、備機(jī)房rabbitmq-secondary.example.com),可在addresses中按優(yōu)先級配置,重連時優(yōu)先嘗試主機(jī)房,失敗后自動切換到備機(jī)房:
spring:
rabbitmq:
addresses: rabbitmq-primary.example.com:5672,rabbitmq-secondary.example.com:5672 # 主備順序客戶端會按順序嘗試連接,主機(jī)房故障時自動切換到備機(jī)房。
4.2結(jié)合服務(wù)發(fā)現(xiàn)動態(tài)獲取節(jié)點(diǎn)(適合大規(guī)模部署)
若使用服務(wù)發(fā)現(xiàn)組件(如 Nacos、Consul)管理RabbitMQ節(jié)點(diǎn),可在resolveDomainToIp方法中從服務(wù)發(fā)現(xiàn)獲取健康節(jié)點(diǎn),動態(tài)更新連接地址:
// 從服務(wù)發(fā)現(xiàn)獲取健康節(jié)點(diǎn)(偽代碼)
private List<String> getHealthyNodes() {
// 調(diào)用服務(wù)發(fā)現(xiàn)API,獲取健康的RabbitMQ節(jié)點(diǎn)(如 "10.0.1.1:5672,10.0.2.1:5672")
return serviceDiscovery.getHealthyInstances("rabbitmq-service");
}4.3重連時的資源恢復(fù)保障
開啟topologyRecoveryEnabled: true后,客戶端會自動恢復(fù)隊列、交換機(jī)、綁定關(guān)系及消費(fèi)者。若需更嚴(yán)格的資源校驗(yàn),可在重連成功后主動檢查:
// 重連成功后校驗(yàn)隊列是否存在(示例)
@Autowired
private RabbitAdmin rabbitAdmin;
public void validateQueue(String queueName) {
if (!rabbitAdmin.getQueueProperties(queueName).containsKey("queue")) {
// 隊列不存在,重新聲明
Queue queue = QueueBuilder.durable(queueName)
.withArgument("x-message-ttl", 28800000)
.build();
rabbitAdmin.declareQueue(queue);
}
}五、監(jiān)控與告警(確保問題可感知)
通過Spring Boot Actuator監(jiān)控RabbitMQ連接狀態(tài),配置如下:
management:
endpoints:
web:
exposure:
include: rabbithealth,health
endpoint:
rabbithealth:
enabled: true # 開啟RabbitMQ專屬健康檢查健康檢查會返回連接狀態(tài)、通道數(shù)、消費(fèi)者數(shù)等信息,結(jié)合Prometheus + Grafana 可實(shí)時監(jiān)控連接波動,機(jī)房切換時及時告警。
注意:Spring Boot Actuator 是一個非常強(qiáng)大的監(jiān)控和管理工具,但如果配置不當(dāng),確實(shí)會帶來??嚴(yán)重的安全風(fēng)險??。確保Actuator安全的關(guān)鍵在于遵循 ??“最小權(quán)限原則”?? ,即只暴露最少必要的信息,并嚴(yán)格控制訪問。
六、核心配置總結(jié)
| 配置方向 | 關(guān)鍵操作 |
|---|---|
| 長連接穩(wěn)定性 | 啟用心跳檢測(requested-heartbeat)、設(shè)置合理超時(connection-timeout) |
| DNS 緩存問題 | 縮短 JVM DNS 緩存時間 + 重連時主動解析域名 |
| 機(jī)房切換重連 | 啟用自動恢復(fù)(automaticRecoveryEnabled)+ 自定義重連監(jiān)聽器 + 多節(jié)點(diǎn)優(yōu)先級 |
| 資源一致性 | 開啟拓?fù)浠謴?fù)(topologyRecoveryEnabled)+ 主動校驗(yàn)隊列 / 交換機(jī) |
博客總結(jié)
通過以上配置,Spring Boot應(yīng)用可在RabbitMQ機(jī)房切換時自動刷新DNS解析、重建連接并恢復(fù)資源,確保消息通信不中斷。
其他參考/學(xué)習(xí)資料:
源碼地址
https://github.com/toutouge/javademosecond
到此這篇關(guān)于SpringBoot rabbitmq長鏈接及域名TTL多機(jī)房切換配置重連能力(完整配置方案)的文章就介紹到這了,更多相關(guān)springboot rabbitmq長鏈接內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合RabbitMQ實(shí)現(xiàn)通配符模式
- SpringBoot整合RabbitMQ之發(fā)布訂閱模式
- SpringBoot+RabbitMQ完成應(yīng)用通信
- Springboot使用Rabbitmq的延時隊列+死信隊列實(shí)現(xiàn)消息延期消費(fèi)
- Springboot使用RabbitMQ實(shí)現(xiàn)關(guān)閉超時訂單(示例詳解)
- SpringBoot 整合 RabbitMQ 的使用方式(代碼示例)
- springboot之redis cache TTL選項(xiàng)的使用
- springboot整合RabbitMQ 中的 TTL實(shí)例代碼
- Springboot整合RabbitMq測試TTL的方法詳解
相關(guān)文章
解讀@NoArgsConstructor,@AllArgsConstructor,@RequiredArgsConstr
這篇文章主要介紹了解讀@NoArgsConstructor,@AllArgsConstructor,@RequiredArgsConstructor的區(qū)別及在springboot常用地方,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12
Java 中文字符按Unicode排序的實(shí)現(xiàn)方法
這篇文章主要介紹了Java 中文字符按Unicode排序的實(shí)現(xiàn)方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-10-10
Springboot 整合RabbitMq(用心看完這一篇就夠了)
這篇文章主要介紹了Springboot 整合RabbitMq(用心看完這一篇就夠了),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
玩轉(zhuǎn)spring boot 結(jié)合jQuery和AngularJs(3)
玩轉(zhuǎn)spring boot,這篇文章主要介紹了結(jié)合jQuery和AngularJs,玩轉(zhuǎn)spring boot,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01
Java Web基于Session的登錄實(shí)現(xiàn)方法
這篇文章主要介紹了Java Web基于Session的登錄實(shí)現(xiàn)方法,涉及Java針對session的操作及表單提交與驗(yàn)證技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-10-10
Java關(guān)于桶排序的知識點(diǎn)總結(jié)
這篇文章給大家總結(jié)了關(guān)于JAVA中J桶排序的相關(guān)知識點(diǎn)和用法分享,有興趣的讀者跟著學(xué)習(xí)下。2018-04-04
SpringBoot實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換的方法總結(jié)
項(xiàng)目開發(fā)中經(jīng)常會遇到多數(shù)據(jù)源同時使用的場景,比如冷熱數(shù)據(jù)的查詢等情況,所以接下來本文就來介紹一下如何使用實(shí)現(xiàn)自定義注解的形式來實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換吧2023-12-12

