第三節:基於Consul做服務的配置中心


一. 簡介

本節架構圖:

(PS:該圖僅服務於本節,完整版的微服務架構圖見后最后章節)

1.什么是配置中心

 配置中心通俗的說就是在程序不重啟的情況下,動態的修改程序的配置文件。

 通俗的解釋:在微服務體系中,實際上就是把各個業務服務器的配置文件 eg:appsettings.json或其它配置文件中的內容copy到配置中心中,然后將業務服務器讀取配置文件的流程改成 從配置中心中加載,這樣就可以實現修改配置中心的內容,業務服務器自動同步哦---- 說白了這里本地的 appsetting.json 已經沒用了。

PS. 我們其實完全可以使用DB或者NoSql自己來實現簡單的配置中心哦.

2.用配置中心的背景

 安全性:配置跟隨源代碼保存在代碼庫中,容易造成配置泄漏。

 時效性:修改配置,需要重啟服務才能生效。

 局限性:無法支持動態調整:例如日志開關、功能開關。

因此,分布式配置中心應運而生!

3.常見配置中心

 (1).Consul

  go開發

  依賴:不依賴其他組件  

  應用內/外:屬於外部應用,侵入性小

  ACP原則:遵循CP原則(一致性+分離容忍) 服務注冊稍慢,由於其一致性導致了在Leader掛掉時重新選舉期間真個consul不可用。

  版本迭代:目前仍然進行版本迭代

  集成支持:支持SpringCloud K8S集成

  訪問協議:HTTP/DNS

  雪崩保護:不支持雪崩保護

  集成:SpringCloud集成,K8S集成

  自動注銷實例:不支持

  界面:英文界面,不符合國人習慣

  上手:復雜一點

(2).Apollo

  java開發 ----- 運維成本比高

  Apollo分為MySQL,Config Service,Admin Service,Portal四個模塊,MySQL存儲Apollo元數據和用戶配置數據; Config Service提供配置的讀取、推送等功能,客戶端請求都是落到Config Service上;Admin Service提供配置的修改、發布等功能,Portal操作的服務就是Admin Service; Portal提供給用戶配置管理界面;功能強大,社區活躍,但較為復雜,部署組件較多,運維成本比高

(3).Nacos

  依賴:mysql

  應用內/外:屬於外部應用,侵入性小

  ACP原則:通知遵循CP原則(一致性+分離容忍) 和AP原則(可用性+分離容忍)

  版本迭代:目前仍然進行版本迭代,最近的提交是幾天前

  集成支持:支持Dubbo 、SpringCloud、K8S集成

  訪問協議:HTTP/動態DNS/UDP

  雪崩保護:支持雪崩保護

(4).Spring cloud config

  java開發 ----- Net支持比較差

  自動注銷實例:支持

  界面:國產服務,中文界面,符合國人習慣

  上手:極易,中文文檔,案例,社區活躍

  總結:Consul實際上是和Nacos比較相似的產品,雖然Consul目前的主要發展方向放在了Service Mesh,但是Consul最初支持的服務發現和配置管理,也是Nacos的兩大功能。雖然Nacos在Consul之后以與之相似的部署架構開源,但這並不意味着Nacos在功能和架構上也模仿Consul,Nacos的架構和功能是由阿里巴巴內部十年的運行演進經驗得來,所以二者的比較也一定會讓大家更加了解他們的定位和演進方向是完全不一樣的。

 

二. Core中的配置

   關於Core中的配置相關詳見:第十節:Asp.Net Core 配置詳解和選項模式

1.說明

  在core mvc中也有一套配置系統,通過修改屬性reloadOnChange: true,即配置文件修改后,會被自動加載哦。

2.測試

 (1).首先將配置文件都改成 “始終復制”或者“較新則復制”

 (2).test1.json 和 test2.json,要通過代碼加載進來,config.AddJsonFile("Config/test1.json", optional: true, reloadOnChange: true); 其中reloadOnChange: true,表示配置文件修改后,程序自動加載。

