DevOps 由 Micro-service 的掘起帶動

自過往二十幾年的軟件開發歷史,軟件

  • 由 Single-Threaded 演變到 Multi-Threaded
  • 由大量 Closed Source 演變到大量 Open Source
  • 由數個人開發演變到幾十人開發
  • 由 Waterfall 的開發節奏演變到 XP、Agile、Scrum、Water-Scrum-Fall… 等等

軟件開發的節奏一直在改變,對應的開發模式選項由只有 Monolithic,到有 Service Oriented Architecture,再到近代興起的 Micro-service Architecture。

每個開發模式都各有利弊,可以肯定一點就是 Micro-service Architecture 嘗試解決一些過往 Monolithic / Service Oriented Architecture 的問題,例如 Scalability、Replaceablility、Waterfall Development、Development Efficiency、Centralized、Tightly Coupled…等等,但與此同時亦會產生 Infrastructure 新挑戰,隨之亦有對應的新工具去解決新挑戰,例如:

  • Infrastructure as Code (Terraform, Ansible)
  • Container (Docker, OCI, containerd)
  • Container Orchestration (Kubernetes)
  • Kubernetes package manager (Helm)
  • Monitoring (Grafana, Prometheus)
  • Logging (fluentd, Kibana)
  • Service-to-Service Efficient Protocol (gRPC)
  • Service-to-Service Authentication, Service Mesh, Blue-Green Deployments (Istio)
  • Automated CI/CD (Jenki, Travis, GitLab CI, Circle CI, GitHub Actions)

DevOps 應此而生,成為構建 Micro-service Architecture 不可或缺的重要一員。

建立 Yaml、建立 CI/CD Pipelines、處理 Secrets

當年有幸於 2015 年尾,公司已經開始轉用 Kubernetes 1.0~1.2(還未有 GKE (Google Cloud)、EKS (AWS)、AKS (Azure) 的年代),很多工序都依靠人手一步步實踐,而印象最深刻就是每一次加 Micro-service 時,就要通知 DevOps* 加入一次性的 Infrastructure Code,包括 Deployment Yaml 及 CI/CD Pipeline、處理一些 Environment Secrets;

*當時有一位 Backend 同事花了整整一個月時間 Full-time R&D 去學習整個 Kubernetes

雖然整件事頗有系統地進行,但筆者的第一印象就有一種假手於人的感覺,於是在工餘時間都會學習 Kubernetes,務求可以「一腳踢」。

愈深入了解,愈認為 Micro-service Architecture 產生的 Software Engineering 新挑戰,基本上離不開某幾種做法,而且極度需要 DevOps 人才逐一了解、測試以及解決。

Software Engineering 的豐儉由人?

Software Engineering 最有趣的地方就是可以「豐儉由人」,幾乎是一個沒有底線也沒有終點,其中一篇筆者很喜歡的文章內一句 Quote:

Qualities are often lost by an accident, but are never accidentally acquired.
Intentional qualities | by Roman Elizarov

簡單來說,Quality 不會從天而降,100% 完成 Product Owner 提出的 Functional Requirements 只是符合最低要求;其中一個 Quality 參考指標就是 Non-Functional Requirements (NFR) 例如,Logging、Monitoring、Automatic CI/CD、Health Checking ⋯⋯ 等等的配套是否全面做妥,還是都「被節儉」了。

「被節儉」NFR 的 Software / System 通常在「風和日麗」的情況下未必會感覺到差別;但在系統出現各類型「風雨交加」的問題時,Software Engineer 便會開始出現「無法迅速地找出問題」的症狀。

墮入 Micro-service 的「美好世界」

在構建 Micro-service Architecture 時,一些 DevOps 經驗尚淺的 Development Team 很容易墮入 Micro-service 的「美好世界」中,例如

  • 誤以為將 Monolithic 拆散、Containerize 並簡單地接通 Micro-service 就等於完成任務
  • 誤以為使用了 Kubernetes 就等如非常成功地運用「Infrastructure as Code」構建 Micro-service Architecture

從筆者的過往的經驗之談,一個沒有任何配套 (NFR) 的 Micro-service System,就算數量少至 4-7 個 Micro-service,也比起做 Monolithic 的開發速度更慢,而且更難 Maintain。

巧遇 Azure Spring Cloud

筆者一直希望尋找一個 Managed Service 既可以使用 Micro-service Architecture 又能真正做到 Zero DevOps 的工作環境,令 Backend 同事可以專注 Software Development,更可以無痛地及敏捷地加入新 Micro-service。

