之前寫過兩篇關於微服務架構的文章,發現閱讀量挺高的,所以打算再聊聊雲原生和微服務架構,過去的文章如下:
擴充套件閱讀:
本篇分享主要圍繞以下 4 個主題進行:
- 什麼是雲原生 ?
- 為什麼要用雲原生架構 ?
- 微服務的概念
- 微服務的技術選型
什麼是雲原生 ?
雲端計算和雲原生
雲端計算不同於傳統的自建機房,雲端計算就是將計算的抽象為基礎設施然後通過網路分發,得益於雲端計算的無限擴充套件能力,使得“雲端計算”就像自來水廠一樣,我們可以隨時接水,並且不限量,按照自己家的用水量,付費給自來水廠就可以。以下雲端計算的五個基本特徵。
以下是一些目前比較主流的公有云廠商:
雲原生顧名思義,就是基於雲端計算特性所設計的應用服務,得益於雲端計算快速發展,基於雲端計算特性所設計的雲原生應用相比傳統的單體應用在安全性,擴充套件性,快速迭代,運維等各方便都有巨大的領先優勢。雲原生並不是指某一種技術,它是一種架構設計理念,只要符合這種架構設計理念的應用,都可以稱為 雲原生應用, 看看 CNCF 官方對於雲原生的定義:
容器雲技術的發展
雲原生是依賴容器作為技術技術來實現的,但是容器並不是什麼新潮技術,以下是容器雲技術的發展歷史,其中有幾個關鍵的歷史節點
- 早在 06 年的時候 Amazon 基於容器技術構建的 IaaS 平臺 AWS,成為所有云計算廠商的鼻祖,由於技術領先的優勢 AWS 現在依然也是雲端計算行業老大
- 13 年 Docker 的誕生進一步簡化容器技術的使用門檻,Docker 公司自以為掌握雲時代的核心技術,開始野心勃勃的有意挑戰傳統的雲端計算大廠例如 RedHat,Google 的江湖地位,公司股價也是一騎絕塵,卻不料被 RedHat 聯合 Google 釋出的 Kubernetes 擊潰,Kubernetes 的成功讓大家以為容器技術並非雲時代的核心技術,容器編排 才是核心技術。(備註:2020 年 K8S 官方宣佈只要滿足 K8S CRI 介面的容器均可以被 K8S 進行編排,Docker 被時代拋棄)
- 2015 年藉助 Kubernetes 的成功,Google 宣佈成立 CNCF 基金會,這是雲原生時代的代表性的組織。致力於完善雲時代的基礎設施,幫助開發者構建更出色的產品
下圖是 CNCF 的全景圖:
為什麼用雲原生架構 ?
主要從 4 個方面來聊聊:
- 自動恢復
- 服務安全
- 彈性擴充套件
- 快速釋出
自動恢復
早期剛參加工作的時候接手過一個年久失修的遺留系統,這個系統又一個很神奇的 Bug 每天晚上會自動當機,誰也不知道什麼原因。只要重啟就能恢復正常,當時為了保證業務系統的正常使用,我總是在半夜爬起來重啟伺服器,我當時就在想:要是有一種工具可以檢測到系統當機後,就自動重啟恢復就好了,這樣我就可以睡一個好覺了。
這就是雲原生架構想要解決的第一個問題:應用系統掛掉後,無需人工的介入,可以自動在最短的時間恢復來保證系統的健壯性。
當然除了未知的 BUG,還有詭異的異常會導致服務崩潰了,例如:
- 程式碼沒寫好,系統發生 OOM
- 伺服器本身的資源不足
- 死鎖,磁碟,網路等問題
- 等等……
Kubernetes Pod 應用自動恢復的三種策略:
spec:
restartPolicy: Always # 當容器終止退出後,總是重啟容器,預設策略
containers:
- image: nginx
name: web
Always
:當容器終止退出後,總是重啟容器,預設策略OnFailure
:當容器異常退出(退出狀態碼非 0)時,才重啟容器Never
:當容器終止退出,從不重啟容器
安全性
在微服務架構的大型分散式系統,服務和服務之間是通過熔斷建立安全的保護隔離機制。
雲原生架構保障系統的安全性主要體現 2 個方面:
- 服務隔離
- 資源隔離
服務隔離
先來看看服務呼叫的安全隔離,如圖:
假如服務 A 和服務 B 之間存在依賴的呼叫關係,它的處理邏輯如下:
- 如果服務 B 當機或者異常下線,註冊中心會傳送服務 B 的狀態給服務 A,服務 A 就會啟動熔斷保護機制
- 服務 A 採用降級策略或者不再傳送向服務 B 傳送請求,避免產生呼叫鏈雪崩,同時也保護服務 A 的可用性
- 服務 B 再次被拉起的時候,服務 A 收到註冊中心對服務 B 的健康檢查,恢復對服務 B 的呼叫或者移除降級策略
資源隔離
雲原生架構對於服務的保護機制也體現在對資源的使用上,以前多套系統共享一臺主機的資源,總是容易出現木桶的短板效應,就是隻要有一個系統把主機資源佔滿,那麼其他的系統都會因為資源不足受到影響。進而產生連鎖反應,同主機上的所有系統都會崩潰。
現在基於容器部署的微服務系統,你的系統在生產環境的真實部署情況就像被關進一個個小房間裡面,預先安排的資源設定就是這個服務房間的大小,它只能在指定的大小範圍內活動,就算程式內部異常導致把資源全部佔用,也不會影響其他房間的小夥伴的正常活動,從而保證整個系統的可用性
通過 Kubernetes 指定記憶體請求和限制的 Pod 配置檔案:
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi" # 記憶體會被限制在 200 MiB 以內
requests:
memory: "100Mi" # 容器將會請求 100 MiB 記憶體
通過服務隔離,資源隔離的方式為雲原生系統提供安全和可用性,這裡僅僅做一個入門的介紹,如果展開來講的話,內容還有很多,有興趣的同學可以自行去研究和探索。
彈性擴充套件
傳統的單體的應用,往往部署在機房的伺服器主機內,那麼自購的伺服器難以應對業務快速增長,存在以下問題:
- 時間成本:採購伺服器需要事先填好配置清單,走各種流程,等物流,等機器送到接上電源,估計 1~2 周都過去了
- 空間成本:要騰出很大的空間來放置這些大傢伙
- 其他成本:24 小時開空調,專人輪班值守,機器的維護,服務下線後伺服器容易閒置,閒魚不好出手等等。。
在基於雲端計算的基本特徵所設計的雲原生系統,則不存在以上這些問題,在主流的公有云廠商提供 ECS 主機基本可以任意擴充套件和伸縮配置,在資源使用上也提供 按量付費 的執行模式,有效避免對於計算資源的限制和浪費。如下:
快速釋出
隨著類似 Kubernetes 等雲原生基礎設定的完善,現代應用的部署方式也跟以前大不相同。相比傳統低效的停機發布,雲原生服務提供的 Rolling Update 滾動升級幫我們實現不停機升級系統的目標,對於需要快速響應市場需求的企業,快速迭代的業務系統的功能對於企業取得市場競爭力顯得來說尤為重要。
KubernetesRollingUpdate 策略用於解決不停機發布的問題:
另外,我們可以通過kubectl rollout undo
將 deployment 回滾到指定的版本,來解決微服務的快速回滾的問題。
以上就是雲原生架構相比傳統系統所帶來的巨大優勢,我們目前也是處於雲時代架構演進的早期。我個人認為,我們程式設計師作為知識工作者非常值得投入時間去學習下一代的主流架構設計。這將為我們帶來巨大的技術優勢和技術領先。
微服務的概念
微服務的理論基礎
微服務並不特指某一種具體的技術,它是一個抽象的概念,只要滿足它的所有規範,那麼就可以理解為你的系統實現了微服務。
何時用微服務 ?
關於你的專案何時應該引入微服務架構,行業一直有兩種聲音:
- 方案 A 單體優先:隨著架構的演進逐漸替換為微服務架構
- 方案 B 微服務優先:避免後期的大範圍架構重構
其實,早在 2015 年技術大牛 Martin Fowler 在部落格文章 MicroservicePremium 中就給出了具備參考性答案:
早期(2015 年左右)微服務使用成本和上手門檻很高,生產效率不如單體應用,但是伴隨系統的業務複雜度逐漸上升,單體應用的生產效率逐漸降低,在到達臨界點的時候微服務的優勢逐漸出現,微服務的生產效率開始超過單體應用。
所以在 2015 年的時候結合成本和收益的權衡,大多數人會選擇 單體優先 的架構方案,後續再逐步演化成為微服務。
Netflix OSS 的誕生
早在 2015 年的 CNCF 基金會剛誕生,社群的微服務基礎設定非常不完善,Netflix + Pivotal 公司作為微服務的實踐的探索者,通過應用層面提供許多微服務的基礎元件來實現微服務架構。關於 Netflix 提供的微服務全家桶解決方案稱作 Netflix OSS(Open Source Software Center)
關於元件的詳細介紹,我在 一文了解基於 Netflix OSS 的微服務架構 中也有介紹,這裡就不再贅述了。
Netflix OSS 全景圖如下:
微服務優先
Martin Fowler 在 2015 年提出的觀點,顯然已經不再適用 2021 的現代系統架構,這幾年隨著 CNCF 的快速發展,雲原生的基礎設施逐漸的完善和成熟,微服務的使用成本逐年降低,微服務的實現成本已經趨向於單體,甚至未來會優於單體,我的個人看法是,微服務如果能夠解決使用和學習成本的問題,那麼未來微服務也將完全取代單體應用。從長期主義來說,任何新專案都應該優先選擇微服務架構,不僅可以保證業務系統的生產效率、擴充套件性,還可以避免未來產生大規模的重構。
微服務的技術選型
微服務框架選擇
市面上微服務框架很多,目前行業的大公司基本都會有自己的微服務框架,我們只看幾款主流並且具備代表性微服務框架:
- Dubbo (阿里巴巴)
- Spring Cloud (Netflix)
- Kubernetes (Google)
我們通過功能對比,看看都是如何根據自己的理解實現微服務的基本理論概念
我們將主流框架從微服務的基礎關注點,運維架構,產品背景進行三方面維度的比較:
通過橫向對比,我們可以看到不論是 Dubbo 還是 Spring Cloud 對比 Kubernetes 都有諸多缺點。相比阿里巴巴的 Dubbo、Netflix 的 Spring Cloud, Google 提供的 Kubernetes 才是具備完整的一站式的微服務解決方案的技術方案。如圖:
如果使用住房來比喻的話,前者就像毛坯房,還要自己裝修,Kubernetes 則是精裝修的商品房,幫你解決所有問題,拎包入駐即可。另外,自建 Kubernetes 叢集成本比較高,推薦使用公有云廠商提供的 Kubernetes 服務。
微服務和閘道器
如果把分散式的微服務系統比喻成一家公司的話,那麼閘道器就是該公司的前臺,當有使用者要訪問公司必須在前臺登記確認身份,疫情期間可能還需要量一下體溫什麼的。這一步驟就叫 閘道器鑑權,根據使用者描述的任務和身上攜帶的證明,閘道器使用者的業務型別將使用者帶到所屬業務範圍內辦公室,這一步驟就叫做 閘道器路由。如果使用者太多一個前臺處理不過來,就會多開設幾個視窗來分流,這一步驟就叫做 閘道器層面的負載均衡。閘道器是微服務的大門,對於微服務至關重要。
以下是閘道器常見的工作方式:
除了上述的鑑權,動態路由,負載均衡,通過閘道器還可以實現以下高階特性:
- 閘道器限流(人太多,把門關起來,或者在門口排隊)
- 金絲雀釋出(將小部分使用者帶到還未開放的新辦公場地去體驗一下)
- 彈性伸縮
閘道器是微服務的大門,因為閘道器對於對微服務來說至關重要,是微服務彈性伸縮的能力來源。並且閘道器的開發成本其實並不高,所以市場面有很多單獨的閘道器產品,我們可以簡單看看,如圖:
微服務和安全認證
早期分散式單體應用的會話管理
早期的單體應用使用者會話方案都是通過服務端儲存 sessionid + cookid + filter 來儲存和管理使用者狀態會話,但是這種有狀態服務有很多弊端,例如服務重啟使用者狀態丟失,難以橫向擴充套件等等,後單體應用時代大家開始把使用者會話狀態放在類似 Redis 等儲存中介軟體中,來解決系統的橫向擴充套件和重啟後會話不丟失的問題。
架構如圖:
微服務中基於 Auth 的認證方案
在的微服務體系中,身份認證模組將被統一抽取出來交給單獨的服務處理,該服務通常稱為 Auth Service。訪問令牌通常由 Auth 頒發,由閘道器統一鑑權,AuthService 身份認證職責的分離,可以讓微服務本身更加關注業務。
基於 Auth Service 的工作邏輯如圖:
不過這種基於 Auth 認證服務的方案會將所有請求發往 Auth 進行驗證,認證服務承受的壓力大,架構方案重,造成不必要的效能損失。其實大部分的應用系統都不需要這麼嚴格的安全認證等級。那麼有沒有一種輕量級的技術是可以由認證服務頒發令牌後,不在需要依賴 Auth 鑑權,由服務自行驗證令牌的有效性,這樣就可以大大減少對 Auth 的鑑權請求。答案是有的。它就是目前非常流行的 JWT 鑑權方案。
JWT 結合 RBAC 角色許可權模型是目前非常主流的輕量級認證方案。它的工作流程如下:
JWT 備受推崇,廣泛使用的原因,是因為它在由 Auth 服務頒發令牌後,在閘道器即可驗證令牌合法性,無需再請求認證服務,請求少,效能好。令牌本身還可以自包含少量的使用者資訊,JWT 大概是一串這樣的編碼,它由三個部分組成,你可以通過 JWT IO 這個網站對 JWT 進行解碼,從而獲取 JWT 中的資訊:
JWT 的詳細生成和解碼過程就這裡不在贅述了,JWT 並非沒有缺點,我們看看它的優缺點:
優點 | 缺點 |
---|---|
緊湊輕量 | 一旦頒發無法吊銷,只能自動過期 |
減輕 Auth 壓力,簡化 Auth 實現 | 包含資訊越多,傳輸開銷越大 |
總結
RBAC 角色模型 + JWT 鑑權方案是目前微服務主流的安全認證體系,也能應對大多數系統對於安全認證的需求,也是目前市面上大部分的企業應用生產中的最佳實踐
微服務的運維監控
生產就緒系統 Production Ready
說完了開發環節,最後來說說微服務是怎麼運維的。我們知道僅僅只是 完成功能(Feature-Complete) 只是軟體開發流程中很少的一部分,那麼從完成編碼到 生產就緒(Production Ready),還需要經歷哪些環節 ?我們可以參考下圖:
-
整合測試:使用者功能的準確性,效能和壓力測試
-
日誌管理:日誌要規範,要區分:Info,Wrong,Error 等不同的等級,日誌格式統一,方便日誌收集,監控和排查
-
監控預警:包含業務指標監控,應用指標監控,CPU,記憶體,磁碟網路 IO 監控等等,設定合理的預警資訊
-
呼叫鏈監控:呈現分散式系統的呼叫關係,呼叫效能,找到效能瓶頸,快速定位問題
-
高可用考量:雙機備份,主從備份,異地多活,容災策略,應用彈性機制等
當我們確保應用滿足生產就緒(Production Ready)的要求,我們就可以釋出到生產,交付價值了
基於 EFK 的日誌採集方案
基於容器部署的微服務架構不可能像傳統應用那樣通過 SSH 登入伺服器上扒日誌資訊,所以只能採取統一的收集機制。
Kubernetes 中推薦使用 EFK (Elasticsearch + Fluentd + Kibana)採集日誌,它的工作流程如圖:
- Fluentd 會將採集的日誌直接發到 ElasticSearch,中間也可以增加 kafka 作為快取層
- ElasticSearch 通過 Log Parser 初步解析日誌,可以過濾垃圾日誌
- 通過 Kibana Dashboard 查詢 ElasticSearch 顯示日誌
分散式系統的服務監控方案
目前主流的微服務監控體系是通過 Kubernetes + Prometheus 來搭建,如圖:
- 通過 Prometheus 發現 Kubernetes 服務
- 通過 Alert Manager 監控和報警 Email,SMS
- 通過 Grafana 展現和監控服務的執行各項指標
基於 Skywalking 分散式鏈路跟蹤監控
Skywalking 是無侵入分散式鏈路跟蹤框架,可以在不新增一行程式碼的前提下完成對微服務分散式系統的鏈路跟蹤,是目前主流的分散式鏈路跟蹤的解決方案,2019 年 SkyWalking 成為 Apache 頂級專案,SkyWalking 的作者吳晟也因此當選為 Apache 軟體基金會首位華人董事,這裡就不展開講了,SkyWalking 工作大致工作原理如下:
SkyWalking 對分散式呼叫鏈的展示:
總結
本文從雲原生的發展歷史,講述了我們程式設計師為什麼要擁抱選擇雲原生。講解了基於雲端計算的基礎底座所衍生出來的雲原生系統對傳統單體應用所帶來的顛覆性改變,然後講述一些微服務的工作原理,架構佈局和運維方案。但是在真正生產級雲原生應用中,遠遠不止要要考慮以上的內容,還有更多需要考慮的因素,例如:
- HTTPS
- 編碼規範,測試覆蓋率,E2E 測試
- 監控:Log/Trace/Metrics,業務指標監控
- 持續整合:CI/CD 流水線
- 完善的 README 幫助文件
更多細節就不展開講了,期待跟大家共同學習和交流,謝謝大家。
參考文獻: