一、前因
最近在做公司的一個微服務項目,技術架構為spring cloud + consul + SSM。
當我寫完一個功能要在本地測試時,發現服務運行成功,但是前后端聯調報500錯誤。
當時的第一個想法就是gateway服務的問題,但是其他同事卻說gateway服務沒毛病。
最后想到可能是注冊中心的問題,於是訪問consul的管理頁面。服務是注冊上了,但是一眼就能看到毛病:
居然是內網IP!!我驚了!
檢查日志信息發現,向注冊中心發送注冊地址,為內網ip地址:
那么就找到問題原因了。
二、問題
先回想了一下注冊中心原理(以前用的是Eruka,不過原理都是大同小異的):
- 服務提供者啟動后,發送自己的信息到注冊中心進行注冊
- 服務提供者每隔一段時間會想注冊中心發送心跳,證明自己還活着,沒有掛掉!(默認90s)
- 服務調用者第一次調用服務提供者時,會向注冊中心拉取一份服務提供者的地址,並緩存在本地(下次用可以直接從本地取)
- 當服務提供者不可用時,注冊中心會將這個服務提供者信息同步到訂閱過這個服務的服務消費者。
查閱了一些資料,consul的原理如下圖:
和Eruka基本差不多,只是consul不是由服務提供者發送心跳,而是由注冊中心訪問服務提供者的健康檢查鏈接,以此來判斷服務提供者是否還存活!
清晰明了!真正的問題就是:我的服務用局域網鏈接向consul注冊健康檢查鏈接,我能訪問consul,但consul肯定是訪問不到我的局域網IP來對我服務進行健康檢查,因此判斷我的服務掛了
因為和其他同事不在一個地方辦公,我這里拿到的資料很不全,僅僅只有一個服務的代碼和需求文檔。連數據庫、redis、consul等的地址賬號密碼,都是自己從項目配置文件中找的。
而他們的辦公環境是和公司服務器在一個局域網的,所以他們不會出現我這個問題。
三、解決
因為我本地連接了wifi,需要內網穿透才能將本機暴露出去。
這太麻煩了,所以我將服務打包到了自己的阿里雲服務器。
但是,這里也有坑:Consul在不寫ip_address配置項的情況下,默認從第一網卡取地址值。而阿里雲的第一個網卡就是內網ip。
eth0,eth1,eth2……代表網卡一,網卡二,網卡三……
直接拿服務器的外網ip,在配置文件中指定:
spring:
cloud:
consul:
host: ${CONSUL_HOST}
port: ****
discovery:
hostname: ${spring.cloud.client.ip-address}
instance-id: ${spring.application.name}:118.***.***.**:${spring.application.instance_id:${server.port}}
service-name: ${spring.application.name}-app
#check失敗后,多少秒后刪除本服務
health-check-critical-timeout: 30s
#顯示ip地址
prefer-ip-address: true
ip-address: 118.***.***.**
搞定!打包上傳服務器運行,注冊成功