大數據應用:知乎容器平台演進及與大數據融合實踐

在“開源與容器技術”分論壇上,來自知乎的計算平臺負責人張阜興發表了題為“知乎容器平臺演進及與大數據融合實踐”的精彩演講。成都加米穀教育轉自網絡,僅供參考學習。

張阜興,知乎計算平臺負責人。2012 年從中科院計算所畢業後,分別在搜狐和雅虎從事分佈式存儲系統研發和雲平臺建設的工作,加入知乎後從無到有推動了知乎內部容器平臺的建設,目前主要研究方向在資源調度管理以及大數據計算和存儲等。

本文將按照如下三個部分展開討論:

• 知乎容器平臺的演進歷程

• 容器平臺維護踩過的坑

• 容器與大數據的融合實踐


知乎容器平臺的演進歷程

大數據應用:知乎容器平臺演進及與大數據融合實踐

知乎容器平臺的演進歷程大致可以分成三個階段:

• 2015 年 9 月,我們的容器平臺正式在生產環境中上線應用。

• 到了 2016 年 5 月,我們已經將 90% 的業務遷移到了容器平臺之上。

• 如今,除了業務容器之外,包括 HBase、Kafka 等多個基礎組件都已遷至容器平臺。

總的節點數達到了 2 千多個,而容器數則達到了 3 萬多個。可以說知乎基本已經 All in 容器平臺之上。

在容器平臺整體演進的過程中,我們總結了五個要點:

• 從 Mesos 到 Kubernetes 的技術選型變化。

• 從單集群到多集群混合雲的架構調整。

• 從滾動部署到部署與發佈相分離的使用優化。

• 在容器使用上,從無狀態到有狀態,引入持久化的存儲。

• 在容器網絡上,從 NAT 轉換成 Underlay IP 模式。


從 Mesos 到 Kubernetes

大數據應用:知乎容器平臺演進及與大數據融合實踐

早在 2015 年,我們就已經開始在生產環境中使用容器平臺了。由於那時 Kubernetes 剛被髮布,且不成熟,因此我們當時選用的是 Mesos 技術方案。

Mesos 的優勢如下:

• 非常穩定。

• 在架構設計中,由於大部分狀態是由 Mesos 的 Slave 向 Master 去彙報,因此 Master 的負載較輕。

• 單集群所能容納的容器規模較大(官方稱:單個集群可容納 5000 個節點)。

Mesos 的劣勢:由於是單獨開發一套 Framework,因此開發的成本較高。我們最開始採用的就是自研 Framework。

Kubernetes 的優勢如下:

• 有強大的社區支持。

• 功能較為完善,包含有 Pods、Deployment 等概念。

• 由於功能完善,接入使用成本較低。

Kubernetes 的劣勢:由於它將所有的狀態都放入 Etcd 中進行存儲,因此單集群的規模沒有 Mesos 那麼大。官方稱:在將 Etcd 升級到 V3 版本之後,才能達到 5000 個節點。

在運行之初,我們使用的是一些簡單的無狀態容器。後來隨著 Proxy、Kafka 等基礎組件的引入,針對每一套組件都需要開發一套 Framework 的接入成本太高。

因此在後續的實踐過程中,我們直接採用了 Kubernetes,通過資源調度層,統一進行資源的調度和管理。


從單集群到混合雲

大數據應用:知乎容器平臺演進及與大數據融合實踐

在生產環境中,我們有著如下實際需求:

• 對於 Mesos 或 Kubernetes 的任意參數變更,都需要在灰度集群上去先進行驗證。只有驗證通過之後,才能大規模地部署到生產環境之中。

因此,我們需要有一個線上與線下相似的環境,它們的區別僅在於測試的集群規模略小於實際運行的集群。

• 對於 Kubernetes 的單個集群來說,容量是有限的,所以需要通過實施多集群方案來對容量進行水平擴展。

• 可容忍單集群級別的故障。

• 需要採用混合雲的架構。由於公有云的集群池比較大,它既能夠大幅提升彈性資源池的容量,又能夠抵禦突發的擴容需求。

計費模式較為靈活,可按需計費,並“廉價”地實現一些臨時性的活動所帶來的計算資源的消耗。

