正面超越 Spark | 幾大特性墊定Flink1.12流計算領域真正大規模生產可用(上)

點擊上方藍色字體,選擇“設爲星標”

回覆”資源“獲取更多驚喜


在小編的記憶裏,Flink 自從出現在大衆視野中,一直在高速迭代。Flink1.10版本之前因爲重大功能的缺失(主要是和Hive的兼容性),筆者一直都不推薦直接應用在大規模的生產實踐中,可以做小範圍內業務嘗試。Flink 1.10版本可以被認爲是一個承上啓下的革命性版本。

隨着 Flink 1.12版本的更新,Flink更新的一系列重大特性和對穩定性方面的考量,小編個人認爲才真正擁有了和Spark這麼成熟的框架正面交鋒的資格。Flink1.12版本有哪些更新可以在官網查詢到,不再贅述。

我們從這些特性中找出最重要的幾個講解,希望對大家有幫助。

第一個,基於Kubernetes的高可用方案

Flink 1.12 版本後,Flink 終於出現了生產級別的 Kubernetes(下面簡稱K8s)高可用方案。有的同學可能會問,爲什麼不用Yarn,要用K8s做集羣管理?

這個要從K8s的發展過程和相比於Yarn的優勢談起。

Kubernetes 項目源自 Google 內部 Borg 項目,基於 Borg 多年來的優秀實踐和其超前的設計理念,並憑藉衆多豪門、大廠的背書,時至今日,Kubernetes 已經成長爲容器管理領域的事實標準。在大數據及相關領域,包括 Spark,Hive,Airflow,Kafka 等衆多知名產品正在遷往 Kubernetes,Apache Flink 也是其中一員。

Yarn的發展過程不需要贅述,從Hadoop時代開始,Yarn就是最被廣泛使用的資源管理框架存在。

那麼,K8s相比於Yarn有哪些特點呢?小編個人認爲主要是以下幾個方面:

1. K8s作爲容器管理的事實標準,在資源和網絡隔離,安全,多租戶天然優勢
2. 能夠和雲原生的監控體系無縫融合,例如Prometheus
3. Yarn缺少load balance、離在線混合部署這些特性,在資源利用率上稍弱

但是並不是說Yarn就不夠好,K8s也存在很多缺陷,例如較高的運維成本、複雜的權限管理等。

Flink 1.12版本的更新代表:Flink 可以利用 Kubernetes 提供的內置功能來實現 JobManager 的 failover,而不用依賴 ZooKeeper。該方案與 ZooKeeper 方案基於相同的接口,並使用 Kubernetes 的 ConfigMap對象來處理從 JobManager 的故障中恢復所需的所有元數據。

我們從官網上可以找到Flink集成K8s的原理圖:

圖來源於ververica.cn

工作原理如下:

  • Flink 客戶端首先連接 Kubernetes API Server,提交 Flink 集羣的資源描述文件,包括 configmap,job manager service,job manager deployment 和 Owner Reference。

  • Kubernetes Master 就會根據這些資源描述文件去創建對應的 Kubernetes 實體。以我們最關心的 job manager deployment 爲例,Kubernetes 集羣中的某個節點收到請求後,Kubelet 進程會從中央倉庫下載 Flink 鏡像,準備和掛載 volume,然後執行啓動命令。在 flink master 的 pod 啓動後,Dispacher 和 KubernetesResourceManager 也都啓動了。前面兩步完成後,整個 Flink session cluster 就啓動好了,可以接受提交任務請求了。

  • 用戶可以通過 flink 命令行即 flink client 往這個 session cluster 提交任務。此時 job graph 會在 flink client 端生成,然後和用戶 jar 包一起通過 RestClinet 上傳。

  • 一旦 job 提交成功,JobSubmitHandler 收到請求就會提交 job 給 Dispatcher。接着就會生成一個 job master。

  • JobMaster 向 KubernetesResourceManager 請求 slots。

  • KubernetesResourceManager 從 Kubernetes 集羣分配 TaskManager。每個 TaskManager 都是具有唯一標識的 Pod。KubernetesResourceManager 會爲 TaskManager 生成一份新的配置文件,裏面有 Flink Master 的 service name 作爲地址。這樣在 Flink Master failover之後,TaskManager 仍然可以重新連上。

  • Kubernetes 集羣分配一個新的 Pod 後,在上面啓動 TaskManager。

  • TaskManager 啓動後註冊到 SlotManager。

  • SlotManager 向 TaskManager 請求 slots。

  • TaskManager 提供 slots 給 JobMaster。然後任務就會被分配到這個 slots 上運行。

