前言 微服務的「大小」重要嗎? EXPAND
「微服務」這個術語,無可厚非地會將我們的關注點錯誤地聚焦在「微」上。 但大小從來不是一個重要的考量因素
微服務架構的目標是要將應用程式通過一些小的、 鬆散耦合 的服務組織在一起,藉此 提高開發效率 ,特別在:
可維護性 (maintainability)
可測試性 (testability)
可部署性 (deployability)
可擴展性 (scalability)
我們「需要」微服務架構嗎? EXPAND
重點其實不是我們「需不需要」,而是 我們已經在用了!
以 NIS 主體,周邊有許多衛星服務,難道不是為了實現鬆散耦合、可獨立維護、獨立部署等目的而開發的嗎?
Jubo Space 與北美專案,看似可以與 NIS 無關,但我們總會考慮到任何可能再利用我們 NIS 所累積的資料或與 NIS 本體做交互的可能性。這難道不也是考慮上述四點而進行發展的嗎?
又考慮到我們採用 SaaS 為主要商業模型,且積極採用 Cloud Native 的方法論在構築我們的商業產品
故本質上,我們已經跟微服務緊密耦合了
且我們的確有一些問題可以透過微服務架構來解決:
NIS 單體架構搜集到的 logs/metrics 雜訊過多無法聚焦問題,阻礙排錯作業
各模組、應用情境不同,但單體應用的可擴展手段有限
難以理解與維護,隱性地降低開發速度
不易寫測試,阻礙鍛鍊更廣泛技術能力的機會
為何要談微服務架構? EXPAND
需要了解在討論「微服務架構」時,真正 需要考慮的各方面 ,以及 哪些技術方案應可積極採用 ,也 確立更多的溝通術語 在我們的架構討論上
了解更多之後,我們 才能知道還有哪些落差 ,在實現商業目標的同時才能更佳地 瞻前顧後
微服務架構下最契合的「組織溝通模型」? EXPAND
坊間討論這件事時,都提到最契合的組織架構是: 每一個微服務 都明確 有一個團隊 負責
但我們 only one engineering team ,還能把微服務架構玩好嗎?
我個人覺得:邊做邊調整
或當成,提前打造好適合組織人力擴充時的架構
我們還是試著提出一個漸進式策略:拉出「微服務強固 (reinforcing) 工作小組」開始展開一些前期工作及試著拆分 NIS 單體應用
個人想像的中後期發展:
全端小夥伴接到商業需求,需要去迭代微服務時,由工作小組的人確實 review
工作小組的人員在人力資源調度面允許固定下來,那就真的穩定接收後端需求、負責迭代所有微服務囉
如何「使用」微服務架構? EXPAND
採納微服務架構,需要我們備妥所有 可觀測性基礎建設 ,及梳理出 標準排錯步驟 ,發揮此架構真正的價值
也需要我們在新建的(後端)服務滿足可觀測性的要求,及撰寫足夠的自動化測試例,以對齊用微服務來重構單體應用的目標
單體架構 vs. 微服務架構
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Applications/Microservices 的抽象架構
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: Microservices in Action
(左) 單體應用中常見的 3-tier 架構
(右) 微服務架構中,每一個微服務基本上也是此架構
微服務應用的「四層架構」
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: Microservices in Action
微服務應用則會進一步用此模型來討論整體的概念:
客戶層 (Client) : 與整個微服務應用後端互動的用戶端應用。Web applicationa, mobile apps … etc.
邊界層 (Boundary) : 暴露給用戶端進行互動的服務。通常在這層做一些滿足用戶端需求的聚合操作
服務層 (Services) : 我們大部分時間都在開發這一層的服務。這層的服務區通常又可明確地區分成
業務服務 (business service): 職責是 直接實現業務目標
技術服務 (technical service): 職責是 實現服務間共享的技術功能
平台層 (Platform) : 支援微服務快速開發、運行、通訊、部署的元件、基礎建設
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
其中比較陌生的應該是: 平台層 負責了什麼?
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: Microservices in Action
圍繞在 Service 周圍的 Observability, Deployment pipeline, Communication, Service discovery … etc.,都可被歸類在平台層的範疇
而這些平台層的基礎建設,都已有完善的解決方案。直接對照我們目前採用的 tech stacks:
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
啊~ 所以其實「四層架構」,比較像是下圖:
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
溝通模式 (Communication Patterns) 同步訊息傳輸 (Synchronous Messages)
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: Microservices in Action
是最熟悉、最容易理解與測試的溝通模式
內部服務的溝通流行使用 gRPC (with protobuf contracts),視情況繼續使用 RESTful HTTP (with JSON contracts)
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
缺點
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Does gRPC faster than RESTful HTTP?
其實 gRPC 很多效能上的優勢是利基於 HTTP/2 的結果。所以許多文章比較的 gRPC 與 RESTful HTTP,反而是在比較 HTTP/1.1 與 HTTP/2,不太公平。
故若我們不探討執行效率的問題,採用 gRPC 還能帶來什麼益處?
我覺得是「開發體驗」的提升,尤其當業務持續發展,內部越來越多服務的時候,能夠保持較良好的開發與團隊內的溝通效率。
我認為關鍵有二:
利用 protobuf 定義 contracts 後,就是一種 code as a document,不用額外維護 API 文件
透過自動生成的 client stubs ,作為 package 被你的程式引用。你的程式碼就變成一堆 function call 去調用 remote server,IDE 也能利用 IntelliSense 這類功能幫你自動補全、參數提示、member lists、method lists 等
References:
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
用戶端 (Clients) 與邊界層 (Boundary) 之間也有機會使用 gRPC 嗎?
Of course!有興趣的人可先了解一下,一起逃離文件維護地獄:
非同步訊息傳輸 (Asynchronous Messages)
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: Microservices in Action
有一個 事件代理人 (event broker) ,儲存 producers 產生的「事件」;有興趣的 consumers,向代理人訂閱、取得那些事件
最適合用在微服務溝通的模式,使得服務之間交換訊息更有彈性
發布訊息的上游服務不需要擁有下游服務的知識,徹底將服務解耦,避免服務越來越多陷入相互依賴地獄
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
在 Communication in a microservice architecture - docs.microsoft.com 甚至提到:
If possible, never depend on synchronous communication (request/response) between multiple microservices, not even for queries.
且說 sync mode 是 anti-pattern 呢
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
而在非同步傳輸中,還有 兩種最常見的基本模式 需要明確做出區別,分別是: Job queue 與 Publish-subscribe
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Job queue
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: Microservices in Action
多個 workers 消化同一個 job queue;i.e. 一個 job 只被一個 worker 處理到 (沒有重工)
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Publish-subscribe
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: Microservices in Action
一個事件可以發送給任意個監聽者;每個監聽者都能拿到發布的事件並自己做處理
測試策略 (Testing Strategies)
source: https://martinfowler.com/articles/microservice-testing/#conclusion-test-pyramid
很直覺地,在此架構上若要對整體系統做到完善的測試,是比單體架構更有挑戰的
以下以微服務架構的角度,再回顧各種測試的守備範圍 (及實務上的可執行策略),最後也簡介一下 Load Testing
單元測試 (Unit Testing)
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
何謂「一個 unit」?
其實它就像 單一職責原則 一樣,是一個無法量化並明確界定範圍的概念,範疇取決於你要服務的對象。那麼就表示它可以小到是一個 pure function 、或是一個 express / Gin 的 request handling function 的實作。
不執行 Network Communication
被歸類在 unit testing 的 test cases 中, 不真的執行 network communication
e.g. external services、3-rd party services、databases
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
那些對外部服務的依賴,在你的實作上可採用 依賴反轉原則 來實作,就能夠在 test cases 中利用 依賴注入 (Dependency injection) 的方式,用 mock objects 取代,以滿足測試情境的需求。
測試內部重要邏輯
測試那些重要的商業邏輯或共用元件
人生苦短,關注在那些你覺得容易犯錯,或是複雜的部分就好
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Kent Beck : “I get paid for code that works, not for tests”
TDD 之父 Kent Beck 於 stackoverflow 上一篇詢問「unit testing 該做得多深入」的問題答到:他傾向不花時間去測試那些不容易犯錯的部分。而是花時間去測試自己與他人容易犯錯的部分、擁有複雜的邏輯的部分。
在本地開發環境及 CI 環境中執行
此種測試在本地開發應會非常頻繁地被執行
提 MR 的 旁支 應在 CI 環境中通過測試後才可要求 review;若旁支測試失敗,不應讓它併入主分支
若 CI 環境中的測試失敗,理應中斷 pipeline,避免進入 CD 環節
整合測試 (Integration Testing)
source: https://martinfowler.com/articles/microservice-testing/#testing-integration-diagram
真的執行 Network Communication
目標是驗證真的進行 network communication 時,service 內的 success and error paths 如期運作
記住,仍專注在驗證 service 內部與外部接觸的元件邏輯,而不是驗收外部的服務的正確性
在本地開發環境及 CI 環境中執行
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
有資料庫依賴怎麼辦?
在 CI 環境中用 docker 運行資料庫的 contianer
CI 環境的 DB URL 指向該 container 進行測試
test cases 中免不了得自己撰寫創建假資料、初始化資料庫內容的步驟
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
有其他微服務依賴怎麼辦?
protobuf 會同時生成 server/client stubs
故在 test cases 中可以用 server stubs 真的運行一個 mocking server 來滿足測試
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
有其他第三方服務依賴怎麼辦?
視情況 (工時+效益一起評估),原則上若可以實作一個 mocking server 則優先考慮
若成本太大,再考慮僅用 interface 製作 mock objects 做 unit testing
元件測試 (Component Testing)
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
A component test limits the scope of the exercised software to a portion of the system under test, manipulating the system through internal code interfaces and using test doubles to isolate the code under test from other components.
source: https://martinfowler.com/articles/microservice-testing/#testing-component-introduction
測試服務的 Public API
對微服務架構來說,components 指的就是 microservices 本身
故利用服務的 contract of the API 進行測試即可
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
以下面的 gRPC contract 為例,元件測試就會測試 rpc SayHello
的行為是否如其運作:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1 ;
}
message HelloReply {
string message = 1;
}
真的執行 Network Communication
與整合測試一樣,對於外部服務的 會使用 stubs/mocks 等方式取代
對於資料庫的依賴,可考慮實作 in-memory 的版本;但其實我們都在容器化的環境中測試,可直接運行一個拋棄式的資料庫實體即可
在本地開發環境及 CI 環境中執行 端到端測試 (End-to-end Testing)
此種測試 將整體微服務系統視為黑盒子 ,也就是說測試的進入點是在 邊界層 ,或是直接透過 GUI 介面操作來進行測試
當觀點是整體系統時,就會發現涉及到許多 moving parts,故撰寫並維護此類的測試將相當困難。又 若系統有非同步行為 ,可能無法期待測試結果具有「確定性 (deterministic)」
個人相信的觀點:這類的測試由 測試工程師 來進行會較合適。他們比 develoeprs 更關心真實使用者的利益,且能避免球員兼裁判的盲點,更有機會測出有價值的部分
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
有其他替代方案嗎?
其中一種方案:採用 Canary Deployment 的技巧,將特定 users 或一定比例的流量導進新版服務,並透過 可觀測性 (observability) 元件 的輔助了解系統的狀況。
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: https://harness.io/blog/blue-green-canary-deployment-strategies/
負載測試 (Load Testing)
source: https://grafana.com/docs/k6/latest/testing-guides/test-types/
Smoke Test :目的是利用最小的負載驗證 test script 是否正確
Load Test :會去了解 併發用戶數 與 RPS 對系統效能的影響
Stress Test/Spike Test :給予 極限條件 下,評估系統的穩定性
Soak Test :了解系統沈浸在 長時間負載 時的可靠性和效能
以上的測試種類,皆可用同一個 test script,再搭配不同的 test configration 來變換測試種類以達到不同的目標
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
也不是所有的 testing types 都適合做自動化,再看看 k6 如何建議 Automated performance testing
個人實務心得
時間有限的情況下,都直接做 component testing,直接有效
覺得有需要做 integration testing 的地方,優先考慮是不是直接做 component testing 來涵蓋
需求變動太多,不敢寫太多 unit testing 給自己套上枷鎖。只在重要商業邏輯假設上撰寫
可觀測性 (Observability)
在微服務架構下,需要思考如何讓開發者對各個 服務間的交互行為 及 基礎建設的運行狀況 有更高的掌握度,也就是提升所謂的 可觀測性
提升可觀測性有兩大目標:
出現不符預期的情況時能儘早發現、介入並處理;
若無法搶先一步,至少要有能力快速指出需要關注的區域
可觀測性技術堆疊 提供了搜集、儲存、展示與分析資料的方法。平時會就可能搜集越多的度量指標與資訊,以備不時之需
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Prometheus, Loki, Jaeger, Istio, Grafana 及 Profiler 是我們目前使用的可觀測性技術堆疊 (observability tech stack)
Macro-level: 3 Pillars of Observability
source: Elastic 的 Observability 解決方案 - ithelp article
有三種資訊,需要服務 主動 提供 (via instrumenting),以構築所謂的可觀測性:
Logs
Metrics
Traces
這三樣元素都會有各自的 GUI 面板展示它,並讓我們利用它們來分析服務的狀況
source: Microservices in Action
Logs
簡單來說就是程式輸出的 logs,程式運行時紀錄重要處理步驟,以利未來排錯及分析
通常使用 結構化的方式輸出成 JSON format ,讓後面的日誌分析系統做索引、整合
同時妥善利用 logging package 提供的 分級 (levels) ,至少將 logs 分成 Debug , Info , Warn , Error 等層次,以利建立度量指標及警訊規則
source: our Grafana Explore
Metrics
利用時間序列資料格式儲存系統運作及服務的資訊。 e.g.
CPU, Memory, Disk 使用量
HTTP requests 相關資訊
各服務業務領域內的需求
大多數警訊規則也是根據這些度量指標來設定閾值
source: our Grafana Dashboard
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
The Four Golden Signals - Google SRE Book
Google SRE 團隊根據他們維運雲端系統的經驗,建議可從以下切角去設計度量指標:
延遲 (Latency)
量測 requests 的耗時
伺服器 正常回應 與 異常回應 的延遲應分開計算,避免抽樣偏誤
錯誤量 (Errors)
通常會計算 HTTP status code 的數量
流量 (Traffic)
通常會計算 RPS (requests per second)
response bytes
飽和度 (Saturation)
量測你的服務目前有「多滿」
通常在使用量還沒達到 100% 之前就會開始出問題。大概 60% 就需要介入了解並因應
而通常,一個小窗口的R99延遲突然升高,會是一個早期飽和訊號
Traces
source: https://www.oreilly.com/library/view/distributed-systems-observability/9781492033431/ch04.html
利用在 request chain 裡傳遞 uuid (e.g. X-Request-ID
in header),tracing system 可以有效掌握一筆 request 流經各個服務所花費的時間
application 可以進一步將 X-Request-ID
寫在 logs 裡,完整地整合 logs 與 traces 資訊給後續排錯分析
source: our Grafana Explore
Micro-level: Continuous Profiling
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
為何需要 Continuous Profiling ?
我們總是不方便在產品發生問題後,才去 profiling 我們的 application。因為事後可能很難重現問題
前面提到的可觀測性三本柱,能夠採集到的資訊還是過於宏觀,許多問題需要更細微的資訊來排查 root cuase
搜集 CPU 執行時間與記憶體使用量的切片,來了解任何一個時刻服務內的詳情
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Google Cloud Profilier 支援的 profiles
現在很流行使用 火焰圖 來解讀 profiling 的資訊
重新組合 call stacks
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
解讀火焰圖
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
source: https://www.brendangregg.com/flamegraphs.html
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Open Source Continuous Profiling Platform - https://pyroscope.io/
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
除了支援線上 Continuous Profiling,本身也支援本地端運行的 profiling 模式,有舒服的 GUI 直接玩
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Live Demo
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
also has Grafana Plugins
結語
還有些技術議題沒提到,看我們能走到哪,未來再補充
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
如何設計高可靠性的服務
retry strategy
timeout
circuit breaker
rate limiting, … etc.
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
微服務的 Transactions 與 Queries (分散式系統的一致性)
若目標是建構一個穩固且可靠的微服務架構,當然不可避免要克服設計、開發與維運上的挑戰。但技術問題其實都好解決, 最難的是 建構一個 有責任感且具備維運意識的工程師文化 (responsible and operationally aware engineering culture)
Image Not Showing
Possible Reasons
The image file may be corrupted The server hosting the image is unavailable The image path is incorrect The image format is not supported
Learn More →
Vote for next sessions
微服務框架下延伸的內容
Kubernetes 使用者須知 (high-level architecture, workloads, storage and networking)
可觀測性技術堆疊的架構概觀及微服務如何協作
探索 Message Queue 的可能性 - 以 RabbitMQ 為例
單體架構遷移策略: 以 Domain-Driven Design 進行思考
雜談
Web Security - Don’t Trust User Input (SQL injection, XSS, CORS, CSRF, CSP, JWT, OAuth?)
探索 RDBMS 的可能性 - (可能)以 Postgres 為例 (ACID, TX, isolation levels, common SQL statements, pratical recommendations)
探索 Caching 的可能性 - 以 Redis 為例 (general rules, pratical issues and recommendations)
Go
Testable project layout (dependency inversion, consistent structure)
Go Slices: usage and internals
… etc.?