代碼如下:

  public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                //配置相關(這里是用來測試Core本身配置系統的,與Consul配置中心沒有任何關系哦)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                   //1. 設置當前目錄為基礎目錄(后面則可以用相對路徑)
                    config.SetBasePath(Directory.GetCurrentDirectory());
                    //2. 加載json文件 (配置后面兩個參數為true,當配置文件發生變化的時候,會自動更新加載,而不必重啟整個項目)
                   config.AddJsonFile("Config/test1.json", optional: true, reloadOnChange: true);
                    config.AddJsonFile("Config/test2.json", optional: true, reloadOnChange: true);
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

 (3).注釋掉上面從consul加載配置的代碼

 (4).通過指令啟動項目 【dotnet ConfigCenterTest.dll --urls="http://*:7060" --ip="127.0.0.1" --port=7060】

 (5).用PostMan測試,發送Get請求:http://127.0.0.1:7060/api/Home/GetMsg2 獲取原配置中的內容;

     修改test1.json中的內容(一定要去運行的bin文件中修改,不是在代碼中修改哦),重新用postman獲取,獲取的是修改后的內容,這期間項目並沒有重啟,至此,大功告成。

原運行結果:

修改后的運行結果:

 

三. Consul配置中心的應用

補充:

  既然前面的Core已經可以實現動態加載,為什么還要有配置中心呢?

  Reason:微服務會有很多個,分別部署在不同服務器上,去每個服務器修改配置還是很麻煩,這里Consul提供了一個統一的入口,維護更方便。

1.准備條件

 (1).新建WebApi項目ConfigCenterTest,配置支持命令行啟動.

    【dotnet ConfigCenterTest.dll --urls="http://*:7060" --ip="127.0.0.1" --port=7060】

 (2).通過Nuget安裝【Winton.Extensions.Configuration.Consul 3.1.0】

 PS. 這里用ConfigCenterTest項目來單純的演示配置中心功能,在整個微服務體系中需要再各個業務服務器中加上“讀取配置中心”的代碼。

 (3).通過指令【consul.exe agent -dev】啟動Consul

 PS. 這里用的Consul是以開發模式來演示,不能持久化數據,真實環境中要用生產模式,來持久化數據。

2.三種配置模式

(1).單服務單配置

 a.訪問 http://127.0.0.1:8500/ 客戶端, 然后在"Key/Value"選項卡中,以appsettings.json為鍵,將其內容copy到里面作為值進行保存。

 b.在Program中ConfigureAppConfiguration,通過 config.AddConsul("appsettings.json",xxx),表示從Consul中讀取配置文件。

            public static IHostBuilder CreateHostBuilder(string[] args) =>
                 Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    //1.添加命令行支持(寫在上面的Main里也可以)
                    var config = new ConfigurationBuilder().AddCommandLine(args).Build();

                    //2.從Consul中讀取配置文件的3種模式
                    //2.1 單服務單配置模式                   webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        // 加載默認配置信息到Configuration
                        hostingContext.Configuration = config.Build();
                        config.AddConsul("appsettings.json", options =>
                        {
                            options.ConsulConfigurationOptions = cco => { cco.Address = new Uri("http://127.0.0.1:8500"); }; // 1、consul地址
                            options.Optional = true; // 2、配置選項
                            options.ReloadOnChange = true; // 3、配置文件更新后重新加載
                            options.OnLoadException = exceptionContext => { exceptionContext.Ignore = true; }; // 4、忽略異常
                        });
                        hostingContext.Configuration = config.Build(); // 5、consul中加載的配置信息加載到Configuration對象,然后通過Configuration 對象加載項目中
                    });
                    webBuilder.UseStartup<Startup>();
                });

 c.用PostMan測試,發送Get請求:http://127.0.0.1:7060/api/Home/GetMsg 獲取原配置中的內容; 此時,在客戶端中改一下,重新用postman獲取,獲取的是修改后的內容,至此,大功告成。

[HttpGet]
public string GetMsg()
{
   var DbStr = Configuration["DbStr"];
   var userName = Configuration["userName"];
   var pwd = Configuration["pwd"];
   return $"DbStr={DbStr},userName={userName},pwd={pwd}";
}

原運行結果:

在Consul客戶端中修改后的運行結果:

