大數據

Flink 1.10 Container 環境實戰

作者 | 唐雲(茶幹),阿里巴巴高級開發工程師
整理 | 張壯壯(Flink 社區志願者)

摘要:本文根據 Apache Flink 系列直播整理而成,由阿里巴巴高級開發工程師唐雲(茶幹)分享。主要內容如下:

  1. 容器管理系統的演變
  2. Flink on K8S intro
  3. Flink on K8S實戰分享
  4. Demo

Tips:點擊下方可查看更多 1.10 系列直播視頻~

1.10系列直播:
https://ververica.cn/developers/flink-training-course-1-10/

本文第一部分將簡明扼要地介紹容器管理系統的演變;第二部分是 Flink on K8S 簡介,包括集群的部署模式調度原理等等;第三部分是我們這一年以來關於 Flink on K8S 的實戰經驗分享,介紹我們遇到的問題、踩過的坑;最後一部分是 Demo,將手把手演示集群部署、任務提交等等。

容器管理系統的演變

640 1.jpg

首先是以一個 Kubernetes 非內核開發人員的角度去探討其和 YARN 之間的關係。眾所周知,Apache Hadoop YARN 可能是在國內用途最廣的一個調度系統,主要原因在於 Hadoop HDFS 在國內或者是在整個大數據業界,是一個使用最廣泛的存儲系統。因此,基於其上的 YARN 也自然而然成為了一個廣為使用的一個調度系統,包括早期的 Hadoop MapReduce。隨著 YARN 2.0 之後 Framework 的開放,Spark on YARN 以及 Flink on YARN 也可以在 YARN 上進行調度。

當然 YARN 本身也存在一定的侷限性。

  • 如資源隔離,因為 YARN 是以 Java 為基礎開發的,所以它很多資源方面的隔離有一些受限。
  • 另外對 GPU 支持不夠,當然現在的 YARN 3.0 已經對 GPU 的調度和管理有一定支持,但之前版本對GPU 支持不是很好。

所以在 Apache 基金會之外,CNCF 基金會基於 Native Cloud 調度的 Kubernetes 出現了。

從開發人員角度來看,我認為 Kubernetes 是更像一個操作系統,可以做非常多的事情。當然這也意味著 Kubernetes 更復雜、學習曲線比較陡峭,你需要理解很多定義和概念。相比之下,YARN 主要管理資源調度部分,對整個操作系統而言,它體量要小很多。當然,不可置否,它也是一個大數據生態的先驅。接下來我會將焦點放在 Kubernetes 上面,探討從 YARN 的 Container 向 Kubernetes 的 Container(或者 POD)的演變過程中,我們總結的經驗和教訓。

Flink on K8S intro

部署集群

640 2.jpg

上圖展示了 Flink Standalone Session on K8S 上調度流程圖,藍色虛線框內是運行在 Kubernetes 集群內部組件,灰色框的是 Kubernetes 原生所提供的命令或組件,包括 kubectl 和 K8S Master。左側羅列了 Flink 官方文檔上提供的5個 yaml 文件,可以用來在 K8S 上部署最簡單的 Flink Standalone Session 集群。

啟動集群所需要執行的 kubectl 命令如下:

kubectl create -f flink-configuration-configmap.yaml
kubectl create -f jobmanager-service.yaml
kubectl create -f jobmanager-deployment.yaml
kubectl create -f taskmanager-deployment.yaml
  • 首先,它會向 K8S Master 申請創建 Flink ConfigMap,在 ConfigMap 中提供了 Flink 集群運行所需要的配置,如:flink-conf.yaml 和 log4j.properties;
  • 其次,創建 Flink JobManager 的 service,通過 service 來打通 TaskManager 和 JobManager之間的聯通性;
  • 然後,創建 Flink Jobmanager 的 Deployment,用來啟動 JobMaster,包含的組件有 Dispatcher 和 Resource manager。
  • 最後,創建 Flink TaskManager 的 Deployment,用來啟動 TaskManager,因為 Flink 官方 taskmanager-deployment.yaml 示例中指定了2個副本,所以圖中展示了2個 TM 節點。

另外,還有一個可選操作是創建 JobManager REST service,這樣用戶就可以通過REST service 來提交作業。

以上就是 Flink Standalone Session 集群的概念圖。

作業提交

下圖展示了使用 Flink client 向該 Standalone Session 集群提交作業的流程細節。

640 3.jpg

使用 Flink client 提交作業的命令是:

./bin/flink run -m : ./examples/streaming/WordCount.jar

其中 -m 所需的參數 public-node-IP 和 node-port 正是通過 jobmanager-service.yaml 所暴露 REST service 的 IP 和端口。執行該命令就可以向集群提交一個 Streaming WordCount 作業。此流程與 Flink Standalone 集群所運行的環境無關,無論是運行在 K8S 之上,還是運行在物理機之上,提交作業的流程是一致的。

Standalone Session on K8S 的優缺點:

  • 優點是無需修改 Flink 源碼,僅僅只需預先定義一些yaml 文件,集群就可以啟動,互相之間的通信完全不經過 K8S Master;
  • 缺點是資源需要預先申請無法動態調整,而 Flink on YARN 是可以在提交作業時聲明集群所需的 JM 和 TM 的資源。

因此社區在 Flink 1.10 進程中,也是我們阿里負責調度的同學,貢獻的整個 native 計算模式的Flink on K8S,也是我們過去一年在實戰中所總結出來的 Native Kubernetes。

640 4.jpg

它最大的區別就是當用戶通過 Flink client 提交作業時,整個集群的 JobMaster 通過 K8sResourceManager 向 K8S Master 動態申請資源去創建運行 TaskManager 的 POD,然後 TaskManager 再與 JobMaster 互相之間通信。有關 Native Kubernetes的細節請參考王陽所分享的《Running Flink on Kubernetes natively》。

總而言之,我們可以像使用 YARN 一樣的去使用 K8S,相關的配置項也儘量做到與 YARN 類似。不過為了方便講解,接下來我會使用 Standalone Session集群來展示,而下文介紹的部分功能,在 Flink 1.10 還未實現,預計在 Flink 1.11 完成。

Flink on K8S 實戰分享

日誌蒐集

當我們在 Flink on K8S 上運行一個作業,有一個功能性問題無法迴避,就是日誌。如果是運行在 YARN 上,YARN 會幫我們做這件事,例如在 Container 運行完成時,YARN 會把日誌收集起來傳到 HDFS,供後期查看。但是 K8S 並未提供日誌蒐集與存儲,所以我們可以有很多選擇去做日誌(收集、展示)的事情。尤其是當作業因為異常導致 POD 退出,POD 退出後日志會丟失,這將導致異常排查變得非常困難。

如果是 YARN,我們可以用命令 yarn logs -applicationId 來查看相關日誌。但是在 K8S 上怎麼辦?

目前我們比較常見的做法是使用 fluentd 來蒐集日誌,且已經在部分用戶生產環境有所應用。

640 5.png

fluentd 也是一個 CNCF 項目,通過配置一些規則,比如正則匹配,就可以將 logs 目錄下的.log 、.out 及 *.gc 日誌定期的上傳到 HDFS 或者是其他分佈存儲文件系統,以此來解決我們的日誌收集功能。這也意味著在整個 POD 的裡面,除了 TM 或 JM 之外,我們需要再啟動一個運行著 fluentd 進程的 Container(sidecar)。

當然,還有其他辦法,比如一個不需要再增加 Container 的方式:我們可以使用logback-elasticsearch-appender 將日誌發到 Elasticsearch。其實現原理是通過Elasticsearch REST API 支持的 scoket stream 方式,將日誌直接寫入Elasticsearch。

