實戰:Nacos配置中心的Pull原理,附源碼
大家好,我是哪吒。
在單體服務時代,關于配置信息,管理一套配置文件即可。
而拆分成微服務之后,每一個系統都會有自己的配置,并且都各不相同,有些配置還需要動態改變,以達到動態降級、切流量、擴縮容等目的。
一、本地配置
在Spring Boot開發中,可以把配置項放到config文件中,把配置當代碼使用。比如:
public class AppConfig {
public static final String static_SUCCESS_CODE = "0000";
public static final String static_ERROR_CODE = "0001";
}
也可以通過@Value加載yaml配置文件中的配置。
@Component
public class HttpConfig {
// 核心線程數
public static String config_CORE_POOL_SIZE;
@Value("${async.corePoolSize}")
public void setSaveUrl(String corePoolSize) {
HttpConfig.config_CORE_POOL_SIZE = corePoolSize;
}
}
無論是將配置定義在代碼中,還是將配置寫在yaml配置文件中,都相當于把配置存在應用程序的本地。
如果想修改配置,就需要將在Linux服務器中部署的程序停止,然后手動修改其配置,再進行重啟。
如果修改的配置項較多,這也是一項容易出錯,而且繁瑣的事情,長期運維的小伙伴應該深有體會。
當時,我就在想,作為世界上使用人數最多的語言,更新一個配置,需要這么復雜嗎?
答案肯定不是的。
二、配置中心
配置中心(Configuration Center)通常用于集中管理應用程序的配置信息。這些配置信息可以包括數據庫連接信息、外部服務地址、日志級別、超時設置等。配置中心可以提高應用部署的靈活性和可維護性。
程序啟動時,可以自動從配置中心拉取所需要的配置項,配置中心中配置有所改變時,同樣可以自動從配置中心拉取最新的配置信息,服務不需要重新發布。
1、以Nacos為例:
- 配置中心的信息一般都是放在bootstrap.yml 中。
- 初始化的時候,Bootstrap Context負責從外部源加載配置屬性并解析配置。
- Bootstrap屬性有高優先級,默認情況下,它們不會被本地配置覆蓋。
- 然后再讀取application.yml中的配置,進行配置合并,完成項目的啟動。
項目的核心配置,需要熱更新的配置才有放到nacos管理的必要。基本不會變更的一些配置還是保存在微服務本地比較好。
2、Pull模式
Nacos采用的是Pull模式獲取服務端數據,客戶端采用長輪詢的方式定時的發起Pull請求,去檢查服務端配置信息是否發生了變化。
- 客戶端發起長輪詢請求,監聽變更的dataId+group。
- 服務端收到客戶端的請求,這時會掛起客戶端的請求。
- 如果在服務端設計的29.5s之內都沒有發生變更,觸發自動檢查機制,此時不管是否有變化,服務端都會返回響應到客戶端
- 如果在29.5s之內配置項發生了變更,則會觸發一個事件機制,將變更的數據推送的客戶端。
3、也可以通過Nacos實現注冊中心
這種是最簡單的Nacos注冊中心,有若干個服務,都注冊到Nacos注冊中心,調用之前,先到Nacos獲取對應接口,然后進行實際的調用。
服務1和服務2和Nacos之間維護一個心跳關系,每5秒跳一次,頻率不能太快或者太慢,否者會嗝屁的。
- 如果Nacos在5秒內沒有收到心跳,則表示服務掛了,Nacos會下線此服務。
- 對于超過15秒沒有收到客戶端心跳的服務實例,會將它的healthy屬性置為false,客戶端無法調用healthy為false的服務。
- 如果超過30秒沒有收到心跳,Nacos會直接將此服務剔除。
也可以通過服務端主動注銷的方式,停止注冊。
服務1調用服務2時,服務1會通過定時任務到Nacos中獲取在線的服務,保證所調用的服務一直都是健康在線的狀態。
獲取到之后,用緩存將其保存起來,然后通過負載均衡器調用服務2,此時,將不再使用服務端的負載均衡Nginx了。
三、配置中心提供了哪些功能
- 配置項管理:支持添加、發布、修改配置項以及配置項的分組,可以實現版本管理,支持熱發布、灰度發布、環境隔離,提供API接口與可視化操作頁面。
- 權限控制:配置項訪問控制,讀權限和寫權限。
- 操作審計:支持記錄用戶的操作行為。
- 配置變更:當有新的配置項或是現有的配置項發生變動時,配置中心能夠進行實時的監控并做出相應的處理。
- 配置推送:通過訂閱/發布的模式,將配置信息推送給各個服務的消費者。
- 歷史版本管理:保存所有的配置歷史版本,并提供查詢和對比的功能,可以輕松的回滾到任何一個版本。
- 灰度發布:通過配置中心可以實現在部分環境中先發布新的配置項,觀察一段時間沒有問題后再推送給其他所有的環境。
- 配置變更審計:記錄每次配置的修改記錄,方便追蹤和管理。
這些功能可以幫助降低分布式系統中管理配置信息的成本,降低因錯誤的配置信息變更帶來可用性下降甚至發生故障的風險。
四、如何操作配置中心
1、配置注冊
配置中心的配置注冊通常包括以下步驟:
- 服務提供者在啟動時,將自己的配置信息注冊到配置中心。這些信息可能包括服務的IP地址、端口號、數據庫連接信息等。
- 配置中心接收并存儲這些配置信息。一般來說,配置中心會提供一個統一的接口或者界面,讓服務提供者能夠方便地進行注冊。
- 服務消費者在需要使用某個服務時,會從配置中心獲取相應的配置信息。這樣,即使服務提供者的地址等信息發生變化,服務消費者也能通過配置中心獲取到最新的配置信息,而無需手動修改。
通過這種方式,配置中心實現了配置的統一管理和動態更新。服務提供者和消費者都可以通過配置中心來進行配置的注冊和獲取,大大提高了配置的靈活性和便利性。同時,也減少了因為手動配置錯誤而導致的問題,提高了系統的穩定性和可用性。
要通過Java代碼實現配置注冊到配置中心,你可以遵循以下步驟。這里繼續提供一個通用的示例代碼,以展示基本的流程和步驟。請注意,實際的代碼可能會因所使用的具體配置中心而有所不同。
import com.configcenter.sdk.ConfigCenterClient;
import com.configcenter.sdk.exception.ConfigCenterException;
import com.configcenter.sdk.model.Configuration;
public class ConfigurationRegistration {
public static void main(String[] args) {
// 配置中心的服務器URL和認證令牌
String serverUrl = "configcenter_server_url";
String authToken = "your_auth_token";
// 創建配置對象
Configuration configuration = new Configuration();
configuration.setId("your_configuration_id");
configuration.setKey("your_configuration_key");
configuration.setValue("your_configuration_value");
// 可選:設置其他配置項屬性,如描述、標簽等
try {
// 初始化配置中心的客戶端
ConfigCenterClient client = ConfigCenterClient.init(serverUrl, authToken);
// 調用配置中心的注冊API
boolean success = client.registerConfiguration(configuration);
if (success) {
System.out.println("配置注冊成功");
} else {
System.out.println("配置注冊失敗");
}
} catch (ConfigCenterException e) {
System.out.println("配置注冊出現異常: " + e.getMessage());
e.printStackTrace();
}
}
}
在這個示例中:
- 我們首先創建了一個Configuration對象,設置了配置項的ID、鍵(key)和值(value)。你可以根據需要設置其他屬性,如描述、標簽等。
- 然后,我們初始化配置中心的客戶端,并調用client.registerConfiguration()方法來執行配置注冊操作,傳入創建好的Configuration對象。
- 該方法將返回一個布爾值,表示注冊是否成功,我們根據返回結果打印相應的消息。
- 如果發生異常,我們進行異常處理并打印異常信息。
2、配置反注冊
配置中心的配置反注冊是指從配置中心中移除或注銷某個配置項的過程。當某個服務或應用不再需要使用某個配置項時,可以進行配置反注冊操作。這個操作通常通過配置中心提供的接口來完成,它會將指定的配置項從配置中心中刪除或標記為注銷狀態。
配置反注冊可以是手動觸發的,也可以是自動觸發的。
- 在手動觸發方式下,管理員或開發者可以通過調用配置中心提供的反注冊接口,指定需要反注冊的配置項。
- 自動觸發方式下,通常會在服務或應用停止時,自動觸發配置反注冊操作。
配置反注冊是配置中心的一個重要功能,它可以幫助管理員或開發者更好地管理配置項的生命周期,確保配置中心中的數據與實際應用需求保持一致。同時,通過反注冊不再需要的配置項,也可以減少配置中心的存儲空間和資源消耗。
要通過Java代碼實現配置反注冊,你需要使用配置中心提供的Java SDK或API。以下是一個示例代碼,展示了如何使用Java來實現配置反注冊。
import com.configcenter.sdk.ConfigCenterClient;
import com.configcenter.sdk.exception.ConfigCenterException;
public class ConfigurationDeregistration {
public static void main(String[] args) {
// 配置中心的服務器URL和認證令牌
String serverUrl = "configcenter_server_url";
String authToken = "your_auth_token";
// 初始化配置中心的客戶端
ConfigCenterClient client = ConfigCenterClient.init(serverUrl, authToken);
// 配置項的ID
String configurationId = "your_configuration_id";
try {
// 調用配置中心的反注冊API
boolean success = client.deregisterConfiguration(configurationId);
if (success) {
System.out.println("配置反注冊成功");
} else {
System.out.println("配置反注冊失敗");
}
} catch (ConfigCenterException e) {
System.out.println("配置反注冊出現異常: " + e.getMessage());
e.printStackTrace();
}
}
}
在這個示例中:
- 我們首先通過ConfigCenterClient.init()初始化配置中心的客戶端,傳入服務器URL和認證令牌。
- 然后,我們調用client.deregisterConfiguration()方法來執行配置反注冊操作,傳入配置項的ID。
- 該方法將返回一個布爾值,指示反注冊是否成功。
- 根據返回結果,我們打印相應的消息。
- 如果發生異常,我們捕獲并打印異常信息。
3、配置查看
通過配置中心的用戶界面和API接口,你可以方便地查看和管理配置項。
import com.configcenter.sdk.ConfigCenterClient;
import com.configcenter.sdk.exception.ConfigCenterException;
import com.configcenter.sdk.model.Configuration;
public class ConfigurationViewer {
public static void main(String[] args) {
// 配置中心的服務器URL和認證令牌
String serverUrl = "configcenter_server_url";
String authToken = "your_auth_token";
// 配置項的ID或鍵(key)
String configurationId = "your_configuration_id";
// 或者使用配置項的鍵(key)來獲取配置項,根據配置中心API的要求而定
// String configurationKey = "your_configuration_key";
try {
// 初始化配置中心的客戶端
ConfigCenterClient client = ConfigCenterClient.init(serverUrl, authToken);
// 調用配置中心的API接口獲取配置項
Configuration configuration = client.getConfiguration(configurationId);
// 或者使用配置項的鍵(key)來獲取:
// Configuration configuration = client.getConfigurationByKey(configurationKey);
// 輸出配置項的信息
if (configuration != null) {
System.out.println("配置項ID: " + configuration.getId());
System.out.println("配置項鍵(key): " + configuration.getKey());
System.out.println("配置項值(value): " + configuration.getValue());
// 輸出其他配置項屬性,如描述、標簽等
} else {
System.out.println("未找到配置項");
}
} catch (ConfigCenterException e) {
System.out.println("查看配置項出現異常: " + e.getMessage());
e.printStackTrace();
}
}
}
在上面的示例代碼中:
- 我們首先初始化配置中心的客戶端。
- 然后調用相應的API接口來獲取配置項。
- 在獲取到配置項后,我們可以輸出配置項的各種屬性,如ID、鍵(key)、值(value)等。
- 如果發生異常,我們進行異常處理并打印相應的異常信息。
4、配置變更訂閱
配置中心通常支持配置變更訂閱功能,允許應用程序或其他服務訂閱配置項的變更通知。當配置項發生變化時,配置中心會向訂閱者發送通知,以便訂閱者能夠及時獲取最新的配置項。
要通過Java代碼實現配置變更訂閱,你可以按照以下步驟進行操作:
- 首先,確保你已經初始化了配置中心的客戶端,如上述示例代碼所示。
- 創建一個訂閱者(listener)類,實現配置中心提供的訂閱接口。這個類將負責處理配置項的變更通知。
- 在訂閱者類中,實現接口中定義的方法,以處理配置項的變更事件。該方法通常會在配置項發生變化時被調用,并且會接收包含變更信息的參數。
- 在你的應用程序或服務中,創建一個訂閱請求(subscription request)對象,指定你希望訂閱的配置項或配置項的過濾條件。
- 使用配置中心的客戶端對象,調用訂閱方法,將訂閱請求對象和訂閱者對象作為參數傳遞給該方法。這將向配置中心注冊你的訂閱請求,并指定訂閱者類來處理變更通知。
- 一旦注冊成功,當配置項發生變更時,配置中心將調用訂閱者類中的方法,將變更信息傳遞給訂閱者。你可以在這個方法中編寫邏輯來處理配置項的變更,如更新本地緩存、重新加載配置等。
下面是一個簡單的示例代碼,展示如何實現配置變更訂閱:
import com.configcenter.sdk.ConfigCenterClient;
import com.configcenter.sdk.exception.ConfigCenterException;
import com.configcenter.sdk.listener.ConfigurationChangeListener;
import com.configcenter.sdk.model.Configuration;
public class ConfigurationSubscriber {
public static void main(String[] args) {
// 初始化配置中心的客戶端(省略代碼)
// 創建訂閱者類
ConfigurationChangeListener listener = new ConfigurationChangeListener() {
@Override
public void onConfigurationChanged(Configuration configuration) {
// 處理配置項變更事件
System.out.println("配置項發生變化: " + configuration.getKey() + " = " + configuration.getValue());
// 在這里可以更新本地緩存、重新加載配置等
}
};
try {
// 創建訂閱請求對象(根據配置中心API的要求而定)
// 指定你希望訂閱的配置項過濾條件,如配置項的鍵(key)或其他屬性
// 調用配置中心的訂閱方法
ConfigCenterClient client = ConfigCenterClient.init(serverUrl, authToken);
client.subscribeToConfigurationChanges(filter, listener);
} catch (ConfigCenterException e) {
System.out.println("配置變更訂閱出現異常: " + e.getMessage());
e.printStackTrace();
}
}
}
五、主流的微服務注冊中心有哪些,如何選擇?
1、在選擇微服務注冊中心時,可以考慮以下因素:
- 功能和特性:不同的注冊中心可能具有不同的功能和特性,需要根據自己的需求來選擇。例如,一些注冊中心可能更側重于服務發現,而另一些可能提供更全面的配置管理功能。
- 性能和穩定性:注冊中心作為微服務架構的核心組件,其性能和穩定性至關重要。需要對候選的注冊中心進行性能測試和穩定性評估,確保它們能夠滿足你的業務需求。
- 易用性和開發體驗:注冊中心的易用性和開發體驗也是選擇的重要因素。選擇一個提供良好開發文檔、客戶端庫和工具的注冊中心,可以使開發過程更加順暢高效。
- 社區支持和生態系統:一個活躍和健康的社區可以為注冊中心提供持續的支持和改進。同時,一個豐富的生態系統可以提供更多的集成選項和解決方案。因此,需要評估候選注冊中心的社區活躍度和生態系統成熟度。
- 安全性和合規性:安全性和合規性對于任何系統都至關重要。需要確保所選的注冊中心能夠提供足夠的安全保障,并滿足你的合規性要求。
最終,選擇微服務注冊中心是一個權衡的過程,需要根據自己的實際需求、技術棧、團隊熟悉度等因素進行綜合考慮。
2、主流注冊中心
在Eureka、Consul、Zookeeper和Nacos這幾個微服務注冊中心中,選擇最適合的一個取決于你的具體需求和環境。
(1)Eureka
- 是Netflix開發的服務注冊中心,與Spring Cloud集成良好。
- 保證了高可用性和最終一致性,服務注冊相對較快。
- 在數據不一致時,每個Eureka節點仍能正常對外提供服務,保證了可用性。
(2)Consul
- 使用Go語言編寫,具有較好的跨平臺性。
- 提供了豐富的功能和強大的一致性保證。
- 支持多數據中心和分布式部署,適合大規模環境。
(3)Zookeeper
- 最初是一個分布式協調服務,后來被用于服務注冊和發現。
- 提供了強一致性和高可用性,但相對較復雜,需要自行實現一些服務發現功能。
(4)Nacos
- 是阿里巴巴開源的項目,支持基于DNS和基于RPC的服務發現。
- 除了服務注冊和發現,還支持動態配置服務。
- 在Spring Cloud中使用較為簡單,只需簡單的配置即可完成服務的注冊和發現。
3、如何選擇?
- 如果你使用Spring Cloud作為微服務框架,Eureka可能是一個自然的選擇,因為它與Spring Cloud集成良好。
- 如果你需要強大的跨平臺支持和一致性保證,Consul是一個不錯的選擇。
- 如果你已經在使用Zookeeper或其他Apache項目,并且希望在同一生態系統中解決服務注冊和發現問題,那么Zookeeper可能適合你。
- 如果你在尋找一個簡單且與阿里巴巴技術棧集成的解決方案,Nacos是一個值得考慮的選項。
最終的選擇應基于你的技術需求、團隊熟悉度和業務場景。