大數據應用:知乎容器平臺演進及與大數據融合實踐

在混合雲架構的實現過程中,我們曾調研過 Kubernetes 的 Federation 方案,但是發現它存在如下兩點不足:

• 由於尚不成熟,目前官方並不推薦運行在生產環境之中。

• 組件過多,在部署和管理上較為繁瑣。

因此我們採用了自行研發的管理方案,其特點是:

• 每一組業務容器都會同時在多個集群上創建 Deployment。

• 這些 Deployment 的配置,包括:容器版本、CPU / 內存資源的配額,都是完全相同的,唯一不同的只是容器的數量,它們會根據不同的集群大小做出相應的調整。


從滾動部署到部署發佈分離

大數據應用:知乎容器平臺演進及與大數據融合實踐

我們優化了部署與發佈的流程,從原先的滾動部署模式轉換成了部署與發佈相分離的模式。

在此,我們來區分一下部署與發佈這兩個概念:

• 部署,是分發代碼的配置,啟動諸如 Web Service 進程之類的服務實例。

• 發佈,是指把一組服務實例註冊到負載均衡、或者其他流量分發系統上,使其能夠對外接收流量。

如上圖下方的流程所示,上線的基本流程為:內網流量測試→金絲雀流量測試→生產環境全量。

那麼在每一個階段,我們都需要去觀察線上業務的指標,一旦出現異常,我們就需要及時地進行回滾操作。

大數據應用:知乎容器平臺演進及與大數據融合實踐

我們來深入分析一下滾動部署方式的優缺點。

優點如下:

• 每次先升級一部分的容器實例,然後再迭代運行。

• 能夠保證在升級過程中服務的不中斷,而瞬時產生的最大資源消耗是受限制的。

缺點如下:

• 在滾動部署的過程中,我們無法做到:先部署 10%→停下來→再部署 20%→再停下來→接著部署 50%,因此無法靈活地控制進度,也不能對應到前面所提到的各個發佈階段。

• 如果每個發佈的階段都採用獨立的滾動部署方式,那麼整體部署速度將會比較緩慢。

• 在滾動部署過程中,舊的容器實例會被立刻銷燬。一旦此時線上指標出現問題,而我們的觀察卻有所滯後,那麼所涉及到的“銷燬新實例和啟動舊實例”,回滾速度會比較緩慢。

大數據應用:知乎容器平臺演進及與大數據融合實踐

針對上述問題,我們在設計上採用了“部署與發佈相分離”的模式。

例如:我們在上線時,先在後臺啟動一組新的業務容器實例,當容器實例達到並滿足了內網發佈的數量要求時,我們就把它註冊到內網之中,然後將舊的實例從內網流量分發的系統中“反註冊掉”。

如此,新的實例就能夠在內網中被髮布與驗證。在後臺繼續啟動新的容器實例的同時,也避免了用戶能感知到容器啟動實例的時間。

我們實現了內部用戶在驗證完畢的時刻,下一個階段的部署就在數秒內直接升級完畢了。

另外,由於我們舊的容器實例並非立刻被銷燬掉,而是要等到在生產環境發佈完成的一段安全時期之後,再按照類似於金絲雀的策略將舊的一組容器完全銷燬掉。

因此,在金絲雀發佈的過程中,如果線上出現任何問題,我們就能夠立刻把舊的實例重新註冊回來,以實現秒級回滾。


從無狀態到有狀態

大數據應用:知乎容器平臺演進及與大數據融合實踐

在容器的使用模式上,我們最初部署的是一些無狀態的業務 Web 容器。但是隨著其他基礎組件被遷移到了該容器平臺之上,我們引入了持久化存儲,以提供服務支持。

因此在生產環境中,我們用到了如下典型的持久化存儲方式:

• HostPath。主要是配合 DaemonSet 進行使用。因為 HostPath 本身就能夠保證在每一個 Node 上只啟動一個 Pod 實例,因此不出現多個 Pod 同時使用同一個 HostPath,進而導致產生路徑衝突的問題。

例如,我們讓 Consul Agent 採用 DaemonSet 部署,那麼由於 Consul Service 在註冊的時候需要持久化到本地存儲目錄之中,因此就很適合於用這種方式去實現。

