劉琦
摘 要:隨著容器技術的快速發(fā)展,應用服務的支撐框架已從原先的物理機、云計算虛擬機到目前的基于Kubernetes的容器平臺?;谌萜髌脚_的云原生應用通過應用本身的彈性、動態(tài)擴張實現(xiàn)可造性(resiliency)。文章從平臺支持和應用本身的改造兩方面說明云原生應用可造性的實現(xiàn)方式。
關鍵詞:云原生應用;應用服務;可造性
1 云原生應用平臺研究背景
云計算時代,各類云計算平臺如雨后春筍般出現(xiàn)在各個企業(yè)中,雖然在服務類型和平臺功能上有所差異,但是他們本質都是一樣,均是一種資源的服務模式。云平臺的快速發(fā)展,衍生了一系列云平臺產品。隨著大規(guī)模的互聯(lián)網應用不斷在云計算平臺上遇到挑戰(zhàn),新的應用架構模式呼之欲出,在眾多的實踐和方法論中,云原生應用是其中的佼佼者,主要包含容器化、容器的動態(tài)編排和微服務。
2 云原生應用平臺介紹
Kubernetes是Google開源的容器集群管理系統(tǒng),構建在Docker技術之上,為容器化的應用提供資源調度、部署運行、服務發(fā)現(xiàn)動態(tài)伸縮等一系列完整功能,它最大的優(yōu)點是可以顯著提升整個集群的總CPU利用率,所以成為眾多容器調度框架中最受歡迎的調度模式。云原生應用平臺是基于Kubernetes實現(xiàn)的,在完全兼容Kubernetes、Docker 技術的基礎上,提高大規(guī)模容器集群管理的便捷性。
2.1 使用場景
2.1.1 大型復雜系統(tǒng)
原本小而簡單的應用會隨著長時間使用變得臃腫,在大型復雜系統(tǒng)中,應用越大,啟動時間越長,修復bug和實施新功能也就愈發(fā)困難且耗時頗多,從而影響開發(fā)和交付的敏捷性,大大降低了生產效率。面對數(shù)據(jù)中心規(guī)模大、應用數(shù)量多,技術架構多樣,但運維人力有限的問題,將運維復雜度和應用規(guī)模解耦是可行的解決思路。從運維系統(tǒng)的角度出發(fā),隨著應用越來越復雜,必須引入相應的平臺化手段進行解耦,避免有限的運維人力與不斷擴大的數(shù)據(jù)規(guī)模之間的矛盾。
云原生應用平臺通過微服務架構重新構建復雜的應用,將單體式應用從不同緯度拆分成多個微服務,每個微服務的內容使用一個Docker鏡像管理。在功能不變的情況下,應用拆分成了多個可管理的服務,每個單體的服務容易理解、開發(fā)和維護。不同的服務也可以由不同的團隊來開發(fā),開發(fā)團隊可自由選擇開發(fā)技術和程序語言等,每個服務又可獨立部署、獨立擴展。
2.1.2 業(yè)務頻繁升級
龐大且復雜的應用的另一問題是難以進行持續(xù)部署更新,而目前的發(fā)展趨勢要求應用可以在單日內多次將修改推送到生產環(huán)境。對于傳統(tǒng)應用而言,更新應用的某個部分,必須重新部署整個應用,更新周期被無限拉長,漫長的啟動時間更是雪上加霜,此外,由于不能完全預見修改的影響,用戶不得不提前進行大量人工測試,使得持續(xù)部署變得不可能。實現(xiàn)快速迭代首先需要開發(fā)獨立,如果一單體應用由幾百人開發(fā)一個模塊,將可能出現(xiàn)代碼提交沖突頻發(fā)、人員過多而難以溝通解決的情況。團隊規(guī)模越大,沖突概率則越大。
當應用被拆分成不同的模塊,每個模塊由10個人左右進行維護時,首先可大幅降低代碼沖突的概率,當技術沖突發(fā)生時也更容易解決。每個模塊對外提供接口,其他依賴模塊無需關注具體的實現(xiàn)細節(jié),只需要保證接口正確。適合需要快速上線、頻繁更新升級的業(yè)務。
云原生應用平臺通過持續(xù)集成、持續(xù)交付、持續(xù)運維,極大提高軟件的發(fā)布效率。持續(xù)集成強調開發(fā)人員提交了新代碼之后,立刻進行構建、(單元)測試,便于確定新代碼和原有代碼能否正確地打包集成在一起。持續(xù)交付在持續(xù)集成的基礎上,將集成的代碼部署到預發(fā)布環(huán)境和現(xiàn)網環(huán)境上。而持續(xù)運維則通過各種自動化工具實現(xiàn)了整個應用在運行過程中的托管。通過以上3項功能實現(xiàn)應用全生命周期管理。
2.1.3 功能持續(xù)擴展
應用要實現(xiàn)快速迭代,首先需要上線獨立。如果沒有拆分微服務,每次上線都將面臨各類挑戰(zhàn)。當修改某個小功能時,因為依賴其他模塊而造成的模塊耦合、互相依賴,使得整體應用上線的復雜度更高、風險更大、周期更長。
當服務拆分后,在接口穩(wěn)定的情況下,不同的模塊可以獨立上線。上線的次數(shù)增多,單次上線的需求列表變小,可隨時回滾,風險降低,周期縮短,影響面小,從而加快迭代速度。對于需要接口升級的部分,可采取灰度的方式,先做接口新增,而非原接口變更,并通過注冊中心監(jiān)控接口調用情況,確保原接口不再使用再進行刪除。
2.1.4 應用并發(fā)量大、穩(wěn)定、高可用
可靠性是傳統(tǒng)應用難以解決的問題之一。由于所有模塊都運行在同一進程中,任何模塊中的一個bug,例如內存泄漏都可能影響到整個進程。此外,由于應用中的所有實例都是唯一,這個bug將影響整個應用的可用性。
并發(fā)性是另一個問題。對于并發(fā)量不大的系統(tǒng)而言,進行云原生化的驅動力較低,如果只有少量的用戶在線,多線程即可解決問題。然而對于存在突發(fā)性訪問高峰,有明顯波峰和波谷的應用而言,云原生化不僅可大幅提高其可用性,還可以實現(xiàn)熱備和雙活等特性。
2.2 核心功能
云原生應用平臺為客戶提供了一套完整的云原生應用服務,可提供容器服務、資源管理與編排、多租戶鏡像倉庫、應用部署、應用全生命周期管理、持續(xù)集成以及應用常用通用組件,例如智能網關、基礎賬號體系支撐等功能。主要可以實現(xiàn)這六大特性:以應用驅動資源、多語言集成、一鍵式部署、快速發(fā)布更新、彈性伸縮、持續(xù)穩(wěn)定。
云原生平臺的主要功能包含以下方面。
2.2.1 資源統(tǒng)一納管
(1)虛擬機、物理機混合管理:云原生應用平臺容器平臺能進行統(tǒng)一資源管理和調度,打通物理機、虛擬機,使之互相通信,協(xié)同工作。基于云原生應用平臺創(chuàng)建的k8s集群,可實現(xiàn)基于IP地址手動添加虛擬機、物理機資源節(jié)點。提供對虛擬機或物理節(jié)點完善的管理功能,可以方便直觀地獲取主機監(jiān)控信息以及主機信息等,包括CPU、內存、I/O。
(2)存儲資源管理:云原生應用平臺提供對存儲節(jié)點完善的管理功能,容器應用通過持久卷實現(xiàn)狀態(tài)存儲,后臺使用Ceph存儲集群,云原生應用平臺支持存儲節(jié)點動態(tài)添加,可以方便直觀地獲取存儲節(jié)點監(jiān)控信息,包括CPU、內存、I/O。
(3)異構IaaS層資源接入:云原生應用平臺異構實現(xiàn)對接多種異構IaaS,統(tǒng)一其接口及資源模型,可以實現(xiàn)在不同IaaS部署標準的Kubernetes集群。支持同時接入虛擬機CPU、虛擬機GPU、物理機CPU、物理機GPU 4種類型的資源管理。
(4)多集群、多租戶隔離:云原生應用平臺采用多集群、多租管理模型和租戶的資源配額管理,嚴格實現(xiàn)多租戶資源/服務的安全隔離。集群(Cluster)為物理隔離單位,實現(xiàn)物理資源隔離。租戶(Tenant)為邏輯隔離單位,實現(xiàn)虛擬資源的邏輯隔離。如一個公司可創(chuàng)建多個集群,并在集群中配置多個租戶,通過用戶組、用戶和權限對各個集群、租戶的安全性進行隔離和控制。同時也能實現(xiàn)配額管理,為避免單一租戶過量占用資源,可通過K8s集群中的租戶管理實現(xiàn)資源配額,主要包括CPU和內存資源限制,同時也可以限制容器資源的創(chuàng)建。
2.2.2 集群自動化部署
云原生應用平臺容器平臺提供K8s集群的自動化部署??蓪崿F(xiàn)部署過程中每一個步驟的自動化,在整個生命周期(包括部署在內)中把必須的人工干預降低到最小。
2.2.3 多租戶鏡像倉庫
(1)多租戶鏡像管理:云原生應用平臺提供對容器鏡像的統(tǒng)一管理,內容包括鏡像名稱、版本,從軟件包的鏡像構成,以及鏡像打包的統(tǒng)一規(guī)范流程,其主要功能包括:鏡像全生命周期管理,鏡像版本管理,安全掃描以及鏡像倉庫訪問控制。
(2)鏡像倉庫訪問控制:鏡像倉庫實現(xiàn)多租戶訪問控制,用戶可以使用并修改被綁定租戶中的鏡像。
2.2.4 應用商店及一鍵式部署
(1)標準應用包管理:可以直接通過配置文件和容器鏡像,對應用包進行管理,包括版本、配置文件、腳本等。
(2)大量PaaS、SaaS服務:為用戶提供大量常用應用模板,包含成熟的PaaS服務,開源的服務(MySQL、Redis等),實現(xiàn)應用一鍵式部署
(3)自動化部署、升級:該平臺為各種業(yè)務配置合適的資源進行安裝部署,并支持應用的更新、升級、擴容、伸縮、卸載等。為各種業(yè)務配置合適的資源進行安裝部署,并支持業(yè)務的更新、升級、擴容、伸縮、卸載等,其支持業(yè)務包括:無狀態(tài)應用、有狀態(tài)應用、多鏡像聯(lián)調部署模型。
(4)通過平臺可以實現(xiàn)對應用的調度策略,以容器為最小運行單位實現(xiàn)應用的不同調度策略,包括:①應用(容器)間的親和/反親和性調度,不同的業(yè)務調度部署在相同或不同節(jié)點中。②應用與節(jié)點的親和/反親和性調度,應用的容器調度部署到指定的或與指定不同的節(jié)點中。
2.3 平臺架構
在數(shù)字化轉型的過程中,針對應用上云的需求,云原生應用平臺結合原有的技術沉淀,為警務服務創(chuàng)建了一套云原生應用支撐平臺。在基礎實施和應用層面解決了警務應用在數(shù)字化轉型中所面臨的痛點,幫助客戶采用云原生技術實現(xiàn)應用架構轉型升級和高效管理。平臺架構如圖1所示。
3 應用服務可造性
3.1 應用拆分&集成
3.1.1 分拆模式
云原生應用采取有關松散耦合的服務,它采用的是單一職責原則。理論上要將應用分成多個小塊,在實際分拆中一般遵守以下規(guī)則。按照業(yè)務功能分拆:業(yè)務功能是指產生價值的最小單位,一組給定業(yè)務的功能劃分則取決于企業(yè)本身的類型,每一個業(yè)務功能都可以被看作是一種面向業(yè)務,而非技術的服務。
3.1.2 分拆規(guī)范
(1)規(guī)范一:服務縱向拆分最多3層、兩次調用。服務拆分是為了橫向擴展,因而應橫向拆分而非縱向拆成多層級式??v向最多拆分3層。
①基礎服務層:用于屏蔽數(shù)據(jù)庫、緩存層,提供原子的對象查詢接口,封裝數(shù)據(jù)從而實現(xiàn)數(shù)據(jù)庫擴容、緩存替換等。使得數(shù)據(jù)對上層透明,上層僅調用這一層的接口而不直接訪問數(shù)據(jù)庫和緩存。
②組合服務層:這一層調用基礎服務層,完成較為復雜的業(yè)務邏輯,實現(xiàn)分布式事務也多在這一層。
③對外接口層:調用組合服務層對外提供標準接口。
(2)規(guī)范二:僅單向調用、嚴禁循環(huán)調用。服務拆分后,如果服務間的依賴關系復雜(如循環(huán)調用),則升級將會變得難以維護。因而層次之間的調用規(guī)定如下。
①基礎服務層主要做數(shù)據(jù)庫的操作和一些簡單的業(yè)務邏輯,不允許調用其他任何服務。
②組合服務層可以調用基礎服務層,完成復雜的業(yè)務邏輯,可以調用組合服務層,不允許循環(huán)調用,不允許調用對外接口層服務。
③對外接口層,可以調用組合業(yè)務層服務,不允許被其他服務調用。如果出現(xiàn)循環(huán)調用,則使用消息隊列,將同步調用改為異步調用。
(3)規(guī)范三:將串行調用改為并行或異步調用。如有的組合服務需要調用多個外部服務,應考慮如何通過消息隊列實現(xiàn)異步化和解耦。對基于Kubernetes的云原生應用,使用消息隊列可增強其橫向擴展能力?;蛘咄ㄟ^Kubernetes內服務自帶的負債均,這樣處理時間會大大縮短(不是多次調用的時間之和,而是調用所需最長時間)。
(4)規(guī)范四:接口嚴格按照REST標準寫。以前不同服務接口之間傳遞往往通過數(shù)據(jù)結構,從底層一直到上層使用同一個數(shù)據(jù)結構,或上層的數(shù)據(jù)結構內嵌底層的數(shù)據(jù)結構。當數(shù)據(jù)結構中添加或者刪除一個字段的時候,波及的面會非常大。因REST標準在每兩個接口之間約定,嚴禁內嵌和透傳。這樣接口協(xié)議的改變,影響面僅僅在調用方和被調用方,當接口需要更新的時候比較可控,也容易升級。
3.2 應用容器化
3.2.1 應用分析
操作系統(tǒng):應用運行的操作系統(tǒng)類型和版本,如centos7.2。
運行環(huán)境:Java,go,php,python等,以及對應的版本號。
依賴:如openssl,以及對應的版本號。
3.2.2 盡量使用TCP、HTTP協(xié)議
服務間接口調用使用非標準協(xié)議進行交互(如EJB調用使用t3協(xié)議),無法通過負載均衡器進行有效負載。建議服務間接口調用通過TCP和HTTP協(xié)議進行交互,這樣可使用負載均衡器進行有效負載。
3.2.3 確定域名、端口
每個服務盡量只提供一個服務。
避免使用IP:如果服務需要與其他服務通訊,由于容器IP是不固定的,依賴IP地址將無法實現(xiàn)通訊。建議在程序中盡量使用域名代替IP,并且通過Kubernetes的Service負債均衡,尤其對傳統(tǒng)非改造的應用直接搬遷,需要使用這個模式。集群中訪問,則使用service的域名方式訪問更好。
監(jiān)聽固定端口:對于標準的服務只需提供一個對外服務端口,而有些服務在運行過程中會自己產生一些服務端口對外服務,而且這些端口是隨機產生,給管理帶來不便。建議在服務設計時盡量使用固定服務端口,并且需要讓端口固定下來并體現(xiàn)在集成文檔中。
3.2.4 設計好程序啟動過程和時間
雖然容器服務本身可以做到“秒級”啟動,但是對于程序如何在容器/Kubernetes里啟動,需要遵守標準的規(guī)范。程序在容器內啟動過程大體如圖2所示。
Kubernetes提供雙重檢查:liveness和readiness。容器啟動并不代表程序已經可以被訪問,因為容器內部程序啟動比較費時,如果此時去訪問服務則很容易timeout。
Liveness: 確保程序還存活,否則Kubernetes就會重啟這個POD。
Readiness: 確保程序已經可以接收流量了,否則不會分發(fā)流量給它。
3.2.5 充分利用K8s Deployment & Service
使用Kubernetes的Deployment的方式來部署服務,Deployment會保證服務時刻有一定的副本存活,提高了服務穩(wěn)定性。其次,Kubernetes的Service可以實現(xiàn)負載的均衡。Kube-DNS可以將Service名解析成具體的ClusterIP?;贙ube-DNS和Service的特性,可以實現(xiàn)服務的注冊發(fā)現(xiàn)和負載均衡。具體如圖3所示。
3.3 應用無狀態(tài)化
有狀態(tài)應用是指在應用內存儲狀態(tài)信息。例如用戶在登錄后會有一定的會話信息(也就是應用中的session對象)存儲在實例中,如果該實例異常停止,該用戶的會話信息就會丟失。
建議應用開發(fā)時將用戶的會話信息保存到緩存(如Redis,Memcached)中,根據(jù)用戶的唯一標識session_id來對緩存服務器進行存取用戶的會話信息,這樣會話信息與應用實例分離,實現(xiàn)應用無狀態(tài)化。
3.4 熱數(shù)據(jù)緩存
熱數(shù)據(jù)指程序在運行過程中經常使用的數(shù)據(jù),傳統(tǒng)方式是程序在啟動時通過數(shù)據(jù)庫加載到程序實例緩存中,提高數(shù)據(jù)的訪問速度,但往往因為加載的數(shù)據(jù)過多而導致系統(tǒng)啟動過慢。
建議程序在設計時將熱點數(shù)據(jù)存放到緩存(如Redis,Memcached)中,在啟動時避免執(zhí)行加載緩存動作,提高程序啟動速度,相關熱點數(shù)據(jù)可通過手動或自動方式更新到緩存中,程序通過訪問緩存獲取相關熱點數(shù)據(jù)。
3.5 有狀態(tài)數(shù)據(jù)庫
服務必須是松散耦合的,以便部署和獨立擴容,尤其當各個服務需要橫跨多個服務時。當應用需要從多個服務中查詢到數(shù)據(jù)時,有時需要根據(jù)需求和規(guī)模對數(shù)據(jù)庫進行復制或分片,不同的服務具有不同的數(shù)據(jù)存儲需求。
服務單獨DB:為每個服務配備一個獨享的數(shù)據(jù)庫模式,該數(shù)據(jù)庫僅能被其對應服務的API單獨訪問,而不能被其他服務直接訪問到。每個服務應該擁有一個單獨的數(shù)據(jù)庫ID,以便它們在獨享訪問的同時,禁止再訪問其他的服務表集。
服務共享DB:服務單獨DB是一種理想的微服務模式,只有在新的云原生應用中會用到。但對于采用微服務架構的應用,按服務共享DB的模式雖然有些違背微服務的理念,但對于將傳統(tǒng)的單體應用拆分成較小的邏輯塊而言是更為適用的。在該模式下,一個數(shù)據(jù)庫可以匹配多個服務,當然至多2~3個,否則會影響到擴容、自治性和獨立性。
3.6 網絡梳理
對應用容器化后的網絡進行規(guī)劃是另一個重要工作。首先容器平臺本身分為管理集群master,計算集群slave以及包含其他日志、監(jiān)控、鏡像倉庫等系統(tǒng)服務的集群??梢詫⒐芾砑?、日志、監(jiān)控等劃入管理IP網段,將計算集群劃入業(yè)務IP網段,并且對每臺主機上安裝的組件進行端口規(guī)劃。
另外,需要根據(jù)應用的特性,進行網絡模式選擇。例如無狀態(tài)的分布式應用,可以在容器部署時使用bridge模式。需要指定端口的應用,或者對網絡性能要求高的應用,更適合使用host網絡模式,但使用host模式時,需要進行網絡端口資源規(guī)劃,同樣的應用實例只能在一臺主機上部署一個,避免端口沖突。
4 云原生應用平臺展望
云原生應用,專門為在云平臺部署和運行而設計的應用。通過容器化、容器的動態(tài)編排和微服務來統(tǒng)一管理應用,實現(xiàn)資源的統(tǒng)一納管、集群的自動化部署、多租戶鏡像倉庫和應用商店一鍵式部署,整個平臺滿足應用運行所需的資源、部署、管理等各個環(huán)節(jié),真正可實現(xiàn)應用自動化管理,帶來應用開發(fā)的新時代。
[參考文獻]
[1]BALALAIE A,HEYDARNOORI A,JAMSHIDI P.Microservices architecture enables devops: migration to a cloud-native architecture[J].IEEE Software,2016(3):42-52.
[2]BALALAIE A,HEYDARNOORI A,JAMSHIDI P.Migrating to cloud-native architectures using microservices: an experience report[C].Taormina:European Conference on Service-Oriented and Cloud Computing,2015:201-215.
[3]BREWER E A.Kubernetes and the path to cloud native[C].New York:Proceedings of the Sixth ACM Symposium on Cloud Computing,2015:167.
[4]ROUSSEV V,MCCULLEY S.Forensic analysis of cloud-native artifacts[J].Digital Investigation,2016(16):104-113.
[5]TOFFETTI G,BRUNNER S,BL?CHLINGER M,et al.Self-managing cloud-native applications: design,implementation,and experience[J]. Future Generation Computer Systems,2017(72):165-179.