李道兵:京東雲的雲原生理念及Serverless最佳實踐

在雲原生技術全面爆發之前,我們開發的應用可以被稱爲非雲原生應用,非雲原生應用並沒有考慮到應用的彈性和規模性,甚至很多都不具備擴展性,當業務規模擴大時,特別依賴硬件的升級,進而帶來了很多問題。雲原生的出現帶來了新的開發方式,然而這一技術處於快速的發展過程中,導致很難定義清楚各類概念和理解各種技術名詞,本文采訪了京東雲中間件團隊負責人李道兵,瞭解京東雲在雲原生領域的理念和相關探索,以期對開發者有所幫助。

如今,企業很難在聊雲原生這個話題時避開容器,但是往回倒四年,容器在國內的應用並不普遍,大多集中在技術實力較強的互聯網大廠,但也並非後來大火的Docker,當時的不少文章還將這羣早期實踐者稱作“敢於吃螃蟹的人”。顯然,在雲原生領域,容器的發展是推動其落地的重要條件,但最大的需求並不是爲了使用容器,這個邏輯本身就很奇怪,爲了出現而出現的技術往往不會有好的結局,容器所解決的問題纔是組織或開發者最大的需求。那麼,組織現階段對雲原生實踐最大的需求是什麼呢?

過去幾個月,InfoQ 先後就雲原生這一話題採訪了阿里巴巴騰訊青雲居然之家、華爲等衆多廠商,對值得關注的開源技術及相關落地實踐進行了初步探索。本文,InfoQ 對京東雲中間件產品研發部高級總監李道兵進行了獨家專訪,瞭解京東雲在雲原生領域的理念和相關探索。

雲原生理念

關於雲原生,其實每篇相關文章都會特意留出一部分講解企業的理念,也多次提到了Pivotal 公司的 Matt Stine 寫的一本叫做遷移到雲原生應用架構的小冊子以及CNCF在今年KubeCon上海站提出的定義(V1.0):

雲原生技術有利於各組織在公有云、私有云和混合雲等新型動態環境中,構建和運行可彈性擴展的應用。雲原生的代表技術包括容器、服務網格、微服務、不可變基礎設施和聲明式 API。

但是,正如李道兵在接受採訪時所言:“與其說雲原生涉及了衆多理念,不如說現在社區還沒有找到最佳實踐應該是什麼樣子。”正因如此,每篇文章都會花費一些篇幅介紹本文所討論的雲原生理念的範圍。

相比於“雲原生”這個名字的誕生,李道兵認爲這一概念的出現可以追溯到更早之前。

2008年,通過將 cgroups 的資源管理能力和 Linux Namespace 的視圖隔離能力組合在一起,LXC(Linux Container)這樣的完整的容器技術出現在了 Linux 內核當中。當然,在這之前的虛擬機的概念此處就不贅述了,李道兵介紹道,LXC比虛擬機輕量很多,但可以達到大部分虛擬機的效果,隔離性和安全性卻不夠好。

在這之後,Docker項目的正式發佈是對雲原生領域產生深遠影響的重要事件。李道兵補充道,Docker真正的成功在於Docker Hub,也就是官方維護的公共倉庫,其內存儲了大量鏡像。其次就是構建鏡像的方法,Docker構造鏡像的方法比其他的簡單很多,也能更輕鬆地利用其他人的已有成果。總之,Docker的出現大幅降低了微服務的運維負擔,讓微服務能真正成爲一個能大面積推廣的技術。微服務實施在服務拆分之後,就會開始出現服務治理的需求,包括服務發現、服務伸縮、日誌收集、問題定位等,隨即就出現了很多類似Mesos、Kubernetes的技術,做服務的方式由原來的用Java寫完後跑在Tomcat上演變成將服務部署在容器之上,再利用Kubernetes進行管理,開發者已經不需要操心服務器的事情,這一系列由此產生的新理念可以稱之爲“Cloud Native(雲原生)”。

不難看出,容器是雲原生得以落地的重要條件,但這背後的真正訴求則是開發者對服務治理和去運維化的需求,可以認爲在雲原生時代,系統運維這個角色可能完全消失掉,因爲不需要操心服務器,自然就無運維,容器鏡像可以直接將一個應用運行所需的完整環境,即:整個操作系統的文件系統全部打包進去,這纔是容器得以大面積普及的原因。換句話說,這樣的服務交付方式纔是開發者的真正訴求。

雲原生最佳實踐

正如開篇所言,現在談到雲原生實踐很難避開容器這個話題,同樣也很難避開Kubernetes(k8s),這就好像曾經的Hadoop是大數據領域的事實標準一樣,但Kuberntes的複雜性也是有目共睹的,李道兵表示:“我承認Kubernetes底層體系的重要性,但它的接口真的不夠簡單。相比較而言,早些年穀歌推出的Google App Engine反而是對未來很好的示範,但很可惜,由於種種原因(當時雲的概念還沒有起來、在 AppEngine 寫一個有狀態服務非常困難、對AppEngine的性能分析和優化困難等),Google App Engine並沒有獲得很好的反響。但就這個層面來講,未來,我們應該可以得到比Kubernetes友好得多的界面。”

既然如此,爲什麼Kubernetes頂着“複雜性”的帽子還可以發展得如此迅速呢?李道兵認爲首先底層的複雜性是不可避免的,我們只能在上層通過合適的抽象來簡化使用界面。其次過去幾年採用 k8s 大都是技術好的團隊,他們能駕馭這種複雜性,同時還能從底層的靈活性中獲益。但最近幾年隨着 k8s 的更廣泛採用,這個問題就愈發嚴重了,也有很多項目在嘗試解決這個問題。

那麼 k8s 是否會被新的框架取代呢?李道兵認爲這個問題可以類比爲編程語言來看待,比如“Java就足夠好到把所有編程語言都比下去嗎?”這也未必,當年,Java確實好到足以淘汰COBOL(現在依舊有一些企業在使用),但一旦Java被大面積採用,你淘汰Java就需要一個比Java好一個數量級的語言。所以儘管出現了一些針對Java作出改進的語言,比如 groovy, scala等,但仍然無法撬動Java在企業市場的佔有率,畢竟對於整個IT業界,做出決定更換編程語言是要耗費很多成本的。同理,Kubernetes還是有非常多優點的,並且已被廣泛採納,所以要被取代其實很難。

如今,在Kubernetes上進行探索的大部分企業以技術見長的互聯網大廠爲主,這些企業有動力也有能力選擇Kubernetes,因爲搞得定。但是,爲了面向更加廣泛的用戶,Kubernetes 社區一直沒有停止在這個領域的持續探索,並已經取得一些關鍵性突破。因此,雲原生領域的核心技術其實是處在不斷的發展和變化之中,現在很難對最佳實踐給出定論。

京東雲的雲原生實踐

京東雲雖然是一個雲服務的提供者,但其內部也需要進行雲原生改造,比如京東雲提供的對象存儲服務,其下的數十個組件同樣有服務治理的需求。因此,京東雲在這個過程中有很多Service Mesh相關實踐,主要是通過Service Mesh的sidecar將原本需要寫在代碼中的邏輯替換掉,而微服務改造和容器化可以認爲在此之前已經陸續完成(如果對這部分感興趣,可以閱讀《專訪京東雲:願雲原生不再只有 Kubernetes》,本文不作爲重點介紹)。

在Service Mesh方面,目前比較有代表性的開源工具就是Istio。

如上圖,Istio 的核心組件主要包括 Proxy 代理、Mixer 混合器、Pilot 引導、Citadel 堡壘和 Galley。其中,Proxy 代理的代理組件主要是 Envoy,用來攔截所有想攔截的流量;Mixer 混合器混合了各種策略以及後端數據採集或遙測系統的適配器,實現了前端 Proxy 與後端系統的隔離與匯合;Pilot 引導提供了一系列 rules api,允許運維人員指定一系列高級的流量管理規則;Citadel 堡壘管理着集羣的密鑰和證書,是集羣的安全部門;Galley 主要是用來驗證用戶編寫的 Istio api 配置。

目前來看,Istio並沒有太大的問題,但李道兵表示,Envoy 可能成爲 Istio 發展的阻礙,Envoy本身是用C++編寫的,主要由核心團隊維護,社區參與度一般。Envoy 支持了多種調用機制,但仍然不能滿足部分工業界的需求(比如 Backup Request), 而 Envoy 的複雜性又限制了使用者自行擴展,不排除未來 Envoy 會被更靈活的 sidecar 組件替代掉。

除此之外,過去一段時間,京東雲在Serverless層面進行了大量實踐,這也是京東雲整體改造中非常重要的一個環節。

Serverless實踐

2019 年,Serverless 被 Gartner 稱爲最有潛力的雲計算技術發展方向,並被賦予是必然性的發展趨勢。Serverless 從底層開始變革計算資源的形態,爲軟件架構設計與應用服務部署帶來了新的設計思路。在行業內,對Serverless的解讀並沒有公認的準確定義,京東雲認爲Serverless技術目前有三種實現:

  • 真正的無服務器,就是所謂的函數計算FaaS;
  • 類似京東雲的原生容器,容器直接呈現給用戶,並且背後不需要有虛擬機來支持;
  • 應用比較廣泛的無服務器,背後虛擬機由雲廠商來提供,但是對用戶不可見,仍然是以虛擬機的方式來提供容器。

