Flink 1.10 Container 環境實戰

ApacheFlink發表於2020-06-10

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

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

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

Tips:點選下方可檢視更多 1.10 系列直播視訊~

1.10系列直播:
https://ververica.cn/develope...

本文第一部分將簡明扼要地介紹容器管理系統的演變;第二部分是 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 <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 工具。

相關文章