市面上大部份 Managed Service 都只是 Managed Container Orchestration,只能說可以減輕 DevOps 負擔,一定要擁有相關 DevOps 知識及經驗才能正確運用,所以稱不上是一套完整 Solution。

於機緣巧合下,正與 Azure 洽談合作宣傳一個 2021年 2 月的 Open Azure Day Event 時,在洽談過程中得知 Azure 幾個月前剛推出一個全新服務 Azure Spring Cloud,節錄官方:

With Azure Spring Cloud, you can focus on building the apps that run your business without the hassle of managing infrastructure. Simply deploy your JARs or code and Azure Spring Cloud will automatically wire your apps with the Spring service runtime. Once deployed you can easily monitor application performance, fix errors, and rapidly improve applications.

Spring Cloud 不是算是新工具,但由於筆者相對早的時間已經開始使用 Kubernetes,而且 Kubernetes 相關的 DevOps 知識已經相當多,再加上要兼顧 iOS、Android、Web、Backend 的發展,很難再抽空去了解「Spring Cloud 如何解決一個 Micro-service 產生的挑戰」。

筆者對 Spring Cloud 的認識可謂:「只聞其聲,不求其詳」,所以要構建一個 Micro-service Architecture 都會偏向使用 Kubernetes,要由零開始了解 Spring Cloud 實在有太大阻力。

現在既然有 Spring Cloud Managed Service,大幅降低阻力,介紹中亦提到可以讓 Software Engineer 專注在 Software Development 上,更加可以直接 deploy your JARs or code,決定一試!

P.S. 除了宣傳 Open Azure Day Event 之外,以下所有內容㫮是自費測試,Azure 方面沒有提供、修改或刪減任何內容。

立即免費登記 Azure Account,有 $200 美金玩足一年

Azure Spring Cloud First Impression

試用之前,筆者做了少許資料搜集,才發現大部份 Spring Cloud 都是透過 Netflix Open Source Software(OSS) 組合而成 (Netflix 內部使用了一段時間後 Open Source 出來的 Solution)。

有 Netflix 認証已經信心增,而最令筆者感到意外的事莫過於 Netflix 將內部的 Netflix OSS Component 都換成 Spring Cloud Community Solution,節錄:

The union of Netflix OSS and Spring Boot began outside of Netflix. We now embrace it inside of Netflix.
Netflix OSS and Spring Boot — Coming Full Circle

整理了一個 Table 去比較 Azure Spring Cloud 及 Kubernetes 如何解決 Micro-service Architecture 產生的 DevOps 挑戰:

Microservice Challenge Azure Spring Cloud Kubernetes Environment
Configuration Spring Cloud Config Server Kubernets ConfigMap, Kubernets Secrets
Service Discovery Netflix Eureka Kubernets Service, KubernetsIngress
Load Balancing Netflix Ribbon Kubernets Service
API Gateway Netflix Zuul Kubernets Ingress
Centralized Logging Logback + Azure Monitor Fluentd
Centralized Metrics Sleuth, OpenTelemetry(Collector), Azure Monitor Prometheus, Grafana(Plugin)
Distributed Tracing Sleuth, OpenTelemetry(Collector), Azure Monitor Istio, Jaeger, Zipkin
Fault Tolerance Resilience4j Istio
Batch Processing Spring Batch Kubernets Jobs
Auto Scaling Managed by Azure Kubernetes Service (AKS) Managed by Kubernets
Infrastruce and Application Security Audit (i.e. isolation / security patch) Managed by Azure Managed by DevOps
Development JVM based only Any

根據 Azure Spring Cloud 官方網站介紹

The service instances in Azure Spring Cloud are isolated from each other and deployed to security-hardened Azure Kubernetes clusters . Critical security patches for Zulu JDK and Spring Cloud runtimes are applied to Azure Spring Cloud.

Azure Spring Cloud 背後透過 Azure Kubernetes Service (AKS) 組成,但因為 Spring Cloud 大膽假設了所有 Micro-service 均用 Spring Cloud 及 JVM 結構,才可以大大簡化整個使用體驗,實踐 Zero DevOps!

抱著 Zero DevOps 的條件從範例起手

在開始測試之前,筆者是抱著 Zero DevOps 的心態下測試能否達到筆者心目中的要求。

根據這個 Repository 提供的範例,開始 Azure-Samples/spring-petclinic-microservices,實測透過使用 CLI 執行 Repo 內的 Script 就可以完整地 Deploy 整個寫好的 Micro-service architecture,不過有幾個位可以分享一下經驗:

