微服務框架之微軟Service Fabric

天府雲創發表於2018-06-14

常見的微服務架構用到的軟體&元件:

docker(成熟應用)

spring boot % spring cloud(技術趨勢)

Service Fabric(屬於後起之秀 背後是微軟雲的驅動)

四種常用的微服務架構方案,分別是ZeroC IceGrid、Spring Cloud、基於訊息佇列與Docker Swarm。

實際生產中多半是組合的模式運用例如最佳實踐spring cloud+docker。

微服務特性——持續整合(Jenkins,Snap-CI),構建(Maven,Gradle),部署(Docker),持續交付(Jenkins),日誌聚合(ELK,Splunk),運維(監控警告Zabbix,Nagios) 

微軟的 Azure Service Fabric 的官方部落格在2017.3.24日釋出了一篇部落格 Service Fabric .NET SDK goes open source ,介紹了社群呼聲最高的 Service Fabric 開源的情況以及當前的情況,當時開源了 Service Fabric的.NET SDK 部分,社群一直在期盼著 Service Fabric 的正式開源,經過了一年漫長的等待,2018年3月14日微軟終於開源了 Service Fabric ,而且是以 MIT 許可下開放原始碼,在官方部落格宣佈 https://blogs.msdn.microsoft.com/azureservicefabric/2018/03/14/service-fabric-is-going-open-source。

    目前微軟在 Github 上的開源地址是 https://github.com/Microsoft/service-fabric,目前的程式碼構建適用於 Linux 的 Service Fabric ,執行基本測試,有問題可以在上面提交 issue 和 PR 了,Windows 構建環境以及完整的 CI 環境還沒有遷移過來。Windows 內部為 Service Fabric 開發了將近十年的內部服務,其中大部分時間都是微軟內部平臺,比如 Office365,Azure Stack 平臺等,這意味著我們有近十年的內部微軟工具可以在遷移之前完成遷移和流程細化,逐步全部開源,以後全部開發都在開源模式下進行開發工作。

Service Fabric基本概念: Node, Application, Service, Partition/Replicas

Azure Service Fabric 是一款分散式系統平臺,可方便使用者輕鬆打包、部署和管理可縮放的可靠微服務和容器。 開發人員和管理員不需解決複雜的基礎結構問題,只需專注於實現苛刻的任務關鍵型工作負荷,即那些可縮放、可靠且易於管理的工作負荷。

     本節將為大家介紹Azure Service Fabric的基本概念及相關元件的工作機制, 包括Micro Service, Node type, Node等等。雖然名稱叫Azure Service Fabric但其可應用的平臺遠不止Azure平臺本身,我們會在後續章節的使用場景中為大家專門描述Service Fabric在各大平臺上的工作形式。

Microsoft Azure Service Fabric是微軟開發的一套支撐高可用高伸縮雲服務的框架,其核心部分是一個分散式系統平臺,用於構建可擴充套件的可靠應用。在便於封裝可部署程式碼的同時,支援建立無狀態和有狀態的微服務,通過雲平臺來伸縮他們,來應對高複雜度、低延遲、資料密集的情況。開發者和系統管理員可以免於處理複雜的基礎設施問題,將精力更多地投入到所構建應用程式的實現上。

 

 

微服務Microservice

在具體介紹Service Fabric之前,不得不先提一下微服務的思想。因為使用Service Fabric的開發過程就是微服務的設計開發過程。有了Service Fabric,您只需要考慮開發微服務的功能,而無需過多考慮部署後的伸縮性和可用性的問題,這些問題都可以交給Service Fabric來幫您實現。

微服務的思想就是將複雜單體式應用程式解耦成多個各個獨立的服務,在功能不變的情況下,被分解出來的多個可管理的服務可以通過約定的介面相互通訊。這種方法為採用單體式編碼很難實現的功能提供了模組化的解決方案。因為,單個服務可以更易於開發、維護。這種架構方式使每個單個服務都可以有專門的團隊來開發,每個團隊可以各自選擇自己擅長的開發技術,通過約定介面來實現相互通訊。每個服務可以獨立實現、測試、部署和升級,開發者不再需要擔心其他服務部署對本服務的影響。AB測試加快了部署的速度,從而實現持續整合持續部署。所有微服務作為一個整體為使用者提供服務,同時各個微服務可以根據自身對資源的需求獨立擴充套件,從而最大化伺服器的資源利用率。