• Local。最新版的 Kubernetes 已經能夠支持 Local Volume 了。優勢在於:因為使用的是本地的磁盤,它相對於網絡存儲有著較高的 IOPS,且延時較低。

所以對於諸如 MySQL 和 Kafka 之類的有著高 IOPS、低延時的存儲類應用來說,是非常合適的。

• NFS。我們通過將分佈式文件系統的 Fuse 接口映射到容器之中,以保證業務能夠從分佈式文件系統上去讀取各種數據文件。


從 NAT 到 Underlay IP

大數據應用:知乎容器平臺演進及與大數據融合實踐

在容器網絡的模式上,我們最早採用的是 iptable 所實現的 NAT 模式。該模式實現起來較為方便,不需要對現有網絡予以調整。

但是它存在一定的性能損耗問題,這對於我們早期的那些業務容器來說尚可接受。

到了後期,需要將一些大流量的高速網絡應用,如 Ngix、Haproxy 放到容器裡時,我們對這種性能開銷就無法容忍了。

因此我們結合自身機房的網絡實際,在 Kubernetes 方案上選用了 Underlay IP,這種簡單互聯的網絡模式,以保證容器的 IP 與所在物理機的 IP 是完全對等的。

由於不存在 Overlay 的封包 / 解包處理,因此性能幾乎沒有損耗。通過實測,我們覺得性能非常好,所以將各種大流量的分發應用都放在了此容器裡。

另外,由於 IP 模式具有良好的業務對應關係,因此我們可以方便地去定位網絡連接的來源和故障。

例如:倘若在 MySQL 側發現有大量的連接產生,你將如何定位這些連接的來源呢?

按照原有的端口映射方式,你可能只能定位到是來自於某臺機器,但是往往一臺機器上會被部署了多個業務應用,因此也就沒法精確地定位到是由哪個業務方所導致的。

如今,採用了 IP 方式之後,你就可以很方便地根據 IP 地址來判定對應的是哪個業務容器了。

同時,在具體的實踐過程中,我們還給每一臺機器分配了一個固定的網段(如一個 C 類網段),然後通過 Kubelet 的 CNI 插件,即 APAM,來負責每臺機器 IP 地址的創建、分配和釋放。


容器平臺維護踩過的坑

由於我們在生產環境中大規模地使用了容器平臺,可見容器平臺已經成為了我們基礎組件中的基礎組件。

那麼它一旦出現問題,將會對我們的生產環境造成重大的故障。下面給大家分享一些我們曾經在生產環境中踩過的坑。


K8S Events

大數據應用:知乎容器平臺演進及與大數據融合實踐

一次半夜三更,我們的 API Server 突然全部無法訪問了。通過調查,我們發現原因就在於 K8S Events。

眾所周知,K8S Events 就像 Log 一樣記錄著 K8S 集群裡發生的任何變更事件。

如果你沒有進行額外配置的話,它會根據默認模式將這些變化全部記錄到線上的同一個 Etcd 裡。

同時,K8S 為這些 Events 配置了相應的過期策略 TTL,以保證在經過一段時間後,該 Events 會被自動回收掉,從而釋放 Etcd 的存儲空間。

該設計看似合理,但是在 Etcd 實現 TTL 時,卻採用的是遍歷的方式,因此實現效率比較低下。

隨著集群規模的逐漸變大,集群上會出現頻繁的發佈、部署與變更,這就會導致 Etcd 的負載逐漸增大,直至最終造成 Etcd 無法再選舉出一個 Leader,而整個 K8S 集群就此崩潰。

針對上述事故,其實 K8S 也意識到了,它為我們提供了一項可以將 Events 記錄到某個單獨 Etcd 集群中的配置。

不過,針對該單獨的 Etcd 集群,我們是不需要進行高可用存儲的,因此我們就直接使用了單節點的 Etcd,而並沒有採用 Raft 方式去組建具有更好性能的集群。

另一方面,我們意識到 K8S 所給定的諸如“每隔三個小時就回收掉 Events”的 TTL 機制過於精確。

因此我們自行實現了一種過期清理策略,即:固定在每天晚低峰的時候,再將整個 Events 的 Etcd 集群清空。


K8S Eviction

大數據應用:知乎容器平臺演進及與大數據融合實踐