過程中遇到 Create Spring Cloud 是會遇到 Error
spring-cloud-init-script-error-1

要 Fallback 在 Azure Portal 上開 Spring Cloud
spring-cloud-ui-init

其中有一段 mysql CLI script ,如果不想安裝 MySQL CLI Client 建議可以用 Docker 運行

docker run -it --rm mysql mysql defaultdb --host xxx.mysql.database.azure.com --user xxx@mysql-servername --password=xxx

JAR Deployment

# Build JAR in Maven
mvn clean package -DskipTests -Denv=cloud

# Basic Tier need to deploy Jar, Standard Tier can directly deploy source code
az spring-cloud app deploy --name ${API_GATEWAY} \
        --jar-path ${API_GATEWAY_JAR} \
        --jvm-options='-Xms2048m -Xmx2048m -Dspring.profiles.active=mysql'
    

相信一般 Backend 熟悉 CLI 的朋友,應該可以 30 分鐘內構建整個範例,如下:
spring-cloud-init-status

Enterprise Grade Features Out-of-Box

enterprise-grade 毋庸置疑已經成為一個「攻頂」Marketing Buzz Word,相信每一位 Software Engineer 都會對 enterprise-grade 抱有一定想法,例如:

  • Expensive but solved practical challenages
  • Work in large scale organization
  • Simple, stable, straight forward and productive

分享一下 Azure Spring Cloud 試用心得

Micro-service Dependency Graph & Distributed Tracing

一個簡潔清晰的界面標示不同 Micor-service 之間的關係,以及能清楚顯示 Http Call 的數量及 Response time,右邊亦有一些 Insights Action 可以做:
spring-cloud-application-map

spring-cloud-application-map

坊間都有一些幫助 Distributed Tracing 的 Open Source 工具如 Zipkin、Jaeger,兩者都可以自己安裝,也有其它類近的 Enterprise Solution 例如 AppDynamic 可做到相似的效果。

例如以完全免費的 Self-Hosted Kubernetes + Jaeger 為例,除了 UI 界面差別外,筆者認為最大的差別在於 Azure Spring Cloud 可以在同一個 Azure Portal 下 Monitor 整個 Micro-service Architecture,當要管理一些 Role-based Access 時必定會相對地簡單。

Auto Scaling

Apps > api-gateway > Scale out (preview) 設定 Auto Scaling。

Azure Spring Cloud 底蘊使用了 Azure Kubernetes Service (AKS),因此筆者對這個 Auto Scale 的 Implementation 也感到十分安心,嘗試設定
api-gateway

  • CPU > 50%, Scale out 1 instance
  • CPU < 20%, Scale In 1 instance
  • Maximum 2 instance

customer-service

  • CPU > 50%, Scale out 1 instance
  • CPU < 20%, Scale In 1 instance
  • Maximum 4 instance

spring-cloud-auto-scale
spring-cloud-auto-scale-2

若使用傳統 VM 方式去做 Self Hosted Spring Cloud,Auto Scale 要額外人手處理;用 Kubernetes 的話,則要有對應 DevOps 知識管理整套 Kubernetes,可謂一闊三大 ⋯⋯

測試 Auto Scaling

簡單以 Go bombardier 轟炸一下 Azure Spring Cloud Cluster 內的一個 List Owner Endpoint,測試一下 Auto Scaling

https://join-open-azure-day-api-gateway.azuremicroservices.io/api/customer/owners

docker run -ti \
--rm --ulimit nofile=65535:65535 \
alpine/bombardier \
-o json \
-p result \
--http1 \
-c 10 \
-d 900s \
-t 30s \
-l https://join-open-azure-day-api-gateway.azuremicroservices.io/api/customer/owners | jq .

Auto Scaling 於 Application Insights > Live Metrics 查看
spring-cloud-auto-scaling-live-metrics

不斷加入 bombardier 簡單做一個 Ramp up 效果,最後成功 Horizontal Scale out 到 Maximum 數目。

Performance Monitoring

運行後,結果比想像中的有點差,透過 Application Map 內見到有大量 Database Query,在 Performance 版面發現 spring-petclinic-microservices Implementation 可能存在 N+1 Fetch 問題 (一個在 Spring + Hibernate 極度常見的 Performance Issues)

spring-cloud-application-map-highlight-1

spring-cloud-performance-highlight