相比於之前的 fluentd 來說,優點是不需要另啟一個 Container 來專門收集日誌,缺點是無法蒐集非 log4j 日誌,比如 System.out、System.err 打印的日誌,尤其是作業發生 core dump,或者發生 crash 時,相關日誌會直接刷到System.out、System.err 裡面。從這個角度來看使用 logback-elasticsearch-appender 寫入 Elasticsearch 的方案也不是那麼完美了。相比之下,fluentd 可以自由地配置各式各樣的策略來蒐集所需要的日誌信息。

Metrics

日誌可以幫助我們觀察整個作業運行的情況,尤其是在出問題之後,幫助我們回溯場景,進行一些排查分析。另外一個老生常談也非常重要的問題就是 Metrics 和監控。業界已經有很多種監控系統解決方案,比如在阿里內部使用比較多的 Druid、開源InfluxDB 或者商用集群版 InfluxDB、CNCF 的 Prometheus 或者 Uber 開源的 M3 等等。

然後我們這裡直接拿 Prometheus 進行討論,因為 Prometheus 與 Kubernetes 均屬於 CNCF 項目,在指標採集領域具備先天優勢,從某種程度上來說Prometheus 是 Kubernetes 的一個標配監控採集系統。Prometheus 可以實現功能很多,不僅可以去做報警,也可以定一些規則做定期的多精度管理。

640 6.jpg

但是我們在實際生產中發現一個問題,Prometheus 的水平拓展支持不夠好。大家可以看到上圖右側部分,Prometheus 所謂的聯邦分佈式架構其實就是多層結構,一層套一層,然後它上面節點負責路由轉發去下一層查詢結果。很明顯,無論部署多少層,越往上的節點越容易成為性能瓶頸,而且整個集群的部署也很麻煩。從我們接觸到的用戶來說,在規模不是很大的時候,單點的 Prometheus 就可以承擔絕大部分的監控壓力,但是一旦用戶規模很大,比如幾百個節點的 Flink 集群,我們就會發現單點 Prometheus 會成了一個非常大的性能瓶頸,無法滿足監控需求。

我們怎麼做到呢?

640 7.jpg

我們首先對不同 Flink 作業的 metrics 做了一致性哈希,當然肯定不會是一個作業的metrics 只發了一個 Prometheus,而是面向作業裡面不同 scope 的 metrics,Flink的 metrics 力度從大到小分別是:

  • JobManager/TaskManager metrics
  • Job metrics(checkpoint次數、size和fail次數)
  • task metrics
  • operator metrics(每秒處理多少條record、receive的bytes數目)。

現在方案是先根據不同的 scope 去做一致性哈希,發到不同的 Prometheus 上,之後再配合 Thanos (滅霸,對就是在《復仇者聯盟3》裡面打完響指後去種瓜的農夫)。我個人理解 Thanos 是一個可以支持分佈式查詢 Prometheus 的增強組件。所以整個 Prometheus 架構,演變成單個 Prometheus 實例所在的 container 會搭載一個 Thanos sidecar。

當然整個架構會導致一些限制,這個限制也是我們做一致性哈希的原因,是因為當 Thanos 與 Prometheus 所搭配部署時,如果有一段 metrics數據,因為某些原因導致它既在 Prometheus A 裡面,也在 Prometheus B 裡面,那麼在 Thanos query 裡邊它會有一定規則,對數據進行 abandon 處理,即去掉一個以另外一個為準, 這會導致 UI 上 metrics 圖表的線是斷斷續續的,導致體驗很不友好,所以我們就需要一致性哈希,並通過 Thanos 去做分佈式查詢。

但是整個方案實際運行中還是有一些性能問題,為什麼 Prometheus 在很多業務級 metrics 上去表現其實很不錯,而在 Flink 或者是這種作業級別上,它表現的會有一些壓力呢?其實很重要的一個原因是作業 metrics 變化是非常急劇的。相比於監控HDFS、Hbase,這些組件的指標是有限的、維度也不高。我們用一個查詢場景來解釋維度的概念,例如說我們要查詢在某個 hosts 的某個 job 的某個 task 上所有的 taskmanager_job_task_buffers_outPoolUsage,這些所說的查詢條件,也就是用 tag 去做查詢過濾,那麼就有一個問題是 Flink 的 taskAttempId,這個是一個非常不友好的一個 tag,因為它是一個 uuid 且每當作業發生 failover 的時候,taskAttempId 就會發生變化。

如果作業不斷 failover,然後不停地持久化新的 tag 到 Prometheus,如果 Prometheus 後面接的 DB 需要對 tag 構建一個索引的話,那麼索引的壓力會非常大。例如 InfluxDB 的壓力就會非常大,可能會導致整個內存 CPU 不可用,這樣的結果非常可怕。所以,我們還需要藉助於社區在 report 這邊把一些高維度的 tag 過濾掉,有興趣的同學可以關注下 FLINK-15110。

性能

■ 網絡性能

我們先介紹 network 性能。無論你用 CNI 或者 Kubernetes 的網絡化插件,不可避免的會出現網絡性能損耗。比較常見的 flannel,在一些測試項目上會有百分之30左右的性能損耗。也不是很穩定,我們使用時發現作業經常會報PartitionNotFoundException: Partition xx@host not found,也就是下游無法獲取到上游的 Partition。

640 8.jpg

當然,你可以在 Flink 層去增大一些網絡容錯性,例如把 taskmanager.network.request-backoff.max 調到300秒,默認是10秒,然後把akka 的 timeout 調大一點。

還有一個讓我們特別頭疼的問題:

640 9.jpg

我們發現作業運行過程中經常遇到 Connection reset by peer 問題,原因是 Flink 在設計時,對網絡的穩定要求很高。因為要保證 Exactly once,如果數據傳輸失敗,那麼 Flink 就要 fail 整個 task 並重新啟動,然後我們會發現經常會出現令人頭疼的Connection reset by peer 問題,我們有幾個的解決方案方式:

  • 不要有異構網絡環境(儘量不要跨機房訪問)
  • 雲服務商的機器配置網卡多隊列 (將實例中的網絡中斷分散給不同的CPU處理,從而提升性能)
  • 選取雲服務商提供的高性能網絡插件:例如阿里雲的 Terway
  • Host network,繞開 k8s 的虛擬化網絡(需要一定的開發量)

第一個要排查的問題就是集群不要有異構網絡環境,因為有可能 Kubernetes 的宿主機在不同機房,然後跨機房訪問遇到網絡抖動的時候都就會比較頭疼。然後是雲服務商機器配置網卡多隊列,因為 ECS 虛擬機,它是需要耗一定的 CPU 去做網絡虛擬化。那麼如果網卡不配置成多隊列的話,有可能網卡只用了1到2個 core,然後虛擬化會把這2個 core 用光,用光的話會導致丟包,也就會遇到這種比較頭疼的Connection reset by peer 問題。

還有一種方案是選取雲服務商提供的高性能網絡插件,當然這需要雲服務商支持,比如阿里雲的 Terway,Terway 對外描述是可以支持與 host network 一樣的性能,而不是像 flannel 會帶來一定的性能損耗。

最後一種,如果無法使用 Terway,我們可以用 host network 來繞開 K8S 虛擬化網絡。不過這種方案首先是對 Flink 有一些開發工作,其次是如果你已經使用了Kubernetes,卻還要使用 host network,從某種意義上來說,有一點奇怪,很不符合 K8S style。當然我們也在一些無法用 Terway 的機器,然後又遇到這個頭疼的問題是,也提供了相應工程,部署時採用 host network,而不是使用 overlay 的flannel 方案。

■ 磁盤性能

接下來談磁盤性能,前文提到過:所有虛擬化的東西都會帶來一些性能損耗。對於 RocksDB 需要讀寫本地磁盤的場景,就很頭疼,因為 overlay 的 file system 會有大概30%的性能損耗。

640 10.jpg

那怎麼辦呢?我們選擇一種方式,就是使用 hostPath。簡單來說,POD 可以訪問到宿主機的物理盤。上圖右側部分就定義了 hostPath,當然需要預先保證 Flink 鏡像的用戶是具備訪問宿主機目錄權限,所以最好把這裡目錄改成 777 或者 775。

大家如果想用這個功能的話,可以查看 Flink-15656,它提供一個 POD 的 template,意味著你可以自行調整。因為我們知道 K8S 的功能特別多,特別繁雜,Flink 不可能為了每一個功能都去做個適配。你可以在 template 裡面,比如定義 hostPath,然後你所寫 POD 的就可以基於這個模板下面的 hostPath 就可以去訪問目錄了。

OOM killed

OOM killed 也是個比較頭疼的問題。因為在容器環境下,部署服務的時候,我們需要預先設置 POD 所需 memory 和 CPU 的資源,然後 Kubernetes 會指定配置去相關 node (宿主機)上面申請調度資源。申請資源除了要設置 request 之外,還有會設置 limit——一般都會打開 limit——它會對申請的 memory 和 CPU 進行限制。

比如說 node 的物理內存是 64G,然後申請運行8個8G內存的 POD,看著好像沒有問題,但是如果對這8個 POD的沒有任何 limit的話,假如每個用到10G,那麼就會導致 POD 之間出現資源競爭,現象是一個 POD 運行正常另外一個 POD 忽然被 Kill,所以就要做一個memory limit。memory limit 帶來的問題是:POD 莫名其妙退出,然後查看 Kubernetes 的 event 發現是因為 POD 被 OOM killed 了。我相信如果用過Kubernetes 的同學肯定遇到過相關問題。

我們是怎麼排查的呢?

640 11.jpg

第一個是我們可以在 JVM 端開啟 native 內存追蹤,可以定期去查看,但這隻能看到 JVM 所申請的 native 內存,包括如 Metaspace,非 JVM 就無法分析了;還有一個就是萬能的 Jemalloc 和 jeprof 去做定期 dump 內存進行分析。

老實說第2個功能我們可能用的比較少,因為我們以前在 YARN 上面會這樣用,就是說發現有的作業內存很大,因為 JVM 對最大內存會做限制,所以肯定是 native 這邊出的問題,那麼到底是哪個 native 出問題,就可以 Jemalloc+jeprof 作內存分析。比如我們之前遇到過用戶自己去解析 config 文件,結果每次都要解壓一下,最後把內存撐爆了。

當然這是一種引起 OOM 的場景,但更多的可能是 RocksDB 引發 OOM,當然如果是使用了 RocksDB 這種省 native 內存的 state backend。所以我們在 Flink 1.10 做了一個功能貢獻給社區,就是對 RocksDB 的 memory 進行管理,由參數state.backend.rocksdb.memory.managed 控制是否進行管理,默認是開啟。

我們下面這個圖是什麼呢?

640 12.jpg

是在 RocksDB 沒有使用 memory 控制,這裡一共定了4個 state,分別是 value、list、map 和 window,大家可以看到最頂端的線是 block cache usage 加上RocksDB 的 write buffer 就構成了 RocksDB 當前所使用總內存的大小。大家看到這4個加起來的話差不多超過400M了。

原因是 Flink 目前的 RocksDB 對 state 數沒有限制,一個 state 的就是一個 Column Family,而 Column Family 就會額外獨佔所用的 write buffer 和 block cache。默認情況下,一個 Column Family 最多擁有2個64MB write buffer 和一個 8MB block cache,大家可以算一算,一個 state 就是136MB,四個 state 就是544MB。

如果我們開啟了 state.backend.rocksdb.memory.managed,我們會看到4個 state所使用的 block cache 折線走勢基本一致:

640 13.jpg

為什麼呢?是因為實現了 cache share 功能。就是說,我們在一個 state 裡面我們先創建一個 LRU cache,之後無論是什麼情景都會從 LRU cache 裡面去做內存的分發和調度,然後藉助 LRU cache,最近最少被用的內存會被釋放掉。所以在 Flink 1.10之後,我們說開啟 state.backend.rocksdb.memory.managed 可以解決大部分問題。

640 14.jpg

但是,當然萬事都有但是,我們開發過程中發現:RocksDB cache share 的功能做的不是特別好。這涉及到一些實現原理細節,比如沒法去做 strict cache,如果你開啟的話可能會碰到奇怪的NPE問題,所以說在某些特定場景下可能做的不是很好。這時你可能就要適當增大taskmanager.memory.task.off-heap.size 以提供更多的緩衝空間。

當然我們首先要知道它大概用多少內存空間。剛才我們展示的內存監控圖裡面,是需要打開參數 state.backend.rocksdb.metrics.block-cache-usage:true,打開之後,我們可以在 metrics 監控上面去獲取到相關的指標,觀察一下大概超用到多少。比如說1GB一個 state TM 默認的 manager 是 294MB。

所以說你發現比如說你可能超過很多,比如說偶爾會到300MB,或者310MB,你這時候就可以考慮配置參數taskmanager.memory.task.off-heap.size (默認是0)來再增加一部分內存,比如說再加64MB,表示在 Flink 所申請的 off-heap 裡面再額外開闢出來一塊空間,給RocksDB 做一段 Buffer,以免他被 OOM killed。這個是目前所能掌握的一個解決方案,但根本的解決方案可能需要跟 RocksDB 社區去一起去協同處理。

我們也希望如果有同學遇到類似問題可以跟我們進行交流,我們也非常樂意和你一起去觀察、追蹤相關問題。

Demo

最後一部分演示使用 hostPath 的 demo,大部分 yaml 文件與社區的示例相同,task manager 的部署 yaml 文件需要修改,見下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flink-taskmanager
spec:
  replicas: 2
  selector:
    matchLabels:
      app: flink
      component: taskmanager
  template:
    metadata:
      labels:
        app: flink
        component: taskmanager
    spec:
      containers:
      - name: taskmanager
        image: reg.docker.alibaba-inc.com/chagan/flink:latest
        workingDir: /opt/flink
        command: ["/bin/bash", "-c", "$FLINK_HOME/bin/taskmanager.sh start; \
          while :;
          do
            if [[ -f $(find log -name '*taskmanager*.log' -print -quit) ]];
              then tail -f -n +1 log/*taskmanager*.log;
            fi;
          done"]
        ports:
        - containerPort: 6122
          name: rpc
        livenessProbe:
          tcpSocket:
            port: 6122
          initialDelaySeconds: 30
          periodSeconds: 60
        volumeMounts:
        - name: flink-config-volume
          mountPath: /opt/flink/conf/
        - name: state-volume
          mountPath: /dump/1/state
        securityContext:
          runAsUser: 9999  # refers to user _flink_ from official flink image, change if necessary
      volumes:
      - name: flink-config-volume
        configMap:
          name: flink-config
          items:
          - key: flink-conf.yaml
            path: flink-conf.yaml
          - key: log4j.properties
            path: log4j.properties
      - name: state-volume
        hostPath:
          path: /dump/1/state
          type: DirectoryOrCreate

Q&A 問答

1、Flink 如何在 K8S 的 POD 中與 HDFS 交互?

其與 HDFS 交互很簡單,只要把相關依賴打到鏡像裡面就行了。就是說你把 flink-shaded-hadoop-2-uber-{hadoopVersion}-{flinkVersion}.jar 放到 flink-home/lib目錄下,然後把一些 hadoop 的配置比如 hdfs-site.xml、 core-site.xml 等放到可以訪問的目錄下,Flink 自然而然就可以訪問了。這其實和在一個非 HDFS 集群的節點上,要去訪問 HDFS 是一樣的。

2、Flink on K8S 怎麼保證 HA?

其實 Flink 集群的 HA 與是否運行在 K8S 之上沒什麼關係,社區版的 Flink 集群 HA需要 ZooKeeper 參與。HA 需要 ZooKeeper 去實現 checkpoint Id counter、需要ZooKeeper 去實現 checkpoint stop、還包括 streaming graph 的 stop,所以說HA 的核心就變成如何在 Flink on K8S 的集群之上,提供 ZooKeeper 的服務,ZooKeeper 集群可以部署在 K8S 上或者物理機上。同時社區也有嘗試在 K8S 裡面借用 etcd 去支持提供一套 HA 方案,目前真正工業級的 HA,暫時只有 zookeeper 這一種實現。

3、Flink on K8S 和 Flink on YARN,哪個方案更優?怎樣選擇?

Flink on YARN 是目前比較成熟的一套系統,但是它有點重,不是雲原生(cloud native)。在服務上雲的大趨勢下,Flink on K8S 是一個光明的未來。Flink on YARN 是一個過去非常成熟一套體系,但是它在新的需求、新的挑戰之下,可能缺乏一些應對措施。例如對很多細緻的 GPU 調度,pipeline 的創建等等,概念上沒有K8S 做得好。

如果你只是簡單運行一個作業,在 Flink on YARN 上可以一直穩定運行下去,它也比較成熟,相比之下 Flink on K8S 夠新、夠潮、方便迭代。不過目前 Flink on K8S 已知的一些問題,比如學習曲線比較陡峭,需要一個很好的 K8S 運維團隊去支撐。另外,K8S 本身虛擬化帶來的性能影響,正如先前介紹的無論是磁盤,還是網絡,很難避免一定的性能損耗,這個可能是稍微有點劣勢的地方,當然相比這些劣勢,虛擬化(容器化)帶來的優點更明顯。

4、 /etc/hosts 文件如何配置的?我理解要跟 HDFS 交互,需要把 HDFS 節點 IP 和 host,映射寫到 /etc/hosts 文件。

通過通過 Volume 掛載 ConfigMap 內容並映射到 /etc/hosts 來解決,或者無需修改 /etc/hosts 轉而依賴 CoDNS。

5、Flink on K8S 故障排查困難,你們是怎麼解決的?

首先 Flink on K8S 與 Flink on YARN 的故障排查有什麼區別呢?主要是 K8S 本身可能會有問題,這就是稍微麻煩的地方。K8S 可以認為是一個操作系統,可能有很多複雜的組件在裡面。YARN 是一個用 Java 實現的資源調度器,這時更多是宿主機故障導致集群異常。面對 K8S 可能出問題,我個人感覺是相比 YARN 來說要難查一些。因為它有很多組件,可能 DNS 解析出問題,就需要去查看 CoDNS 日誌;網絡出問題或者是磁盤出問題你要去查看 kube event;POD 異常退出,需要去查看 event POD 退出的原因。實話實話,確實需要一定的門檻,最好是需要運維支持。

但如果是說 Flink 故障排查,這在 K8S 或是 YARN 排查手段都一樣,

  • 查看日誌,檢測是否有 exception;
  • 如果是性能就需要用 jstack,查看 CPU、調用棧卡在哪裡;
  • 如果發現總是有 OOM 風險,或者老年代總是打的很滿,或者 GC 頻繁,或者Full GC 導致 Stop the world,就需要 jmap 查看哪塊佔內存,分析是否存在內存洩露

這些排查方法是與平臺是無關的,是一個放之四海而皆準的排查流程。當然需要注意POD 鏡像中可能會缺少一些 Debug 工具,所以建議大家在搭建 Flink on K8S 集群時,構建私有鏡像,在構建的過程中安裝好相應的 Debug 工具。

Leave a Reply

Your email address will not be published. Required fields are marked *