(2).多服務單配置

 背景:上述①中的配置模式,如果是多個服務,每個服務都會對應一個appsettings.json,首先在Consul客戶端上同一目錄下是沒法創建的.

 解決方案:利用文件夾分層的方式,在Consul客戶端上一個項目對應一個文件夾,然后在各自文件夾下放各自的appsettings.json, 如:ConfigCenterTest/appsettings.json、GoodsService/appsettings.json然后在Program加載配置文件的時候,動態獲取項目名稱,進行路徑的組裝即可.

 var evn = hostingContext.HostingEnvironment;

 config.AddConsul($"{evn.ApplicationName}/appsettings.json", options =>{})

 

 代碼分享:

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    //1.添加命令行支持(寫在上面的Main里也可以)
                    var config = new ConfigurationBuilder().AddCommandLine(args).Build();
                    //2.從Consul中讀取配置文件的3種模式
                    //2.2 多服務單配置模式
                    webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        // 加載默認配置信息到Configuration
                        hostingContext.Configuration = config.Build();
                        //動態獲取項目名稱
                        var evn = hostingContext.HostingEnvironment;
                        config.AddConsul($"{evn.ApplicationName}/appsettings.json", options =>
                        {
                            options.ConsulConfigurationOptions = cco => { cco.Address = new Uri("http://127.0.0.1:8500"); }; // 1、consul地址
                            options.Optional = true; // 2、配置選項
                            options.ReloadOnChange = true; // 3、配置文件更新后重新加載
                            options.OnLoadException = exceptionContext => { exceptionContext.Ignore = true; }; // 4、忽略異常
                        });
                        hostingContext.Configuration = config.Build(); // 5、consul中加載的配置信息加載到Configuration對象,然后通過Configuration 對象加載項目中
                    });
                    webBuilder.UseStartup<Startup>();
                });

(3).多服務多配置

 背景:如果有多個服務,每個服務還需要多個配置文件,上①②都解決不了.

 解決方案:首先要把所需的所有配置文件都手動copy到指定項目文件夾的consul中,然后在②的基礎上多加幾個config.AddConsul($"{evn.ApplicationName}/test1.json", options =>{})等等,即可。

 測試:

  用PostMan測試,發送Get請求:http://127.0.0.1:7060/api/Home/GetMsg2 獲取原配置中的內容;修改test1.json中的內容,重新用postman獲取,獲取的是修改后的內容,至此,大功告成.

 注:這里不需要做配置文件的本地加載,因為已經改為從Consul中讀取了,不需要config.AddJsonFile(xxx)!!!

 PS:該方案也適用於單服務多配置哦.

 

代碼分享:

  public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    //1.添加命令行支持(寫在上面的Main里也可以)
                    var config = new ConfigurationBuilder().AddCommandLine(args).Build();
                    //2.從Consul中讀取配置文件的3種模式
                    //2.3 多服務多配置模式
                    webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        // 加載默認配置信息到Configuration
                        hostingContext.Configuration = config.Build();
                        //動態獲取項目名稱
                        var evn = hostingContext.HostingEnvironment;
                        config.AddConsul($"{evn.ApplicationName}/appsettings.json", options =>
                        {
                            options.ConsulConfigurationOptions = cco => { cco.Address = new Uri("http://127.0.0.1:8500"); }; // 1、consul地址
                            options.Optional = true; // 2、配置選項
                            options.ReloadOnChange = true; // 3、配置文件更新后重新加載
                            options.OnLoadException = exceptionContext => { exceptionContext.Ignore = true; }; // 4、忽略異常
                        });
                        config.AddConsul($"{evn.ApplicationName}/test1.json", options =>
                        {
                            options.ConsulConfigurationOptions = cco => { cco.Address = new Uri("http://127.0.0.1:8500"); }; // 1、consul地址
                            options.Optional = true; // 2、配置選項
                            options.ReloadOnChange = true; // 3、配置文件更新后重新加載
                            options.OnLoadException = exceptionContext => { exceptionContext.Ignore = true; }; // 4、忽略異常
                        });
                        config.AddConsul($"{evn.ApplicationName}/test2.json", options =>
                        {
                            options.ConsulConfigurationOptions = cco => { cco.Address = new Uri("http://127.0.0.1:8500"); }; // 1、consul地址
                            options.Optional = true; // 2、配置選項
                            options.ReloadOnChange = true; // 3、配置文件更新后重新加載
                            options.OnLoadException = exceptionContext => { exceptionContext.Ignore = true; }; // 4、忽略異常
                        });
                        hostingContext.Configuration = config.Build(); // 5、consul中加載的配置信息加載到Configuration對象,然后通過Configuration 對象加載項目中
                    });

                    webBuilder.UseStartup<Startup>();
                });

3. 應用

 (1).動態切換數據庫鏈接

  在配置中心中修改數據庫連接字符串,代碼中配合:

  xxxContext.Database.GetDbConnection().ConnectionString = Configuration["DbStr"];    即可實現動態切換數據庫.

 (2).切換數據源,充當一個開關.

  比如:flag=true,從緩存中讀數據,flag=false,從db中讀數據

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM