微服務
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 如何通過.netcore+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)上傳您的本地倉庫中的鏡像,但是由于國内已知的原因,還是推薦使用國内雲提供商提供的免費鏡像市場或者私有化部署自己的鏡像倉庫(推薦使用阿裡雲)
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
軟體安裝
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體系下的分布式監控與日志架構,可自行了解