除了上面提到的“由於 API Server不響應,所導致的整個 K8S 集群失控”故障,我們也碰到過“所有生產環境中的 Pods 全部給直接刪掉”的坑。

在所有 API Server 都“掛掉”的極端情況下,如果你沒有及時去處理,並超過了一段時間(如五分鐘),那麼在 K8S 1.5 之前的版本中,Controller Manager 會認為這些集群的 Node 都已與之失聯,並開始進行 Eviction。

即:將這些不健康 Node 上的所有 Pods 全都 terminate 掉了。此時,如果你恢復了 API Server,那麼所有的 Kubelet 會根據命令,將運行在自己上面的 Pods 全部刪掉。

當然,在 K8S 1.5 之後的官方版本中,已經增加了一項“-unhealthy-zone-threshold”的配置。

例如:一旦它發現有超過 30% 的 Node 處於失聯狀態,就會認為該大規模故障必有其他原因,因此禁用且不再執行 Controller Manager 激進的驅逐(Eviction)策略。


Docker 容器端口洩露

大數據應用:知乎容器平臺演進及與大數據融合實踐

另外我們也曾經在生產環境中發現“port is already allocated(端口已經被使用)”的現象。

我們檢查後發現:容器雖然已經釋放了端口,但是它的 Proxy 還在佔用該端口。

通過進一步檢查 Docker Daemon 的代碼,我們得知:Docker Daemon 從分配使用某個端口,直到將該端口記錄到自己的內部持久化存儲中,該過程並非“原子性”。

如果 Docker Daemon 在中間階段退出,那麼它在重啟恢復的內部存儲過程中,會忽略掉已經分配的端口,從而導致了容器端口的洩露。

針對該問題,我們已向官方提交了帶有對應解決方案的 Issue。


TCP Connection Reset

大數據應用:知乎容器平臺演進及與大數據融合實踐

我們在 Docker NAT 網絡模式下也遇到過 TCP Connection Reset 的問題。

如上圖所示,該系統默認的配置對於網絡數據包可能出現的亂序情況過於敏感和嚴格。

在我們的系統訪問公網的過程中,如果網絡環境較差,且出現的亂序包超過了 TCP 窗口,那麼系統就會根據該配置直接將這些連接進行 Reset。因此,我們直接將其關閉掉,就可以解決此問題了。

下面介紹一些我們在容器技術與大數據應用融合方面所做過的嘗試與實踐。


容器與大數據的融合實踐

基於 Kubernetes 的大數據融合

大數據應用:知乎容器平臺演進及與大數據融合實踐

在大數據的場景下,我們使用兩條處理路徑,實現了容器平臺和大數據組件的融合。如上圖所示,左邊綠色的是實時處理,右邊灰色的是批處理。

由於出發點的不同,這些組件的設計思想有著較大的差異:

批處理,主要是運行 ETL 任務,包括數據倉庫的構建、離線分析等,因此它追求的是數據吞吐率和資源利用率,而對於時延本身並不敏感。

例如:一個 Map-Reduce 任務需要運行 1~2 個小時,這是非常正常的。並且它被設計為具有高容錯性。

例如:某個 Map-Reduce 任務“掛掉”了,你完全可以通過上層的 Ozzie 或 Azkaban 對整個任務(job)進行重試。只要最終完成了重啟,這些對於上層業務都將是“無感”的。

實時處理,對於時延較為敏感,且對於組件的可用性也要求比較高。一旦其中的任何節點“掛掉”或重啟,都會導致數據“落地”(運營指標)的延遲,以及數據展示的失敗。因此它的組件要求機器的負載不能太高。

大數據應用:知乎容器平臺演進及與大數據融合實踐

當然,我們在對大數據生產環境的維護過程中,也經常遇到如下各種問題:

• 由於某個業務的變更,伴隨著 Kafka 寫入的流量出現猛增,也會拉高 Kafka 整個集群的負載。那麼如果無法恢復的話,就會導致集群的癱瘓,進而影響整個生產環境。

• 我們治理的思路是:按照業務方將集群予以劃分和隔離。

• 我們按照業務方將集群劃分出幾十套,那麼面對這麼多的集群所帶來的成本,又該如何統一進行配置與部署管理呢?