Application Insights > Transaction Search
spring-cloud-insight-transaction-search

確認存在 N + 1 Fetch Issues
spring-cloud-n1-issues

試想一下,如果 Micro-service Architecture 沒有安裝一些 Metrics Agent,在一個完全摸黑的地方要找出 Performance 問題,談何容易。

Upgrade to Production

可以一鍵將 Basic Cluster 升級到 Standard Cluster,R&D 未 Launch Production 前,可以一直使用 Basic,價錢便值一點,但相對地沒有 SLA、HA、Custom Domain、VNET、Blue/Green Deployment、Deploy from Source Code 的功能

spring-cloud-upgrade

Pricing?

Azure Spring Cloud 價錢
spring-cloud-price

這個是 East Asia (包括 Hong Kong) 的 Cluster,Bundled 最少要用 16 vCPU 32GB RAM,即 2 vCPU 4 GB 可以運行 8 個 Instance,相信足夠大部份 Startup 剛開業時的需求。

另外,若一間做 Spring Boot + JVM Monolithic 的公司有意想試行 Spring Cloud 路線,筆者認為 Azure Spring Cloud (Managed Service) 絕對可以幫助:

  • 省卻聘用 DevOps 高手費用及減低 DevOps 離職後的風險;試想一下,如果公司只得一個 DevOps,離職時會相當麻煩,聘用兩個 DevOps 防止 Single Point of Failure 卻更加提高成本
  • 省卻開發及設定相關 Open Source / Enterprise Solution 去解決 Micro-service「必須」的 Monitoring 及 Distributed Tracing;Spring Cloud 內例如一些 Spring Cloud Config Server、Distributed Tracing Service、Prometheus ⋯⋯等等 R&D 及學習成本

在同一個 Spring Petclinic 例子中,也有不是 Azure Spring Cloud 的版本
GitHub - spring-petclinic/spring-petclinic-microservices: Distributed version of Spring Petclinic built with Spring Cloud

spring-cloud-local

例子中可以看到有不同 Self-managed Service 要了解及接駁,Performance Monitor 分別使用了 Zipkin 及 Grafana,要分別設定 Access 的方法。

總結

有鑑於筆者有 Kubernetes + Spring + Kotlin 的使用背景,在親身體驗後覺得 Azure Spring Cloud 非常有趣,雖然有 JVM + Spring 的限制,但正因為這個大膽的假設及 Netflix OSS Contribution,令整個 Managed Spring Cloud 可以更加緊密整合去實踐 Zero DevOps - 即使沒有任何 DevOps 經驗也可以做到一個 Maintenance Free 的 Micro-service Architecture,更會比起一些只有半桶水的 Managed Kubernets + Customization 或 Self-host Kubernetes 的 Micro-service System 更完善。

此外,公司就算沒有 DevOps 高手,筆者相信只要有 Spring 高手加基本 CLI 認識,就可以開始用 Spring Cloud based Micro-service Architecture;至於價錢上到底值不值用 Managed Service,筆者建議以時間成本、技術限制及風險管理去作出理性判斷,始終每個人或公司的團隊背景都不一樣,不能一概而論。

Micro-service Architecture 不單只是產生了一些新的 DevOps 挑戰,亦產生了一些新的 Development 挑戰,例如

  • Independent Database
  • Distributed Transactions
  • Duplicated Domain Models Overhead
  • Backward-compatible upgrade
  • RESTful API Intergration Overhead

⋯⋯等等,有機會再寫!(你懂的,大家識做)

如有更多興趣了解 Spring Cloud,於 23 Feb 2021 (Tue) 11:25am - 11:55am 有一場 Open Azure Day 廣東話分享 《The Cloud Native Platform for your Microservice Apps with Azure Spring Cloud in real life》!快啲報名聽下!

最後,不得不提嘅係 Spring + Kotlin 其實幾好寫,筆者亦十分期待日後的 Spring Native (GraavlVm) Binary 可以媲美 Go 的極速 Boot Time!

Study Resources

Netflix OSS and Spring Boot: Coming Full Circle

Azure Spring Cloud: a fully managed service for Spring Boot apps is now generally available

Azure Spring Cloud: Bootiful Application Monitoring with Azure Spring Cloud

GitHub - Azure-Samples/spring-petclinic-microservices: Distributed version of Spring Petclinic built with Spring Cloud

GitHub - microsoft/azure-spring-cloud-training: Guides and tutorials to make the most out of Azure Spring Cloud

Spring Cloud History: Introducing Spring Cloud