1. 程式人生 > >Asp.Net Core與攜程阿波羅(Apollo)的第一次親密接觸

Asp.Net Core與攜程阿波羅(Apollo)的第一次親密接觸

img

一、瞎扯點什麼

1.1 阿波羅

​ 阿波羅是希臘神話中的光明之神、文藝之神,同時也是羅馬神話中的太陽神;他是光明之神,從不說謊,光明磊落,在其身上找不到黑暗,也被稱作真理之神。他非常聰明,通曉世事,是預言之神。

後世各種各樣的專案都喜歡以阿波羅命名,比如著名的美國登月計劃:阿波羅計劃;

既然攜程以阿波羅(Apollo)命名專案,那我們我們接下來看看,攜程阿波羅能給我們程式設計師帶來怎樣的光明(我希望這個光明是可以每天下午6點鐘的太陽 哈哈);

下面看看.net core和Apollo會碰撞出什麼樣的火花吧

二、攜程阿波羅(Apollo)

2.1簡單介紹

在這之前,我們先看官方是怎麼介紹的:

Apollo(阿波羅)是攜程框架部門研發的分散式配置中心,能夠集中化管理應用不同環境、不同叢集的配置,配置修改後能夠實時推送到應用端,並且具備規範的許可權、流程治理等特性,適用於微服務配置管理場景。

講的很清楚,攜程阿波羅(後面簡稱Apollo)是一個分散式配置中心,就是管理配置程式配置地方;Apollo服務端基於Spring Boot和Spring Cloud開發(對的,就是微服務框架),打包後可以直接執行,不需要額外安裝Tomcat等應用容器。

Apollo有以下特點:

  • 統一管理不同環境、不同叢集的配置
  • 配置修改實時生效(熱釋出)
  • 版本釋出管理
  • 灰度釋出
  • 許可權管理、釋出稽核、操作審計
  • 客戶端配置資訊監控
  • 提供Java和.Net原生客戶端
  • 提供開放平臺API
  • 部署簡單

具體每一項展開是什麼意思,我就不多說了,更多介紹請看Apollo配置中心介紹

再多說一句,截止到這篇部落格編寫時間為止,Apollo在github已經有9300+個star了;

並擁有眾多的生產使用案例;

2.2使用場景

我們設想一下,我們微服務架構中,我們一個每一個服務都可能部署到5~10機器上,我們有很幾十個各種各樣的服務;比如某一天,我們機房因為網路問題,必須更換資料庫伺服器ip,業務介面ip等;如果人工去一臺機一臺機地改,哇,那就就頭痛了。。。

不止是微服務,做開發這麼多年,經常因配置的問題引發生產環境的bug。有些年久的專案,幾百個密密麻麻的配置項,經常容易搞混,有時好幾個專案有好多同樣的配置項,經常被配置問題,或者配置衍生的問題搞得奄奄一息;這時候或者選用一個配置管理中心,也是個不錯的選擇;

有人說,我做了用了Jenkins或者什麼做了自動化部署的,不是提交一下程式碼就可以了嗎;確實,自動化部署環境確實也可以做到配置的“一處更改,所有引用起效”的效果;但是,映象的打包失敗,打包時間過長等問題,也需要考慮進來的;

所以,綜合來說,在配置人工管理困難的時候或者說成本較高的時候;使用配置中心是一個合理的選擇;

img

三、Apollo的安裝與配置

3.1 環境

windows10 64bit 專業版
8G記憶體

這次是我的本地環境,不是騰訊雲了

3.2 安裝

我也在學習中,演示的是本地測試環境的安裝與配置,生產環境請參考分散式部署指南

我這裡是普通方式的安裝,docker方式請參考Apollo Quick Start Docker部署

1、依次安裝以下程式

Java 1.8+

Mysql 5.6.5+ (Apollo的表結構對timestamp使用了多個default宣告,所以需要5.6.5以上版本。)

GitBash (安裝參考)

下載apollo-build-scripts專案到本地

2、建立資料庫

分別執行下面兩個初始化的資料庫sql:

apolloconfigdb.sql

apolloportaldb.sql

執行完成我們得到:

1542806085229

3、修改配置檔案

修改剛剛下載專案apollo-build-scripts根目錄下面的demo.sh

#!/bin/bash

# apollo config db info
apollo_config_db_url=jdbc:mysql://`139.199.196.67`:3306/ApolloConfigDB?characterEncoding=utf8
apollo_config_db_username=`root`
apollo_config_db_password=`password`

# apollo portal db info
apollo_portal_db_url=jdbc:mysql://`139.199.196.67`:3306/ApolloPortalDB?characterEncoding=utf8
apollo_portal_db_username=`root`
apollo_portal_db_password=`password`

4、啟動

gitbash執行:

./demo.sh start

靜候片刻,看到以下表示啟動成功(不一定一模一樣):

1543245209761

注意檢查資料庫配置,確認無誤後執行demo.sh,如果有報錯多執行兩次看看,因為我也有

“Config service failed to start in 120 seconds! Please check ./service/apollo-service.log for more information.”

這個報錯,然後再次執行才啟動成功的;

接著如提示訪問 http://127.0.0.1:8070

1542792843089

ok,我們登入看看,預設賬號密碼是:apollo/admin

我們看到已經有一個SampleApp,作為配置參考了

1542808265590

1542808341712

根據提示,我們再訪問一下 8080 埠:

我知道 Eureka 是java那邊比較喜歡用的服務註冊中心,是一個跟consul差不多一樣的東西,我也不太熟,先放著;

到這一步,Apollo我們已經安裝成功了;接下來我們先參照SampleApp新增一個我們自己的app,為.net core程式的與她的親密接觸做準備;

1542808483430

四、建立/配置Apollo專案

4.1 新建專案

建立一個叫myDotnet的專案

部門資料在ApolloPortalDB庫ServerConfig表裡配置

1542809520034

提交後我們看到如下提示,什麼是Namespace??擦 需要補課;1542814456082

4.2 什麼是Namespace

官方Apollo核心概念之Namespace已經講得很清楚了。這裡是我的理解,看看能不能概括一下:

  • Apollo每一個專案下面都可以有多個Namespace,每一個Namespace都類似於我們開發中的一個配置檔案。比如appsetting.json
  • Namespace有兩種許可權(對客戶端讀取設定的許可權):
    • private:只能被所屬的應用獲取到,像放在當前執行程式目錄下的配置;
    • public:共有的配置,能被所有的引用獲取到。像放在共享目錄的配置;
  • Namespace有三種類型(歸類,給不同的歸類設定不同的許可權屬性):

    • 私有型別:私有型別的Namespace具有上訴的private許可權。
    • 公共型別:公共型別的Namespace具有上訴public許可權,即任何應用都可獲取;
    • 關聯型別(繼承型別):比如我們經常配置的timeout,公共配置timeout=60;,然後我本地可以配置的一個timeout=90;覆蓋公共配置這種情景;

4.2.2 示例

如下圖所示,有三個應用:應用A、應用B、應用C。

  • 應用A有兩個私有型別的Namespace:application和NS-Private,以及一個關聯型別的Namespace:NS-Public。
  • 應用B有一個私有型別的Namespace:application,以及一個公共型別的Namespace:NS-Public。
  • 應用C只有一個私有型別的Namespace:applicationNamespace例子
2.2.1 應用A獲取Apollo配置
  //application 
  Config appConfig = ConfigService.getAppConfig();
  appConfig.getProperty("k1", null); // k1 = v11
  appConfig.getProperty("k2", null); // k2 = v21
  
  //NS-Private
  Config privateConfig = ConfigService.getConfig("NS-Private");
  privateConfig.getProperty("k1", null); // k1 = v3
  privateConfig.getProperty("k3", null); // k3 = v4
  
  //NS-Public,覆蓋公共型別配置的情況,k4被覆蓋
  Config publicConfig = ConfigService.getConfig("NS-Public");
  publicConfig.getProperty("k4", null); // k4 = v6 cover
  publicConfig.getProperty("k6", null); // k6 = v6
  publicConfig.getProperty("k7", null); // k7 = v7
2.2.2 應用B獲取Apollo配置
  //application
  Config appConfig = ConfigService.getAppConfig();
  appConfig.getProperty("k1", null); // k1 = v12
  appConfig.getProperty("k2", null); // k2 = null
  appConfig.getProperty("k3", null); // k3 = v32
  
  //NS-Private,由於沒有NS-Private Namespace 所以獲取到default value
  Config privateConfig = ConfigService.getConfig("NS-Private");
  privateConfig.getProperty("k1", "default value"); 
  
  //NS-Public
  Config publicConfig = ConfigService.getConfig("NS-Public");
  publicConfig.getProperty("k4", null); // k4 = v5
  publicConfig.getProperty("k6", null); // k6 = v6
  publicConfig.getProperty("k7", null); // k7 = v7
2.2.3 應用C獲取Apollo配置
  //application
  Config appConfig = ConfigService.getAppConfig();
  appConfig.getProperty("k1", null); // k1 = v12
  appConfig.getProperty("k2", null); // k2 = null
  appConfig.getProperty("k3", null); // k3 = v33
  
  //NS-Private,由於沒有NS-Private Namespace 所以獲取到default value
  Config privateConfig = ConfigService.getConfig("NS-Private");
  privateConfig.getProperty("k1", "default value"); 
  
  //NS-Public,公共型別的Namespace,任何專案都可以獲取到
  Config publicConfig = ConfigService.getConfig("NS-Public");
  publicConfig.getProperty("k4", null); // k4 = v5
  publicConfig.getProperty("k6", null); // k6 = v6
  publicConfig.getProperty("k7", null); // k7 = v7

仔細看完示例應該理解了,如果實在不瞭解,我們後面用示例自己去體會;

4.3 新增Namespace和配置項

我們在上面的myDotnet專案下面,分別新增一個Public型別的Namespace和一個Private型別的Namespace;

其中:

Hei.Public:Public型別,存放Mongodb連線,Redis連線等幾乎每個程式都需要用到的公共配置;

Hei.Private:Private型別,存放當前web應用程式需要使用的連線,比如title,keyword,description;

1542850762853

新增配置

紅圈的地方,有提示Public型別的Namespace能被任何應用讀取

新增完配置記得一定要點擊發布,別問我怎麼知道的。。。。

1543283593089

小tips:這些配置可以以文字形式,快速 批量新增的:

1543283919947

五、與Asp.Net Core的親密接觸(使用)

5.1 簡單使用

1、引用nuget包:Com.Ctrip.Framework.Apollo.Configuration 

1542852719125

2、新增配置

修改appsetting.json,新增Apollo節點配置:

"apollo": {
    "AppId": "myDotnet",  //這是我們上面新增的Apollo裡面的Appid
    "MetaServer": "http://127.0.0.1:8080" //Apollo配置伺服器地址,注意這裡是8080,不是admin的8070
  }

3、修改Program.cs,修改為:

   public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, builder) =>
                {
                    builder
                    .AddApollo(builder.Build().GetSection("apollo"))
                    .AddDefault() //預設的application Namespace
                    .AddNamespace("TEST1.Hei.Public ") //public 型別的Namespace
                    .AddNamespace("Hei.Private");//private 型別的Namespace
                })
                .UseStartup<Startup>();

非常簡單,我們總共就修改了這3個地方,用起來也跟獲取本地配置幾乎無差;

1543284034098

來,我們看看執行結果:

Public型別的:

1543284400433

Private型別的:

1543284433973

測試的時候可以隨時在Apollo後臺修改配置 釋出後,重新整理連結;可以看到,配置即時起效的。

5.2 高階用法

其實也不是什麼高階用法。。。

像什麼回滾功能很容易理解;灰度釋出,大家也可以試著用一下;

1、關聯型別的Namespace

大家注意,我們之前一直使用的應用都是:myDotnet現在我們再新增一個netcore的應用,並且這個應用有一個Public的Namespace TEST2.Hei.Globa

注意這裡的MongoDB 跟上面的 myDotnet的配置的值不一樣了

1543287894670

然後,我們給myDotnet 關聯上這個 netcoreTEST2.Hei.Globa ,就等於myDotnet下面多了一個Namespace:

1543287820353

看到myDotnet下面多了一個Namespace:

1543288136940

修改下Program.cs

1543288281731

然後我們看看配置:

MongoDB:還是以myDotnet的為準。

1543287947865

MysqlVersion:

1543288318925

2、監聽配置的變化

偷懶直接上程式碼:

   private static void OnChanged(object sender, ConfigChangeEventArgs changeEvent)
        {
            Console.WriteLine("Changes for namespace {0}", changeEvent.Namespace);
            foreach (string key in changeEvent.ChangedKeys)
            {
                ConfigChange change = changeEvent.GetChange(key);
                Console.WriteLine("Change - key: {0}, oldValue: {1}, newValue: {2}, changeType: {3}", change.PropertyName, change.OldValue, change.NewValue, change.ChangeType);
            }
        }

        static void Main(string[] args)
        {
            Config config = ConfigService.GetAppConfig(); //config instance is singleton for each namespace and is never null
            config.ConfigChanged += OnChanged;

            while (true)
            {
                Thread.Sleep(500);
                var timeout = config.GetProperty("timeout", "");
                Console.WriteLine(timeout);
            }
        }

總結

​ 這篇文章的目的,是希望能給大家提供兩點參考:Apollo是什麼?Apollo可以做什麼?

達到這兩點也就差不多了;至於Apollo提供的更多功能大家可以慢慢體會,我也在學習當中。至於Apollo的效能、穩定性這些,Apollo目前已經有不少公司落地使用了,是社群裡面非常熱的產品,說這些問題,應該都已解決。最後,我也是學習當中,有寫的不對的地方,大家指正,歡迎交流。

demo原始碼地址

[參考]

https://github.com/ctripcorp/apollo/wiki/

https://www.cnblogs.com/edisonchou/p/9419379.html