歡迎光臨
每天分享高質量文章

.NET Core 的微服務、容器、運維、自動化發佈

一、微服務

1.1、基本概念

 

 

1.1.1 什麼是微服務?

 

微服務架構是SOA思想某一種具體實現。是一種將單應用程式作為一套小型服務開發的方法,每種應用程式都在其自己的行程中運行,並採用輕量級的通訊機制(TCP)進行通信。

 

這些服務是圍繞業務功能構建的,可以通過全自動部署機制進行獨立部署。這些服務的集中化管理已經是最少的,它們可以用不同的編程語言編寫,並使用不同的資料儲存技術。

 

1.1.2 為什麼要用微服務?

 

1.1.2.1 微服務解決了什麼問題?

 

在微服務的最佳實踐中都提到如果一個專案以微服務作為起點,則大概率會陷入專案失敗。

 

微服務的本質是解決了團隊分工的問題,當專案團隊的開發人員無法解決大型單體應用的問題或雖然可以解決問題但成本高昂的時候,微服務往往才是最佳實踐。

 

通過從外圍不斷拆分單體架構的業務,以細粒度的單項服務的形式發佈服務,最終將單體架構微服務化。

 

1.1.2.2 微服務帶來了什麼挑戰?

 

微服務首先是對組織架構的調整提出的新的挑戰,微服務要求每一個服務盡可能的獨立和內聚,這要求這個團隊符合2pizza風格,也就是說每一個團隊都盡可能的包含從開發到測試到運維人員組成的獨立專案組。而不是傳統大型企業中以橫向切割的形式讓開發、運維、測試各是一個獨立部門。

 

微服務的第二個挑戰是帶來了分佈式下開發、測試與運維的複雜性。微服務本質上並不是什麼銀彈,它解決了團隊面對單體架構疲於奔命的開發和部署問題,但是也引來了新的問題。

 

在單體開發過程中,開發人員不會想到方法呼叫會失敗、會重試、要冪等。測試人員不會考慮幾十個應用怎麼一起集成測試,運維人員不會考慮下游應用掛了對我有什麼影響。意識到分佈式下開發、測試與運維的複雜性,並掌握這些複雜問題的方法才是更主要的。

 

1.2、架構設計

 

1.2.1 服務註冊/發現

 

服務治理解決了分佈式應用中服務依賴複雜度的問題,當數十個應用需要統一的管理進行服務發現、負載均衡、服務降級、服務下線時。

 

沒有一個統一的管理方式是無法實現的,服務治理的概念也應運而生。服務治理中最重要的部分就是服務的註冊和發現,以dubbo為例,服務提供者啟動後向註冊中心註冊自己提供的服務。

 

消費者(有可能是其他服務、也有可能是網關)啟動,向註冊中心訂閱自己需要的服務。

 

註冊中心傳回服務提供者的健康檢查(心跳)串列,消費者根據軟負載演算法(輪詢/隨機/hash一致/最小壓力優先)選擇一臺發起請求。

 

1.2.2 分佈式通訊

 

1.2.2.1 REST API/RPC

 

一般在微服務架構中,服務和服務之間由於行程隔離甚至物理機隔離,往往會採用一種通用的網絡通訊樣式,以目前主流的設計來說有兩種方案,一種是基於HTTP協議的rest api方式。

 

這種方式下每一個生產者以rest api的形式暴露自己的接口到註冊中心。消費者從註冊中心拉取到生產者串列後通過httpclient的形式發起請求並獲得結果。

 

Rpc協議也是基於網絡的請求協議,rpc通過TCP的形式(如dotnetty)採用遠程過程呼叫的方式,讓本地應用呼叫遠程應用就和呼叫本地過程一樣方便(new remoteprocessserver().get({id=1}))。

 

1.2.2.2 事件總線

 

微服務中由於服務和服務之間採用了物理級的資料隔離機制,而在單體架構中很容易實現的事務在微服務中成了複雜的分佈式問題,目前的解決辦法是引入事件總線(event bus)的機制來實現分佈式環境下的事務問題,事件總線採用了觀察者樣式,通過訂閱發佈到事件總線來實現訊息的最終一致性。

 

訂閱者訂閱訊息,發佈者產生訊息後發佈到事件總線,事件總線異步通知(基於第三方的訊息佇列,如rabbitmq)訂閱者,訂閱者處理訊息。訂閱者可以通過一些機制比如重試和冪等機制保證消費的訊息一定能夠被消費一次。

 

如果稍微複雜則需要引入TCC這樣的機制保證訊息消費失敗可以及時回滾(.netcore目前國內有開源的CAP可以實現eventbus並內置的tcc,無需開發者實現複雜的應用層tcc)

 

1.2.3 網關

 

微服務中,網關是所有服務對外提供的一個統一視窗。網關本質就是一個路由器,通過這個路由器,我們可以將外界(PC/APP/IOT/CLOUD)的請求進行統一的鑒權、限流、監控後對內呼叫服務,從而起到了保護內部服務接口安全的目的。

 

1.2.3.1  服務鑒權

 

用戶呼叫的某一個接口需要進行權限身份驗證時,可以通過網關集成identity進行統一的鑒權管理,而無需每一個應用自己去實現鑒權。也可以通過獨立的授權服務器來處理,網關將每一個需要鑒權的請求通過授權服務器做校驗,再由授權服務器授權後通知網關呼叫具體的服務

 

1.2.3.2 服務限流

 

網關可以通過對每個服務進行限流來保障在高併發中服務因為無法及時處理請求而掛掉,比如當某個服務的請求在單位時間內超過了設定閾值,則網關可以直接傳回給呼叫者一個友好的回呼或者通過快取的形式傳回之前的結果。

 

1.2.3.3 熔斷降級

 

網關可以通過熔斷的機制來保障某一個服務的可用性,比如當某個服務變得不可用的時候,比如當呼叫者多次請求某個服務都超時,當超時次數超過設定閾值的時候,網關可以對該型別的服務進行熔斷,所有對該服務的請求都會收到網關的友好回呼或舊快取。網關會在熔斷時啟動一個定時作業定時檢查該服務的可用性,直到該服務重新可以被訪問時才能重新接入網關。

 

1.2.4  配置中心

 

單體式應用中,一般採用傳統的配置檔案的形式進行本地化配置,方便統一管理或熱更新。但是在分佈式環境下如果沒有一個分佈式的配置中心作為支撐,動輒幾百個微服務應用是沒辦法及時進行統一配置的。

 

所以一個統一的分佈式配置中心是有必要存在的。通過統一的配置中心管理所有應用的配置,應用通過初始化拉取的形式做更新。應用內部依舊採用熱更新的形式讀取配置資料。

 

1.2.5 下一代微服務架構

 

1.2.5.1   Service Mesh

 

這一套解決方案提供了一套基於基礎設施的,對語言和應用本身無依賴的服務網格來提供上一代微服務中心化的網關/註冊中心/快取/負載均衡等等功能。比如基於k8s實現的istio。本質上是通過對容器註入sidercar的形式無感知的實現服務治理。而無需關註服務本身是用何種語言編寫的何種服務。Service fabric也是提供類似的功能的平臺。

 

1.2.5.2 Serverless

 

Serverless 是提供微服務的一種簡化開發、自動化運維、資源分時復用的解決方案,比如Flink(略)

 

1.3、具體實踐

 

1.3.1 如何通過.NET Core+surging+DDD實現微服務?

 

surging 是一個分佈式微服務框架,提供高性能RPC遠程服務呼叫,服務引擎支持http、TCP、WS協議,採用Zookeeper、Consul作為surging服務的註冊中心,集成了哈希,隨機,輪詢、壓力最小優先作為負載均衡的演算法,RPC集成採用的是netty框架,採用異步傳輸。專案地址https://github.com/dotnetcore/surging

 

在surging的基礎上我進行了一些本地化實現,比如授權服務分離。併為應用提供了一套ddd的基礎設施以及自動發佈以及運維監控部分的集成。

 

專案地址:https://gitee.com/gmmy/Microservices

二、容器(docker)

2.1、基本概念

 

2.1.1 什麼是容器?

 

容器基於Linux Container技術,它是一種內核輕量級的操作系統層虛擬化技術。最單純的理解就是通過容器技術,你可以很方便的將你的應用打包到某一個指定的環境(centos/ubuntu/alpine)構建特定的鏡像,這個鏡像可以通過世界上任意一臺安裝了docker的服務器進行拉取併成功運行,解決了以往應用在不同環境中表現不一致的問題。

 

2.1.2 容器和虛擬機的區別?

 

容器和虛擬機最大的區別在於容器本身是依賴於linux操作系統的的半獨立系統而虛擬機則是擁有獨立操作系統的沙箱。

 

容器又在此的基礎上提供了行程級的隔離和檔案資料隔離,基本做到了虛擬機的體驗而資源占用又比虛擬機少了很多。

 

2.1.3 鏡像/容器/自動化構建

 

2.1.3.1 容器

 

容器就是docker中的獨立最小化單元,是一個運行起來的鏡像。內部包含一個操作系統+環境+應用程式。

 

比如(centos+jvm+spring boot)/又或者(Ubuntu+python+flaskwebapp)。

 

雖然容器本身對應用並未有安裝限制,但實際開發時必鬚根據關註點分離的原則一個容器只運行1個應用。

 

2.1.3.2 鏡像

 

鏡像就是容器的原始檔案。當我們通過命令構造一個鏡像後,可以通過run很方便的把這個鏡像啟動成一個或一組容器(集群)。

 

有點類似於編程中的類定義檔案和運行時的類實體,一個類定義檔案在運行時可以創建1個或多個記憶體中運行的實體,由應用來管理它的生命周期。

 

我們也可以通過容器快照的方式將某個容器在某個時間點的快照匯出成鏡像。該鏡像會保留容器快照時的所有狀態。

 

2.1.3.3  自動化構建

 

容器可以通過docker build和docker compose的方式進行自動化構建。前者主要通過dockerfile的形式將本地的應用配合倉庫中的鏡像進行一組打包操作形成一個鏡像。

 

後者則可以直接通過呼叫多個dockerfile/命令的方式啟動一組鏡像(比如一個微服務專案含有多個應用。可以通過此方式一次性全部運行起來)

 

2.1.4 鏡像倉庫/市場

 