回到Service Fabric, 一個Service Fabric開發的應用程式由數個服務組成,每個服務可以作為個體獨自修改、擴充套件和管理,同時可以按照一個完整的應用程式來管理。Service fabric的設計目的就是用微服務的方式來簡化構建複雜應用的過程。

 

叢集Cluster

叢集是一組通過網路連線的虛擬或者物理主機,您的微服務就部署在叢集中,叢集的大小可以擴充套件到上千臺主機。

 

節點Node

叢集中的一臺機器或者VM稱為Node, 每個Node會被分配一個名稱(string字串)。Node還有其他一些屬性,比如位置屬性placement properties。可以通過每臺機器或者VM都有一個自啟動Windows系統服務FabricHost.exe,它隨系統啟動後會執行另外兩個程式:Fabric.exe 和 FabricGateway.exe, 這兩個程式就組成了一個完整的Node。出於測試目的,有時單臺機器上也可以通過執行多個Fabric.exe 和 FabricGateway.exe的例項來擁有多個Node。

一個叢集中的所有Node相互之間平等且可以直接互相通訊。Node除了宿主在物理主機或VM中,還可以宿主在基於Windows的Docker容器中、本地部署的伺服器中、其他公有云和私有云中,我們會在後續Service Fabric的使用場景中為大家詳細介紹這一內容。

 

 

應用程式Application:Application Type和Service Type

Service Fabric應用程式(Application)是一組服務(service)的集合,其中一個service是為Application提供指定功能的單元。您將通過定義一個Application Type和對應的幾個Service Type來構建一個Service Fabric的Application. 當Application被部署到Service Fabric Cluster裡面時,這些型別會被相應地初始化成application例項和service例項。這裡類似我們OO地思想。

Application Type和Named Application: Application Type包含一組Service Type的集合,對應上文中的Service Fabric應用程式(Application)是一組服務(service)的集合。 Application Type的name和version定義在ApplicationManifest.xml檔案中。在部署的時候,ApplicationManifest.xml會被拷貝到Service Fabric的image store中。通過在Cluster中建立Named Application來初始化Application的例項。Named Application通過"fabric:/MyNamedApp"的形式來命名。

Service Type和Named Service: Service Type的name和version定義在ServiceManifest.xml檔案中。當建立好一個Named Application後,就可以建立Named service. 例如您在 "MyNamedApp" Named Application中建立一個 "MyDatabase" Named Service, Name Service被命名為 "fabric:/MyNamedApp/MyDatabase".

 

 

 

分割槽Partitions和複製replicas

一個service可以包含多個分割槽Partition,Service Fabric通過使用分割槽作為擴充套件的機制來將工作分佈到不同的service例項上。

一個分割槽Partition可以包含一個或者多個複製replicas。Service Fabric通過使用複製來實現可用性。一個分割槽可以有一個主複製和多個從複製,多個複製之間的狀態可以自動同步。當主複製出現錯誤時,其中一個從複製被自動提升為主複製,以保證系統的可用性。然後將從複製的個數恢復到正常水平,保證足夠的從複製冗餘。


使用Visual Studio+Service Fabric執行Spring Boot微服務

Service Fabric是微軟提供的微服務管理框架,經過了微軟Cosmos DB等多個產品的驗證。

Service Fabric官方文件只提供了Visual Studio + .net + C#的開發部署方案和Linux + Eclipse + Java的部署方案,但沒有Visual Studio+Eclipse+Java的部署方法,通過摸索和文件,發現微軟提供了這樣的途徑,微軟真是比以前開放多了。

1. 首先在Visual Studio中建立Service Fabric工程,


2. 選擇來賓可執行檔案,輸入第一個微服務的名稱,選擇可執行的jar包所在檔案目錄,Work Folder選為CodeBase,


3. 在VS專案樹中,選擇Jar包,同時將java執行環境包複製/貼上到code目錄中,





4.  開啟"ServiceManifest.xml", 更改以下引數,

  1. Program: This should point to java.exe file in JRE folder that was copied.
  2. Arguments: This should contain the -jar and path of the JAR filename relative to java.exe. They are arguments passed to java.exe when it starts.
  3. WorkingFolder: This should be CodeBase.
  4. Endpoint: Name a endpoint and provide protocol as HTTP and port no (8080) along with type(input)

5. 點選Start按鈕,就可以將此微服務部署搭配本地Service Fabric Cluster上了。


【案例深度講解】利用Service Fabric承載eShop On Containers

從模組化到微服務化

從Pet Shop 到eShop on Container都是Microsoft在技術演進的路徑上給開發者展示.Net的開發能力和架構能力的Sample工程,Petshop的時候更多的是展現應用的分層架構,設計的抽象與模組間的通訊。到了eShop on Container更多的關注在架構設計與微服務化的,下面我們先來看看eshop on Container的架構圖

在上圖,我們可以看到後端服務分成了

  1. Identity microservice(驗證服務)
  2. Catalog microservice(商品分類服務)
  3. Ordering microservice(訂單服務)
  4. Basket microservice(購物車服務)
  5. Marketing microservice(市場營銷服務)
  6. Locations microservice(地理位置資訊服務)

在以前的分層架構中,通常這些服務都是以某一模組來體現的,為什麼現在要將他們拆分成了各個服務呢?當我們從業務場景上面來看這些服務時,我們會發現每個服務的訪問峰值時間區間、容量規劃都是不一樣的,甚至實現這些服務最方便最簡單的技術棧都有可能是不一樣的(當然強大的.net core無所不能,但是公司內不同業務線上的技術儲備不一樣,就有可能選擇不同的技術實現)。這是因為如果我們都將這些模組整合到了一個程式或者服務中的時候,就會碰到在不同時間內服務高峰期擴充套件系統容量困難,要不就是資源不足,要不就是資源過剩。譬如搶購業務開始前大家提前個半小時登入了系統,這時候系統最忙的是登入模組,到了開始搶購時間,系統最忙的是訂單模組。不採用微服務架構的話,半小時前準備給登入模組使用的資源不一定能夠及時的釋放出來給訂單模組。如果兩個模組都使用單一程式架構的話,很可能出現的情況就是搶購的業務把所有資源都佔滿了了,連其他正常訪問系統的使用者資源都被佔用掉,導致系統崩潰。在講究Dev/Ops的今天,開發人員和架構師需要更多的考慮硬體架構層面對程式應用帶來的影響。

用Service Fabric來承載eShop on Container微服務的方法一,通過Service Fabric直接管理Docker

首先我們先到Azure上申請一個Container Registry來承載eShop各個微服務程式的映象(image).建立Azure Docker Registry可以參考官方文件:https://docs.microsoft.com/zh-cn/azure/container-registry/

現在最新版本Service Fabric已經可以直接管理編排Docker了。

1.建立一個型別為Container的Service

image

2.在servicemanifest.xml中描述清楚image所在路徑

<CodePackage Name="Code" Version="1.0.0">

    <!-- Follow this link for more information about deploying Windows containers to Service Fabric: https://aka.ms/sfguestcontainers -->
    <EntryPoint>
  
      <ContainerHost>
        <ImageName>eshopsample.azurecr.io/catalog:latest</ImageName>       
      </ContainerHost>      
    </EntryPoint>
    <!-- Pass environment variables to your container: -->   
    <EnvironmentVariables>
      <EnvironmentVariable Name="HttpGatewayPort" Value=""/>
    </EnvironmentVariables>
  </CodePackage>

這裡非常簡單,指定了image所在位置就好了,如果本身Docker Image裡需要很多配置資訊譬如:資料庫連結串、其他服務的地址等等都可以在EnvironmentVariables裡面去配置。

3.配置Registry的訪問賬號密碼,需要在ApplicationManifest.xml上面來配置

<ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="CatalogService_Pkg"  ServiceManifestVersion="1.0.1" />      
    <Policies>
      <ContainerHostPolicies CodePackageRef="Code" Isolation="hyperv">
        <RepositoryCredentials AccountName="youraccount" Password="xxxxxxxxxxxxx" PasswordEncrypted="false"/>
        <PortBinding ContainerPort="80" EndpointRef="CatalogServieEndpoint"/>
      
      </ContainerHostPolicies>
    </Policies>
  </ServiceManifestImport>

整個過程不會太複雜,只要配置好了Catalog microserivce的ServiceManifest.xm和ApplicationManifest.xml檔案之後,我們可以用同樣的方法將其他服務一一配置完成,然後我們就可以將Service Fabric的配置Publish到Cluster上面了。

image

Service Fabric會自動根據配置在Cluster上面Pull Image和將Docker執行起來。非常簡單

用Service Fabric承載eShop on Container微服務的方法二:用Service Fabric的Runtime執行eShop on Container的微服務

Service Fabric本身就是個微服務的開發框架,現在已經直接支援了.net Core 2.0了所以,我們更新了Service Fabric的SDK之後就可以直接建立.net core的服務了

imageimage

eShop on Container的程式碼都已經是一份成型的.net core 2.0的程式碼,所以不需要重新編寫服務。

1.通過nuget新增最新的Service Fabric最新的SDK。

image

2.修改programe.cs,啟動ServiceFabric Runtime而不是直接啟動Asp.net WebHost

public static void Main(string[] args)
        {

            try
            {
                // ServiceManifest.XML 檔案定義一個或多個服務型別名稱。
                // 註冊服務會將服務型別名稱對映到 .NET 型別。
                // 在 Service Fabric 建立此服務型別的例項時,
                // 會在此主機程式中建立類的例項。

                ServiceRuntime.RegisterServiceAsync("Catalog.API",
                    context => new CatalogAPI(context)).GetAwaiter().GetResult();

                ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(CatalogAPI).Name);

                // 防止此主機程式終止,以使服務保持執行。 
                Thread.Sleep(Timeout.Infinite);
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
                throw;
            }
}
3.編寫

CatalogAPI 類用於啟動WebHost

internal sealed class CatalogAPI : StatelessService
    {
        public CatalogAPI(StatelessServiceContext context)
            : base(context)
        { }

        /// <summary>
        /// Optional override to create listeners (like tcp, http) for this service instance.
        /// </summary>
        /// <returns>The collection of listeners.</returns>
        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            return new ServiceInstanceListener[]
            {
                new ServiceInstanceListener(serviceContext =>
                    new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                    {
                        ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting WebListener on {url}");
                                                return new WebHostBuilder()
                                         .UseKestrel()
                                    .ConfigureServices(
                                        services => services
                                            .AddSingleton<StatelessServiceContext>(serviceContext))
                                    .UseContentRoot(Directory.GetCurrentDirectory())
                                    .ConfigureAppConfiguration((builderContext, config) =>
                                    {
                                        IHostingEnvironment env = builderContext.HostingEnvironment;

                                        config.AddJsonFile("settings.json", optional: false, reloadOnChange: true)
                                            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
                                       
                                    })
                                    .UseStartup<Startup>()
                                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                                    .UseUrls(url)
                                    .UseWebRoot("Pics")
                                    .Build();                  
                    }))
            };
        }
    }

4.編寫serviceManifest.xml描述服務埠等資訊