目前,京東雲在Serverless還在開發中,完整的Serverless實踐需要包括如下幾個模塊:

  • 負責提供計算能力的 FaaS
  • 負責提供通信能力的 Queue Service 和 Notification Service
  • 負責提供持久化能力的 Serverless KV 和 Object Storage
  • 負責提供入口的 API Gateway
  • 負責提供編排能力的 Step Function

京東雲已經提供了 FaaS, Queue Service, Object Storage 和 API Gateway, 其他模塊也會在近期陸續發佈。

FaaS

在FaaS層面,京東雲和 AWS 的 Lambda 以及 Azure 的 Function 類似,都是需要用戶提供一段代碼,這段代碼以 HTTP 的入口形式可以訪問。代碼可以用 Java 等多種語言寫出,處理完用戶請求後給出一定的反饋,整體代碼的生存週期就是請求的處理過程。代碼是由函數計算來提供包括 CPU、內存、語言平臺等運行環境,用戶完全不用關心代碼運行在什麼地方。

當併發請求非常多時,平臺就會運行這段代碼容器的多個副本,這樣就能做到:用戶無需預留計算資源,僅僅根據調用的時長、次數來付費。這種情況是目前爲止計算資源能做到的最小化分配粒度。粒度越小時,越有可能填滿服務器的計算能力,粒度越大,後期就可能有越多的計算能力被閒置。

李道兵表示,FaaS的優勢和劣勢都很明顯,主要優勢包括:徹底的無運維、近乎無限的伸縮能力、和零啓動成本。劣勢則包括:冷啓動比較慢,相對常規服務延時較高、壓力穩定時沒有成本優勢。不過這些劣勢並不是 FaaS 的本質造成的,而是可以解決掉的問題,在解決掉這些問題之後,FaaS就能獲得更大的適用範圍和更遠大的前景。

現階段,FaaS比較適合的應用場景主要有兩類:一是事件驅動型應用,比如IoT、網頁遊戲等類型;二是實驗性項目,這類項目租用虛擬機的成本比較高,而FaaS幾乎是零成本,不調用的情況下不會產生開銷。目前還有一個趨勢是大家在逐步用FaaS取代 AppEngine。京東雲目前將FaaS應用在多媒體內容分析處理和Serverless後端服務兩個場景:

  • 通過對象存儲上傳事件可以觸發多個函數,完成實時圖片或文件篩選、轉存、創建縮略圖、轉換視頻編碼等處理分析。通過事件觸發機制,您能夠快速部署複雜的應用與服務,構建一個彈性、可靠的後端系統。
  • 通過函數服務和API網關構建後端,以驗證和處理 API 請求。採用函數服務構建可靈活拓展架構,輕鬆創造豐富、個性化的應用程序體驗。

如上,京東雲目前的FaaS主要支持Python 2&3和Nodejs 6&8,這兩者是目前FaaS適用場景中使用較多的語言,而接下來也會陸續支持Java和PHP等編程語言,畢竟幾行代碼就可以處理的事件通常開發者更願意用Python而不是Java。籠統地說,可以通過K8s和Docker來實現的服務,也可以選擇用FaaS實現,但要認清楚FaaS的優劣。李道兵表示,FaaS的優勢是啓動零成本和極度彈性(幾乎無限伸縮),劣勢則是冷啓動、延時和大規模場景下的性價比較低等問題比較突出。其中,冷啓動也是業界目前在共同努力解決的問題,這個概念很好理解,就是指函數第一次調用時平臺部署函數實例的過程。

在本地調用函數時,響應基本是實時的,而云上的FaaS需要部署計算環境,這個過程的時間從數百毫秒到數秒不等,難於應對時延敏感型應用;此外,FaaS的優勢是極度彈性伸縮,這讓其在調用量下降時會進行資源回收清理,下次調用時則又需要冷啓動,這個過程一直反覆存在於服務的整個生命週期中。

李道兵表示,京東雲在這方面進行了不少嘗試,主要可以分爲兩部分:一是加快原生容器(下文將介紹這一概念)和雲硬盤的啓動速度,甚至說在雲硬盤加載之前先按需加載數據;二是預留部分實例,需要的時候再啓動,不過這未必適合所有場景,當FaaS運行在客戶的VPC中時,使用的是VPC中的資源,第二種方案暫時並不適用。

目前,業界也有一些方案,比如kata、Firecracker對qemu,虛擬機鏡像做裁剪來加速虛擬機的創建和啓動,但是效果並沒有那麼好。李道兵表示,虛擬機啓動慢的問題並不是第一天出現,因此沒有那麼好解決,而容器的問題則是安全性不夠高,如果容器足夠安全,也不需要造虛擬機了,直接物理機上運行可以節省不少時間,而原生容器算是平衡各種利弊後的一個不錯的嘗試。

隊列服務