鏡像倉庫/市場就是存放鏡像的雲平臺,docker官方提供了(https://hub.docker.com)作為鏡像市場可以免費(2018.11)上傳您的本地倉庫中的鏡像,但是由於國內已知的原因,還是推薦使用國內雲提供商提供的免費(2018.11)鏡像市場(https://www.aliyun.com/product/acr?utm_content=se_1000088670)或者私有化部署自己的鏡像倉庫(https://www.cnblogs.com/Javame/p/7389093.html)。

 

2.1.5 容器編排

 

Docker本身提供了基於shell的方式對單個服務器的容器集合進行簡單的管理,但是在實際的生產過程中,我們依然需要更加強大的集中式管理工具來管理我們跨數個服務的容器集群,k8s就是基於這樣一個容器管理編排平臺,可以通過它很方便的管理容器的生命周期,從應用創建、部署、擴容、更新、調度均可以在一個平臺上完成,而無需創建複雜的腳本進行運維管理。

 

2.2、具體實踐

 

2.2.1 如何通過容器進行asp.netcore應用的發佈?

 

2.2.1.1 準備工作

 

2.2.1.1.1 環境

 

Linux/windows

 

Docker/docker for windows

 

Docker-compose(非必須,需單獨安裝)

 

Asp.net core app(我們假設應用已經發佈並打包好了)

 

2.2.1.2 發佈流程

 

打包鏡像一般我們推薦採用dockerfile的形式來完成。

 

首先在應用所在目錄創建一個沒有後綴的名稱叫Dockerfile的檔案,用vim或者txt打開並編輯它(取決於您採用什麼操作系統)

 

命令如下:

 

#我們需要從本地倉庫拉取一個基礎鏡像(dotnetcore runtime)

FROM microsoft/dotnet:2.1-runtime

#設置我們的工作目錄,後面的操作包括檔案複製,命令啟動如無必要均預設在該目錄執行

WORKDIR /app

#將當前dockerfile所在檔案夾所有檔案複製到鏡像對應的workdir目錄中

COPY . .

#設置容器的預設啟動命令

ENTRYPOINT [“dotnet”, “Web.dll”]

 

這樣一個簡單的dockerfile就創建好了。

 

接下來你可以通過docker build . –t ‘imagename’ 來構建鏡像並通過docker run 的形式來運行它,或採用docker-compose的方式來直接構建並運行它.

 

Docker-compose 方式

 

在剛纔的目錄中可以創建一個docker-compose.yml檔案進行容器編排(此處的編排僅僅指打包運行一組容器非k8s)

 

內容如下

 

version: ‘3.4’

services:

     #名稱,可隨意

  servicename:

#環境變數,根據應用實際需要指定傳入

   environment:

      – Register_Conn=192.168.0.171:80

#是否預設啟動

    restart: always

#指定鏡像名稱,通過build打包後的鏡像名稱

    image: servicename:latest

#指定打包,若沒有則會直接根據上一步的鏡像名稱構建容器

    build:

#打包路徑

      context: .

      dockerfile: Dockerfile

#構建的容器名稱

    container_name: servicename

#對外映射端口,左側是服務器對外開放的端口,右側是容器內開放的端口,假設我的asp.netcore指定了80端口映射到服務器提供的8080端口

    ports:

      – “8080:80”

 

通過簡單的執行 docker-compose up –d –-build 就可以很方便的將應用運行起來了。

三、自動發佈

3.1、基本概念

 

3.1.1 什麼是CI/CD&CD;?

 

CI/CD&CD;字面意思就是指持續集成,持續部署,持續交付。指出在軟體研發過程中需要通過自動化構建的方式將產品能夠快速的高質量的進行交付和迭代,區別於以往小作坊式的手工方式打包部署,避免了人為原因造成的軟體部署失敗以及提升了部署效率。

 

3.2、具體實踐

 

3.2.1 Gitlab+gitlabCI+gitlabRunner

 

軟體安裝

 

Gitlab:https://www.cnblogs.com/wenwei-blog/p/5861450.html

 

gitlab-runner: https://blog.csdn.net/weiguang1017/article/details/77720778

 

ci&cd;具體落地依賴於版本管控軟體以及自動化構建工具以及容器技術,我這裡採用的例子是gitlab自帶的gitlabci工具。

 

其發佈流程如下:push代碼到gitlab->gitlab根據根目錄的.gitlab-ci.yml檔案發佈ci命令,若當前專案部署了對應的gitlabci,則ci工具會啟動對應的gitlabrunner這個行程開始執行對應的命令並推送構建好的鏡像到遠程服務器,大致的流程如下圖:

 

 

3.2.2 單元測試(xtest)與質量管控(SonarQube)

 

單元測試對於軟體開發來說是必要的,所以需要接入單元測試。.netcore推薦xunit作為單元測試工具。https://www.cnblogs.com/ccccc05/archive/2017/08/01/7266914.html

 

代碼質量管控也是一個必要的過程,通過對上傳代碼的分析,可以找出一些人為忽略掉的質量問題,方便後續版本的改進。

http://www.cnblogs.com/qiumingcheng/p/7253917.html

四、運維監控

4.1、基本概念

 

4.1.1 APM

 

Apm致力於監控管理應用軟體性能和可用性,單體應用時代APM的需求並非特別強烈。但是基於微服務的分佈式架構下,多個服務的性能穩定可用必須統一檢測和管控起來。

 

4.1.2 日誌與異常

 

以往的單體應用往往採用日誌檔案或者資料庫記錄的方式來管理日誌和異常(比如知名的log4j),和其他單體應用轉分佈式一樣的問題就是每一個應用的異常資料和日誌都需要統一的進行管理

 

4.2、具體實踐

 

4.2.1 Skywalking+ Elasticsearch + Exceptionless

 

預設已經集成到我的微服務體系里了,可直接運行docker版本

 

4.2.2  Elasticsearch+ Logstash + Kibana

 

JAVA體系下的分佈式監控與日誌框架,可自行瞭解

赞(0)

分享創造快樂