一、微服務
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體系下的分散式監控與日誌框架,可自行瞭解