那麼基於 Flink on K8s的高可用的幾種模式大家可以參考這裏:

https://blog.csdn.net/yunxiao6/article/details/108705244

整體的架構如下:

Flink on Kubernetes 的架構如圖所示,Flink 任務在 Kubernetes 上運行的步驟有:

  • 首先往 Kubernetes 集羣提交了資源描述文件後,會啓動 Master 和 Worker 的 container。

  • Master Container 中會啓動 Flink Master Process,包含 Flink-Container ResourceManager、JobManager 和 Program Runner。

  • Worker Container 會啓動 TaskManager,並向負責資源管理的 ResourceManager 進行註冊,註冊完成之後,由 JobManager 將具體的任務分給 Container,再由 Container 去執行。

  • 需要說明的是,在 Flink 裏的 Master 和 Worker 都是一個鏡像,只是腳本的命令不一樣,通過參數來選擇啓動 master 還是啓動 Worker。

Flink on Kubernetes–JobManager

JobManager 的執行過程分爲兩步:

  • 首先,JobManager 通過 Deployment 進行描述,保證 1 個副本的 Container 運行 JobManager,可以定義一個標籤,例如 flink-jobmanager。

  • 其次,還需要定義一個 JobManager Service,通過 service name 和 port 暴露 JobManager 服務,通過標籤選擇對應的 pods。

Flink on Kubernetes–TaskManager

TaskManager 也是通過 Deployment 來進行描述,保證 n 個副本的 Container 運行 TaskManager,同時也需要定義一個標籤,例如 flink-taskmanager。

對於 JobManager 和 TaskManager 運行過程中需要的一些配置文件,如:flink-conf.yaml、hdfs-site.xml、core-site.xml,可以通過將它們定義爲 ConfigMap 來實現配置的傳遞和讀取。

整個交互的流程比較簡單,用戶往 Kubernetes 集羣提交定義好的資源描述文件即可,例如 deployment、configmap、service 等描述。後續的事情就交給 Kubernetes 集羣自動完成。Kubernetes 集羣會按照定義好的描述來啓動 pod,運行用戶程序。各個組件的具體工作如下:

  • Service: 通過標籤(label selector)找到 job manager 的 pod 暴露服務。

  • Deployment:保證 n 個副本的 container 運行 JM/TM,應用升級策略。

  • ConfigMap:在每個 pod 上通過掛載 /etc/flink 目錄,包含 flink-conf.yaml 內容。

Flink on Kubernetes參考案例

首先,修改flink-conf.yaml:

high-availability: org.apache.flink.kubernetes.highavailability.KubernetesHaServicesFactory
high-availability.storageDir: s3:///flink/recovery
kubernetes.cluster-id: cluster1337

以上3個配置,表明我們希望Flink運行在K8s上。

官網推薦我們使用native Kubernetes deployments模式進行部署。以session-cluster模式爲例,參考官網的案例:

We generally recommend new users to deploy Flink on Kubernetes using native Kubernetes deployments.
# Configuration and service definition
$ kubectl create -f flink-configuration-configmap.yaml
$ kubectl create -f jobmanager-service.yaml
# Create the deployments for the cluster
$ kubectl create -f jobmanager-session-deployment.yaml
$ kubectl create -f taskmanager-session-deployment.yaml

首先啓動 Session Cluster,執行上述四個啓動命令就可以將 Flink 的 jobmanager-service、jobmanager-deployment、taskmanager-deployment 啓動起來。啓動完成之後用戶可以通過接口進行訪問,然後通過端口進行提交任務。