根據瞭解,京東雲的隊列服務(Queue Service)是一項基於Serverless架構的全託管消息隊列服務,它可以提供高可靠並且幾乎無限擴展的託管消息隊列。

如上圖是隊列服務的架構圖,主要分爲底層分佈式存儲、功能及解決方案、安全管理及用戶接入四層,其特點是毫秒級自動伸縮和無規格限制。在消息類型上,標準隊列理論上無限制的TPS上限,最大努力的消息排序以及至少一次消息傳達;FIFO隊列保證消息的傳達順序與消息發送順序一致以及精確的一次性處理。主要的應用場景是如下兩種:

  • 異步解耦,削峯填谷。上下游系統處理能力存在差距的時候,利用隊列作爲數據的緩衝器,增加系統架構的可用性和可靠性,平滑處理峯值流量,解耦系統架構,避免對業務主流程的影響。
  • 性能擴展,容錯處理。由於隊列服務會解耦分離用戶應用的處理進程,因此對於有擴展需求的應用,可以輕鬆提高從隊列服務發送或接收速率來增加用戶應用的處理能力,對於部分故障的模塊可以從整個系統中摘除。

原生容器

原生容器與普通意義的容器還是有一些差別,通常容器會被認爲是在PaaS層,由PaaS團隊負責,而原生容器在京東雲內部屬於IaaS團隊,這也可以看出原生容器與底層的關聯比較密切。簡單來說,可以將原生容器理解爲普通容器和削薄後的虛擬機的結合體。

如上文所言,容器的安全性和隔離性是很大的問題,一旦容器被入侵,入侵者很容易通過穿透容器到達下面的物理機,從而影響整個雲平臺上的用戶,雖然這也是老生常談的問題,但要想既保證性能和啓動時間不受影響,又達到更高的安全級別,這本身就是一件棘手的事情,常規的安全手法成本又太高,最好的方式是將虛擬機隔離起來,通過這個彌補容器安全性上的不足,當容器被入侵時,入侵者不至於影響整個雲平臺的用戶。同時,原生容器對虛擬機做了大幅簡化,資源損耗和啓動時間均有所降低,這就是所謂的原生容器的概念。坦白地說,用戶申請的每一個原生容器裏面跑的就是一個Docker或者Pod。

在原生容器方面,京東的產品推出時 Kubernetes 還沒這麼流行。所以爲了實現節點容量的無限大,是通過一個叫 virtual kubelet 的插件讓 Kubernetes 集羣擁有一個虛擬節點。而如今,原生容器完全看用戶需求。如果是一次性的任務處理批量計算工作,這種方式非常有效,因爲虛擬節點可能會在某些方面不能實現 Kubernetes 所有的接口,某些特殊應用可能需要一定的適配工作,例如 daemonset。京東雲正在考慮把原生容器運行的節點暴露出來,並提供和現在 Kubernetes 所有接口兼容的一個應用。而在 Docker 方面,京東雲希望能向輕量化發展,可以隨時創建、隨時銷燬,並且可以隨時隨地創建更多的副本。

此外,京東雲也希望能將原生容器和 Kubernetes 通過比較緊密的方式結合在一起。比如在 Kubernetes 裏的 Kata Container,其在 Kubernetes 裏使用了更安全的容器;還有 Rancher Labs 基於 K8s 推出的輕量級的 Kubernetes 發行版 K3s,可以滿足在邊緣計算環境中運行在內存和處理能力受限的小型、易於管理的 Kubernetes 集羣日益增長的需求。

結束語

面向未來,京東雲的整體目標還是希望在雲原生領域有更多投入。李道兵表示,具體來說,在Service Mesh方面達到更好的透視遙感能力,如果是較大調用量的分析需要很好地分析服務之間的關係以及出現瓶頸和延遲的原因,甚至在開發者不需要增加代碼的情況下就可以享受這些功能。

在Serverless層面,需要進一步優化FaaS的冷啓動能力,大幅縮短啓動時間至毫秒級別,並儘可能降低延遲,因爲現在需要過的層和轉換的協議還比較多,這部分消耗的時間需要儘量減少,並增加更多語言支持,將界面簡化到接近當年Google App Engine的樣子。

作者簡介:

京東雲中間件產品研發部高級總監,先後在金山、盛大雲、七牛雲等公司工作,曾任盛大雲資深研究員,七牛雲SVP兼首席架構師等職位。作爲開源項目的愛好者,李道兵曾擔任Debian Developer、維基百科中文管理員,維護 iso-codes 等開源方面的工作。 關注服務安全、架構健壯性(高可用、可測試、可追溯)等領域,主導了多個高壓力項目,推崇高可用、可伸縮、低耦合的架構設計。目前,京東雲函數服務正在公測,點擊鏈接可以申請試用,想了解京東雲更多雲原生技術實踐可以關注京東雲開發者社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章