<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="Catalog.APIPkg"
                 Version="1.0.3"
                 xmlns="http://schemas.microsoft.com/2011/01/fabric"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ServiceTypes>
        <StatelessServiceType ServiceTypeName="Catalog.API" />
  </ServiceTypes>

  <!-- Code package is your service executable. -->
  <CodePackage Name="Code" Version="1.0.3">
    <EntryPoint>
      <ExeHost>
        <Program>Catalog.API.exe</Program>
        <WorkingFolder>CodePackage</WorkingFolder>
      </ExeHost>
    </EntryPoint>
    <EnvironmentVariables>
      <EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value="Development"/>
    </EnvironmentVariables>
  </CodePackage>


  <ConfigPackage Name="Config" Version="1.0.1" />

  <Resources>
   
    <Endpoints>   
  
      <Endpoint Protocol="http" Name="ServiceEndpoint"  Type="Input"  Port="5101" />
    </Endpoints>
  </Resources>
</ServiceManifest>


5.修改AppcationManifest.xml增加幾個服務的描述資訊

新增ServiceImport節

<ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="Catalog.APIPkg" ServiceManifestVersion="1.0.3" />
    <ConfigOverrides />
  </ServiceManifestImport>

在DefaultService中描述Service

<Service Name="Catalog.API" ServiceDnsName="catalog.fabric.api">
      <StatelessService ServiceTypeName="Catalog.API" InstanceCount="[Catalog.API_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>

這樣我們就可以將Catalog這個服務改造成可以通過Service Fabric來管理的微服務了。通過Publish,我們可看到幾個服務都已經在Service Fabric下面接受管理和編排了。

image

訪問localhost:5100

image


學習Azure Service Fabric的總結:

  • Azure Service Fabric其實分為兩塊:Azure和Service Fabric。
  • Service Fabric只是一套軟體分散式系統,理論上它可以使用在非Azure環境。也就是說:非Azure環境的機器叢集,進行合理配置,也可以使用Service Fabric 構建分散式系統。
  • 當我們在Azure門戶上建立Azure Service Fabric時,會自動建立Azure Load Balancer, Azure Virtual Machine Scale Set, Azure Virtual Machine。這是因為這些元件都是在Azure環境中將Service Fabric接入公網必須的元件和平臺。但是理論上如果今後有其他的產品,通過合理的負載均衡和配置邏輯,只要可以讓伺服器叢集面向外部網路提供服務,Service Fabric都可以適用。
  • Service Fabric自行構建了一整套虛擬概念,包括後面會提及的Micro Service, Node type, Node等等。這些概念都是僅在Service Fabric範圍內適用。例如Micro Service,可以用C#構建,也可以用Java實現。Node type可以是Azure VMSS, 也可是是硬體物理伺服器。
  • Service Fabric幫助架構師將分散式系統和硬體進行脫耦。理想程度下,所有職責如下:
    • 軟體開發者只需要關係分散式微服務功能邏輯實現,微服務之間如何呼叫通過統一介面完成
    • 應用部署者只需要關心如何將微服務部署至各個node,以及考慮應用的升級維護
    • 硬體架構師只需要關心維護虛擬機器和網路之間的部署關係,並且在虛擬機器效能產生問題是增加虛擬機器來分擔壓力

【參考資料】

1、大話微服務架構之微服務框架微軟ServiceFabric正式開源(三) http://baijiahao.baidu.com/s?id=1595179278058800506

2、Service Fabric https://azure.microsoft.com/zh-cn/documentation/learning-paths/service-fabric/

3、DevOps 工具整合 | Microsoft Azure https://azure.microsoft.com/zh-cn/products/devops-tool-integrations/

4、【圖文】微服務架構設計_https://wenku.baidu.com/view/eb6467d10408763231126edb6f1aff00bed570a3.html

5、微服務架構與實踐摘要-電子發燒友網觸屏版 http://m.elecfans.com/article/631884.html

6、微服務架構設計 - PetterLiu - 部落格園 https://www.cnblogs.com/wintersun/p/6219259.html

7、微服務實踐:從單體式架構遷移到微服務架構 https://blog.csdn.net/gaowenhui2008/article/details/70239716

8、微服務架構 - 老_張 - 部落格園 https://www.cnblogs.com/imyalost/p/6792724.html


相關文章