• 我們通過使用 K8S 模板,方便地實現了一鍵搭建出多種相同的運行環境。

由於每個業務方使用量的不同,會造成那些業務方使用量較小的應用,也需要被分配多臺機器,且需要維護該集群的高可用性,從而帶來了大量的資源浪費。

我們的解決方案是:運用容器來實現細粒度的資源分配和配置。例如:對於這些較小的業務,我們僅分配一個配有單 CPU、單磁盤和 8G 內存的容器,而不是一整臺物理機。


基於 Kubernetes 的 Kafka 集群平臺

大數據應用:知乎容器平臺演進及與大數據融合實踐

由於 Kafka 的性能瓶頸主要存在於磁盤存儲的 IOPS 上,我們通過如下的合理設計,實現了資源的分配管理。

具體方案是:以單塊磁盤為資源單位,進行細粒度分配,即:用單個 Broker 去調度一塊物理磁盤。

如此劃分資源的好處在於:

• 它本身就能對 IOPS 和磁盤容量予以隔離。

• 對於幾個 T 的硬盤而言,資源的劃分粒度較細,而不像物理機那樣動輒幾十個 T。因此資源的利用率會有所提升,而且更適合於小型應用。

• 我們利用 Kafka 自身的 Replica 實現了數據的高可用性。不過容器與物理機在具體實現策略上有所區別:原來我們將 Broker 部署到一臺機器之上,如今將 Broker 部署在一個容器裡。

• 此時容器就變成了原來的物理機,而包含容器的物理機就相當於原來物理機所在的物理機架。

• 同時,我們也對控制 Replica 副本的分佈策略進行了調整。我們把 Broker 的機架式感知,改成按機器予以處理,這樣就避免了出現相同 topic 的副本被放在同一臺機器上的 Broker 的情況。

• 採用了容器方式之後,故障的處理也變得相對簡單。

由於採取的是單塊硬盤的模式,因此一旦出現任何一塊硬盤的故障,運維人員只需將故障盤更換下來,通過 Kafka 的 Replication 方案,從他處將數據拷貝過來便可,而不需要其他部門人員的介入。

大數據應用:知乎容器平臺演進及與大數據融合實踐

在創建流程方面,由於當時 K8S 並不支持 LocalPV,因此我們採用了自定義的第三方資源接口,自己實現了類似於如今生產環境中 Local Volume 的機制。

其流程為:我們靜態地根據磁盤的資源創建 LocalPV,而在平臺創建 Kafka 集群時,動態地創建 LocalPVC。

此時調度器就可以根據其 LocalPVC 和現有的 LocalPV 資源去創建 RC,然後在對應的節點上去啟動 Broker。

當然,目前 K8S 已有了類似的實現方式,大家可以直接使用了。


容器與 HBase 融合

大數據應用:知乎容器平臺演進及與大數據融合實踐

我們的另一個實踐案例是將 HBase 平臺放到了容器之中。具體需求如下:

• 根據業務方去對 HBase 集群予以隔離。

• 由於 HBase 的讀寫都是發生在 Region Server 節點上,因此需要對 Region Server 予以限制。

• 由於存在著大、小業務方的不同,因此我們需要對資源利用率予以優化。

同時,由於數據都是被存放到 HDFS 上之後,再加載到內存之中,因此我們可以在內存裡通過 Cache 進行高性能的讀寫操作。

可見,Region Server 的性能瓶頸取決於 CPU 與內存的開銷。

大數據應用:知乎容器平臺演進及與大數據融合實踐

因此我們將每個 HBase Cluster 都放到了 Kubernetes 的 Namespace 裡,然後對 HBase Master 和 Region Server 都採用 Deployment 部署到容器中。

其中 Master 較為簡單,只需通過 Replication 來實現高可用性;而 Region Server 則針對大、小業務方進行了資源限制。

例如:我們給大的業務方分配了 8 核 + 64G 內存,而給小的業務方只分配 2 核 + 16G 內存。

另外由於 ZooKeeper 和 HDFS 的負載較小,如果直接放入容器的話,則會涉及到持久化存儲等複雜問題。

因此我們讓所有的 HBase 集群共享相同的 ZooKeeper 和 HDFS 集群,以減少手工維護 ZooKeeper 和 HDFS 集群的開銷。


容器與 Spark Streaming 融合

大數據應用:知乎容器平臺演進及與大數據融合實踐

不同於那些需要大量地讀寫 HDFS 磁盤的 Map-Reduce 任務,Spark Streaming 是一種長駐型的任務。

它在調度上,不需要去優化處理大數據在網絡傳輸中的開銷,也不需要對 HDFS 數據做 Locality。

然而,由於它被用來做實時處理計算,因此對機器的負載較為敏感。如果機器的負載太高,則會影響到它處理的“落地”時延。

而大數據處理集群的本身特點就是追求高吞吐率,因此我們需要將 Spark Streaming 從大數據處理的集群中隔離出來,然後將其放到在線業務的容器之中。

大數據應用:知乎容器平臺演進及與大數據融合實踐

在具體實踐上,由於當時尚無 Spark 2.3,因此我們自己動手將 YARN 的集群放到了容器之中。

即:首先在 Docker 裡啟動 YARN 的 Node Manager,將其註冊到 Resource Manager 之上,以組成一個在容器裡運行的 YARN 集群。

然後我們再通過 Spark Submit 提交一項 Spark Streaming 任務到該集群處,讓 Spark Streaming 的 Executor 能夠運行在該容器之中。

如今,Spark 2.3 之後的版本,都能支持對於 Kubernetes 調度器的原生使用,大家再也不必使用 YARN,而可以直接通過 Kubernetes 使得 Executor 運行在容器裡了。


大數據平臺的 DevOps 管理

大數據應用:知乎容器平臺演進及與大數據融合實踐

在大數據平臺的管理方面,我們踐行了 DevOps 的思想。例如:我們自行研發了一個 PaaS 平臺,以方便業務方直接在該平臺上自助式地對資源進行申請、創建、使用、擴容、及管理。

根據 DevOps 的思想,我們定位自己為工具開發的平臺方,而非日常操作的運維方。

我們都通過該 PaaS 平臺的交付,讓業務方能夠自行創建、重啟、擴容集群。

此舉的好處在於:

• 減少了溝通的成本,特別是在公司越來越大、業務方之間的溝通越來越複雜之時。

• 業務便捷且有保障,他們的任何擴容需求,都不需要聯繫我們,而直接可以在該平臺上獨立操作完成。

• 減輕了日常工作的負擔,我們能夠更加專注於技術本身,專注於如何將該平臺的底層技術做得更好。

大數據應用:知乎容器平臺演進及與大數據融合實踐

由於業務本身對於像 Kafka、HBase 之類系統的理解較為膚淺,因此我們需要將自己積累的對於集群的理解和經驗,以一種專家的視角呈現給他們。

作為 DevOps 實踐中的一環,我們在該大數據平臺上提供了豐富的監控指標。

圖中以 Kafka 為例,我們提供的監控指標包括 Topic Level、Broker Level,和 Host Level。

可見,我們旨在將 Kafka 集群變成一個“白盒”,一旦發生故障,業務方就能直接通過我們所定製的報警閾值,在指標界面上清晰地看到各種異常,並能及時自行處理。


總結

從實踐經驗來看,我們的基本思路是:

• 按業務方進行集群隔離。

• 利用 K8S 進行多集群部署和管理。

• 利用 Docker 進行資源隔離和監控。

• 利用 Docker 實現更細粒度資源分配。

• 運用 DevOps 實現運維管理。

大數據應用:知乎容器平臺演進及與大數據融合實踐

後續,我們將嘗試更多的基礎設施組件,利用 K8S 去實現集群的隔離,實現更細粒度的資源分配和進程級的資源監控。

通過更好地在生產環境中實施管理和維護,以及提升資源的利用率,我們將為業務提供更穩定的 PaaS 平臺服務,並最終實現數據中心的資源統一。

同時,我們通過交給 K8S 來進行調度管理,進而實現 DCOS(數據中心操作系統)。成都加米穀教育,專注於大數據人才培養,9月下旬

數據分析與挖掘培訓班新課正在火熱諮詢報名中,大數據開發新課諮詢中,活動好禮可疊加使用!詳情見加米穀大數據微頭條!


分享到:


相關文章: