寫在前面
要出發(fā)周邊游(以下簡稱要出發(fā))是國內知名的主打「周邊游」的在線旅行網站,以國內各大城市為中心,覆蓋其周邊旅游市場,提供包含酒店、門票、餐飲等在內的 1 – 3 天短途旅行套餐。為了降低公司內部各個業(yè)務模塊的耦合度,提高開發(fā)、交付及運維效率,我們在 2017 年就基于 Spring Cloud 完成了公司內部業(yè)務微服務化的改造,并在 2019 年實現(xiàn)了 Spring Cloud 至 UCloud UK8S 平臺的遷移。
本文從要出發(fā)的業(yè)務架構、Prometheus JVM 監(jiān)控、基于 HPA 的峰值彈性伸縮、基于 Elastic 的APM鏈路跟蹤及 Istio 服務治理 等方面介紹了我們基于UCloud UK8S的 Spring Cloud 改造實踐。
Why K8S and Why UK8S
Spring Cloud 作為當下主流的微服務框架,在功能層面為服務治理定義了智能路由、熔斷機制、服務注冊與發(fā)現(xiàn)等一系列的標準,并提供了對應的庫和組件來實現(xiàn)這些標準特性,對微服務周邊環(huán)境提供了最大力度的支持。
改造前,Spring Cloud 的業(yè)務架構如下:服務發(fā)現(xiàn)部分采用了 Spring Cloud 的 Eureka 組件,熔斷器組件采用了 Hystrix,服務網關使用了Zuul 和 Spring Cloud Gateway(歷史原因),分布式配置主要采用了 Spring Cloud Config(部分小組使用了Apollo),并通過 Feign 實現(xiàn)了客戶服務端的負載均衡。
但 Spring Cloud 也有一些不可避免的缺點,如基于不同框架的不同組件帶來的高應用門檻及學習成本、代碼級別對諸多組件進行控制的需求與微服務多語言協(xié)作的目標背道而馳。
在我們內部,由于歷史原因,不同小組所使用的 API 網關架構不統(tǒng)一,且存在多套 Spring Cloud,給統(tǒng)一管理造成了不便;Spring Cloud 無法實現(xiàn)灰度發(fā)布,也給公司業(yè)務發(fā)布帶來了一定不便。更重要的是,作為一家周邊游網站,我們經常會舉行一些促銷活動,面臨在業(yè)務峰值期資源彈性擴縮容的需求 ,僅僅依靠 Spring Cloud 也無法實現(xiàn)資源調度來滿足業(yè)務自動擴縮容的需求。
在決定向 UCloud UK8S 轉型時,我們也考慮過使用 Kubespray 自建 K8S 集群,并通過 Cloud Provider 實現(xiàn) K8S 集群與云資源的對接,例如使用 Load Balance、Storage Class、Cluster Autoscaler(CA) 等,但在這種情況下,新增 Node 節(jié)點需要單獨去部署安裝 Cloud Provider,給運維工作帶來了一定的復雜性。
UCloud UK8S 實現(xiàn)了與內部 UHost 云主機、ULB 負載均衡、UDisk 云盤等產品的無縫連接,我們能夠在 UK8S 集群內部輕松創(chuàng)建、調用以上產品。在峰值彈性的場景下,也能夠通過 UK8S 內部的 CA 插件,實現(xiàn) Node 級別的資源自動擴縮容,極大提升了運維效率 。通過其 CNI 插件,UCloud UK8S 與 UCloud 自身 VPC 網絡相連接,無需采用其他開源網絡解決方案,降低了網絡復雜度 ;而 UK8S 原生無封裝的特質,也給了更大的改造空間,并且能夠在出現(xiàn)故障時自己快速排查定位解決 。
整體業(yè)務架構
從 Spring Cloud 到 UCloud UK8S 的過程,也是內部服務模塊再次梳理、統(tǒng)一的過程,在此過程中,我們對整體業(yè)務架構做了如下改動:
1. 去掉原有的 Eureka,改用 Spring Cloud Kubernetes 項目下的 Discovery。Spring Cloud 官方推出的項目 Spring Cloud Kubernetes 提供了通用的接口來調用Kubernetes服務,讓 Spring Cloud 和 Spring Boot 程序能夠在 Kubernetes 環(huán)境中更好運行。在 Kubernetes 環(huán)境中,ETCD 已經擁有了服務發(fā)現(xiàn)所必要的信息,沒有必要再使用 Eureka,通過 Discovery 就能夠獲取 Kubernetes ETCD 中注冊的服務列表進行服務發(fā)現(xiàn)。
2. 去掉 Feign 負載均衡,改用 Spring Cloud Kubernetes Ribbon。Ribbon 負載均衡模式有 Service / Pod 兩種,在 Service 模式下,可以使用 Kubernetes 原生負載均衡,并通過 Istio 實現(xiàn)服務治理。
3. 網關邊緣化。網關作為原來的入口,全部去除需要對原有代碼進行大規(guī)模的改造,我們把原有的網關作為微服務部署在 Kubernetes 內,并利用 Istio 來管理流量入口。同時,我們還去掉了熔斷器和智能路由,整體基于 Istio 實現(xiàn)服務治理。
4. 分布式配置 Config 統(tǒng)一為 Apollo。Apollo 能夠集中管理應用在不同環(huán)境、不同集群的配置,修改后實時推送到應用端,并且具備規(guī)范的權限、流程治理等特性。
5. 增加 Prometheus 監(jiān)控,特別是對 JVM 一些參數(shù)和一些定義指標的監(jiān)控,并基于監(jiān)控指標實現(xiàn)了 HPA 彈性伸縮。
Kubernetes 化后業(yè)務架構將控制平面和數(shù)據(jù)平面分開。Kubernetes Master天然作為控制平面,實現(xiàn)整套業(yè)務的控制,不部署任何實際業(yè)務。數(shù)據(jù)平面中包含了基于 Java、PHP、Swoole、.NET Core 等不同語言或架構的項目。由于不同語言對機器性能有著不同要求,我們通過 Kubernetes 中節(jié)點 Label,將各個項目部署在不同配置的 Node 節(jié)點上,做到應用間互不干擾。
基于 Prometheus 的 JVM 監(jiān)控
在 Spring Cloud 遷移到 Kubernetes 后,我們仍需要獲取 JVM 的一系列底層參數(shù),對服務的運行狀態(tài)進行實時監(jiān)控。Prometheus 是目前較為成熟的監(jiān)控插件,而 Prometheus 也提供了 Spring Cloud 插件,可以獲取到 JVM 的底層參數(shù),進行實時監(jiān)控。
我們設置了響應時間、請求數(shù)、JVM Memory、JVM Misc、Garbage Collection 等一系列詳盡的參數(shù),為問題解決、業(yè)務優(yōu)化提供可靠的依據(jù)。
基于 HPA 的峰值彈性伸縮
要出發(fā)作為一家周邊游服務訂購平臺,在業(yè)務過程中經常會涉及到景區(qū)、酒店門票搶購等需要峰值彈性的場景 。Kubernetes 的 HPA 功能為彈性伸縮場景提供了很好的實現(xiàn)方式。
在 Kubernetes中,HPA 通常通過 Pod 的 CPU、內存利用率等實現(xiàn),但在 Java 中,內存控制通過 JVM 實現(xiàn),當內存占用過高時,JVM 會進行內存回收,但 JVM 并不會返回給主機或容器,單純基于 Pod / CPU 指標進行集群的擴縮容并不合理。我們通過 Prometheus 獲取 Java 中 http_server_requests_seconds_count(請求數(shù))參數(shù),通過適配器將其轉化成 Kubernetes API Server 能識別的參數(shù),并基于這一指標實時動態(tài)調整 Pod 的數(shù)量。
UCloud UK8S 產品也提供了自身的集群伸縮插件,通過設置伸縮組,并匹配相應的伸縮條件,能夠及時創(chuàng)建相應的云主機作為 Node 節(jié)點,方便我們在業(yè)務高峰時期更快速高效地拉起資源 。
基于 Elastic 的APM鏈路跟蹤
微服務框架下,一次請求往往需要涉及到多個服務,因此服務性能監(jiān)控和排查就變得復雜;不同服務可能由不同的團隊開發(fā),甚至使用不同的編程語言來實現(xiàn);服務有可能部署在幾千臺服務器,橫跨多個不同的數(shù)據(jù)中心。
因此,就需要一些可以幫助理解系統(tǒng)行為、用于分析性能問題的工具,以便發(fā)生故障的時候,能夠快速定位和解決問題。
目前市面有很多開源的APM組件,Zipkin、Pinpoint、Skywalking等等。我們最終選擇了基于Elastic開源的apm-server。正是由于市面上有太多的監(jiān)控開源項目,但是各項目之間無法很好的互通。 而Elastic通過filebeat收集業(yè)務日志,通過metricbeat監(jiān)控應用服務性能,通過apm-server實現(xiàn)服務間的tracing,并把數(shù)據(jù)統(tǒng)一存放在es,很好的將logging、metrics、tracing整合到一起,打破了各項目之間的壁壘,能夠更快速的協(xié)助運維及開發(fā)定位故障,保障系統(tǒng)的穩(wěn)定性。
Istio 服務治理
基于應用程序安全性、可觀察性、持續(xù)部署、彈性伸縮和性能、對開源工具的集成、開源控制平面的支持、方案成熟度等考慮,我們最終選擇了 Istio 作為服務治理的方案,主要涉及以下幾個部分:
1. Istio-gateway 網關:Ingress Gateway 在邏輯上相當于網格邊緣的一個負載均衡器,用于接收和處理網格邊緣出站和入站的網絡連接,其中包含開放端口和TLS的配置等內容,實現(xiàn)集群內部南北流量的治理。
2. Mesh 網關:Istio內部的虛擬Gateway,代表網格內部的所有Sidecar,實現(xiàn)所有網格內部服務之間的互相通信,即東西流量的治理。
3. 流量管理:在去除掉 Spring Cloud 原有的熔斷、智能路由等組件后,我們通過對 Kubernetes 集群內部一系列的配置和管理,實現(xiàn)了 http 流量管理的功能。包括使用 Pod簽對具體的服務進程進行分組(例如 V1/V2 版本應用)并實現(xiàn)流量調度,通過 Istio 內的 Destination Rule 單獨定義服務負載均衡策略,根據(jù)來源服務、URL 進行重定向實現(xiàn)目標路由分流等,通過 MenQuota、RedisQuota 進行限流等。
4. 遙測:通過 Prometheus 獲取遙測數(shù)據(jù),實現(xiàn)灰度項目成功率、東西南北流量區(qū)分、服務峰值流量、服務動態(tài)拓撲的監(jiān)控。
總結
目前我們已將旗下「云客贊」社交電商 App 全部遷移至 UK8S,開發(fā)語言包括Java、PHP-FPM、NodeJS 等等。結合CI/CD,能快速實現(xiàn)服務迭代以及新項目上線,大大提升了開發(fā)以及運維的工作效率;通過完善的日志、監(jiān)控、鏈路跟蹤及告警系統(tǒng),能夠快速的定位故障,并且根據(jù)遙測數(shù)據(jù)提前預判峰值,通過HPA實現(xiàn)服務自動伸縮,科學的分配資源,大大降低了計算資源成本;通過Istio服務治理,很好的實現(xiàn)了流量的管理,并且基于此輕松的實現(xiàn)了灰度發(fā)布。
接下來,我們將更加豐富CI/CD流水線,加入單元測試、代碼掃描、性能測試等提升測試效率;引入chatops豐富運維手段;借助Istio實現(xiàn)多云管理進一步保障業(yè)務的穩(wěn)定性。
作者:王瓊,「要出發(fā)周邊游」運維架構師兼運維經理,負責公司云原生落地和企業(yè)容器化改造。2016年開始接觸K8S,在K8S以及Service Mesh領域持續(xù)深耕,致力于搭建生產級可用的容器服務平臺。
申請創(chuàng)業(yè)報道,分享創(chuàng)業(yè)好點子。點擊此處,共同探討創(chuàng)業(yè)新機遇!