官網給出的建議配置如下圖所示:

  • jobmanager-session-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: flink-jobmanager
spec:
replicas: 1
selector:
matchLabels:
app: flink
component: jobmanager
template:
metadata:
labels:
app: flink
component: jobmanager
spec:
containers:
- name: jobmanager
image: flink:1.12.0-scala_2.11
args: ["jobmanager"]
ports:
- containerPort: 6123
name: rpc
- containerPort: 6124
name: blob-server
- containerPort: 8081
name: webui
livenessProbe:
tcpSocket:
port: 6123
initialDelaySeconds: 30
periodSeconds: 60
volumeMounts:
- name: flink-config-volume
mountPath: /opt/flink/conf
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-console.properties
path: log4j-console.properties
  • taskmanager-session-deployment.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: flink:1.12.0-scala_2.11
args: ["taskmanager"]
ports:
- containerPort: 6122
name: rpc
- containerPort: 6125
name: query-state
livenessProbe:
tcpSocket:
port: 6122
initialDelaySeconds: 30
periodSeconds: 60
volumeMounts:
- name: flink-config-volume
mountPath: /opt/flink/conf/
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-console.properties
path: log4j-console.properties

若想銷燬集羣,直接用 kubectl delete 即可,整個資源就可以銷燬。

$ kubectl delete -f jobmanager-service.yaml
$ kubectl delete -f flink-configuration-configmap.yaml
$ kubectl delete -f taskmanager-session-deployment.yaml
$ kubectl delete -f jobmanager-session-deployment.yaml

我們運行一個demo案例如下:

$ ./bin/flink run -m localhost:8081 
$ ./examples/streaming/TopSpeedWindowing.jar

打開 http://localhost:8081 即可看到結果。

第二個,DataStream API 支持批執行模式

我們都知道Flink在1.12之前是支持DataStream和DataSet兩種API來分別處理無限流和有限流。然而這非常奇怪不是嗎?因爲在Flink的設計理念中,有限流被認爲是時間維度上有限的【無限流】。

Flink1.12在設計中將DataStream API進行了改造,支持批模式。這代表了什麼?Flink真正的走向了批流一體,雖然我們在生產實踐中還是以DataSet處理批模式,但是在不久的將來會變得不一樣。

Flink 1.12 提供了一個配置來告訴集羣使用什麼模式執行任務:execution.runtime-mode。

  • STREAMING

  • BATCH

  • AUTOMATIC

然後我們就可以使用一下命令進行任務提交:

$ bin/flink run -Dexecution.runtime-mode=BATCH examples/streaming/WordCount.jar

當然你也可以在代碼中這麼寫:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRuntimeMode(RuntimeExecutionMode.BATCH);

雖然,目前這個使用模式看起來比較愚蠢。但是這也代表着,無論是從設計理念還是生產實踐上,Flink正式超越Spark在流計算上的設計,成爲當之無愧的NO1。

當然我們在使用DataStream執行Batch或者Streaming模式時,背後是不一樣的,主要體現在以下幾個方面:

  1. Streaming模式下,每一條數據的到來都會立即觸發計算併產生結果,但是Batch模式會劃分Stage,然後一個接一個執行。

  2. Streaming模式下,使用StateBackend存儲狀態,但是Batch模式下會被忽略。

  3. WaterMark在Batch模式下幾乎不需要,但是Streaming模式下的WaterMark是個強需求。

  4. 失敗策略不一樣。Streaming模式會基於Checkpoint進行重試,但是Batch模式下一般整個任務都會重啓。

  5. reduce、sum函數在Batch模式下只輸出最終結果。並且Batch模式完全不支持Checkpoint、Broadcast State、Iterations。

上部分就講解到這裏了。

阿里數據專家的數據平臺實戰筆記

【大數據嗶嗶集20210125】全圖呈現美團酒旅數據治理實踐


本文分享自微信公衆號 - 大數據技術與架構(import_bigdata)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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