通過WordCount來入門Flink,讀懂Flink基礎架構,Flink學習入門(一)

大家好,我是後來,我會分享我在學習和工作中遇到的點滴,希望有機會我的某篇文章能夠對你有所幫助,所有的文章都會在公衆號首發,歡迎大家關注我的公衆號" 後來X大數據 ",感謝你的支持與認可。

前幾天寫的計算機網絡的網絡層在csdn閱讀量快破5000了,也給我帶來了不少的粉絲,還是非常開心的,給了我寫文很大的動力。在這裏看一下:
警察叔叔順着網線是怎麼找到你的?計算機網絡(四)之網絡層未完待續

最近公司越來越多的業務要用到Flink,我也正好把知識點再複習下,做到學以致用,哈哈,而且前幾天看到Flink1.11版本都開始支持hive流處理了,還是比較興奮的。因爲自己關於Flink的經驗也不是很多,所以我就再以小白的身份寫個Flink學習專欄。各位大佬不喜勿噴。

寫完基本知識,也會夾雜着工作實例,算是給自己做個筆記。希望某篇文章能對你有所幫助。
強烈建議:閱讀官網!
我學習一個新技術的步驟大概是這樣的:

  1. 先了解這個技術要解決什麼問題
  2. 簡單上手體驗一下,找找自信心
  3. 學習架構,知曉原理
  4. 學習API,體驗高級玩法
  5. 搞個小項目上手,學以致用。

1、Flink大致介紹

關於實時處理與離線處理,一個很大的不同就在於,數據是不是有界的。

  1. 有界流:數據有終點,比如要對一個txt文本做wordCount。
  2. 無界流:數據有起點,沒有終點,比如說是從socket 端口拿數據計算wordCount,可以無休止的產生數據。

而在實時處理方面,又有Flink和Spark Streaming,那麼他倆最大的區別就是Flink是真正的流處理,而spark Streaming是微批次處理。

  1. Flink可以以事件爲單位,來一條數據就處理一條(可以,不是隻能,flink也可以 以時間窗口爲單位進行計算,大家不要誤解)
  2. Spark Streaming是以一個窗口爲單位,一次處理一批

當然flink也可以擅長做批處理,只不過現在flink代表的更多的是實時處理。

1.1 Flink的組件棧有哪些?

在這裏插入圖片描述
這些組件可以先大概知道有這麼回事,然後後續的學習中一點點理解就記住了。
圖中也能知道:

  1. 運行模式大致分爲3種,本地、集羣、雲
  2. DataStream API流處理
  3. DataSet API批處理
  4. 上層還支持CEP、SQL、機器學習ML、圖計算。

2、Flink初體驗

還是先在IDE中來一個WordCount吧。這個先直接複製了,跑起來我們再來分析其中的東西。
這個代碼是scala代碼寫的,關於建項目和導入scala框架這個大家百度吧。

import org.apache.Flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.Flink.streaming.api.scala._

/**
  * @description: WordCount小入門
  * @author: Liu Jun Jun
  * @create: 2020-06-04 10:10
  **/
object WordCount {
  def main(args: Array[String]): Unit = {
  //獲取環境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
//從客戶端獲取流式數據
    val wordDS: DataStream[String] = env.socketTextStream("bigdata101",3456)
//對數據進行轉換,按照單詞分組,最後求和
    val resultDS = wordDS.map((_,1)).keyBy(_._1).sum(1)
//對結果進行打印
    resultDS.print("ceshi:")
//真正的執行命令,前面這些都是懶加載的,只有在遇到execute纔會觸發執行
    env.execute("wordCount")
  }

}

測試——在linux系統中用netcat命令進行發送測試。沒有nc 的可以安裝一下
(yum -y install nc)
nc -lk 3456
然後自己寫點單詞,控制檯看輸出結果:
結果展示:
在這裏插入圖片描述
在這個測試案例中,我們已經體驗到了Flink的流式處理。
結果展示中,前面的數字代表的當前這個任務跑在我的哪個cpu上,我這個電腦是4個cpu,默認使用全部資源,所以它自己選擇執行。當然你會發現later這個單詞總在cpu4上。

好了,那就繼續往下走,我們剛只是在IDE中體驗了一把,但是我們實際生產中還是要打包放在集羣上跑的。

那麼接下里我們在集羣上部署一下Flink

3、Flink安裝

說到Flink的集羣安裝,就有幾種模式。本地模式一般也就是自學用,所以這裏就暫時不安裝了。來看看集羣部署。

  1. Standalone模式:這種模式下的Flink使用自己的資源管理及任務調度,不依賴於hadoop,目前使用的不是很多。
  2. yarn模式:這種模式的話,Flink更像是一個客戶端,做了一個計算引擎,把任務提交到yarn,由yarn來進行資源的分配以及任務的調度。但計算使用的是Flink引擎。使用的比較多。

以上兩種方式,根據公司需求不同選擇不同。我在這裏主要講一下yarn模式
根據官網介紹:
如果你計劃將 Apache Flink 與 Apache Hadoop 一起使用(在 YARN 上運行 Flink ,連接到 HDFS ,連接到 HBase 等),則需要下載好Flink後,把hadoop組件放在Flink的lib目錄下,這個在官網有說明,如果官網沒提供你的hadoop版本,那就需要自己編譯了。
在這裏插入圖片描述
我這裏直接提供一個Flink1.7.2版本集成好hadoop依賴的包,直接解壓部署就可以了。
解壓值需要配置web頁面地址,當然不配置跑任務也沒有問題。 鏈接在我的微信公衆號【後來X大數據】,回覆”flink“就可以直接下載。

yarn模式也有2種類型:

  1. Session-Cluster
    在這裏插入圖片描述
    這種模式就是在啓動hadoop集羣后,先申請一塊空間,也就是啓動yarn-session,以後所有提交的任務都在這塊空間內執行。相當於是承包商。不如下面的方式靈活。
  2. Per-Job-Cluster
    在這裏插入圖片描述
    這個則是每次提交一個Flink任務,都會單獨的只申請自己所需要的空間,組成flink集羣,任務執行完就註銷掉。任務之間互相獨立,互不影響,方便管理。

很明顯,第二種方式對資源的利用更加靈活。

那麼接下來我們提交個任務看看。我們就用官方的WordCount測試包吧。自己寫個文件,裏面隨便寫點單詞。

bin/flink run -m yarn-cluster -yn 7 -ys 2 -p 14  -ytm 2048m -yjm 2048m  -yqu Flink ./examples/batch/WordCount.jar --input /opt/wc.txt --output /opt/output4/

bin/Flink 後面其實可以指定很多參數,大家可以bin/Flink --help查看一下
-m 指定任務運行模式
-yqu 指定提交任務的隊列
-n(–container):TaskManager的數量。
-s(–slots): 每個TaskManager的slot數量,默認一個slot一個core,默認每個taskmanager的slot的個數爲1,有時可以多一些taskmanager,做冗餘。
-jm:JobManager的內存(單位MB)。
-tm:每個taskmanager的內存(單位MB)。
-nm:yarn 的appName(現在yarn的ui上的名字)。
-d:後臺執行。

那一看命令這麼多參數,那我們平時怎麼提交任務就會方便一些呢?一般情況下我們寫成腳本執行。

提交任務後可以在yarn上看到這個任務,通過Application,可以進入webUI頁面,我們可以看到這個任務的流程圖。(這個圖我完了補上,寫文的電腦上沒裝集羣)

4、Flink架構

通過上述的介紹,其實對Flink已經有了初步的認識。那我們來初步理解一下Flink的架構,前期只需要大致理解就可以了,更多的理解還是要基於使用,畢竟實踐出真知!

4.1 Flink在運行時會包含這幾種主要的角色:

  1. Job Managers:提交的這個任務的老大,管理Flink集羣中從節點TaskManager
  2. Task Managers:單個任務的管理者,負責管理其所在節點上的資源信息,如內存、磁盤、網絡,在啓動的時候將資源的狀態向JobManager彙報
  3. Resource Manager:集羣資源的管理者
  4. Clients:提交作業的機器

上面提到的是任務在運行中有哪些具體的角色,那麼廣義上來說,Flink在這裏充當的角色更多的是一個客戶端,用來提交job。

4.2Flink on yarn時,提交任務的流程就如下圖所示:

在這裏插入圖片描述

  1. Flink提交後,Client向HDFS上傳Flink的Jar包和配置
  2. Client給RM提交任務
  3. RM分配資源並通知選中的對應的NodeManager,啓動ApplicationMaster來作爲這個任務所有資源的老大,進行管理。
  4. ApplicationMaster啓動後加載Flink的Jar包和配置構建環境,然後啓動JobManager
  5. AM向RM申請資源啓動TaskManager,AM分配資源以後,AM就通知資源所在的節點的NodeManager啓動TaskManager
  6. NodeManager加載Flink的Jar包和配置構建環境並啓動TaskManager,TaskManager啓動後向JobManager發送心跳包,並等待JobManager向其分配任務。

4.3那麼Flink任務是怎麼資源調度的?

我們來跟着官網的思路走一下:

  1. 我們的每一個TaskManager都是一個JVM進程,這麼理解吧,TaskManager啓動在NodeManager所在的節點,就等於說是一個節點一個TaskManager。
  2. 這個JVM進程可以在不同的線程中執行一個或多個 subtasks(子任務),那肯定啊,一個節點同時執行很多個子任務。但是同時執行的子任務過多,是不是會搶佔資源比較嚴重,那麼幾個會比較合理呢?
  3. 在Flink中有個插槽的概念,slot: TaskManager 的一份固定資源子集。目前僅僅用來隔離task的內存,例如,具有三個 slots 的 TaskManager 會將其管理的內存資源分成三等份給每個 slot。這樣做的好處就是劃分到不同slot的子任務集不會再搶佔別的slot資源。
  4. 但是問題是:這樣也不公平,比如2個需要資源相差很大的子任務劃分到了不同的slot中,會出現需要資源小的任務早就跑完了,而另一個需要資源多的任務卻遲遲跑不完。所以,Flink 允許 subtasks 共享 slots,即使它們是不同 tasks 的 subtasks,只要它們來自同一個 job。這樣的好處是:
    (1)需要資源少的子任務可以劃分到一個slot,而需要資源多的可以單獨劃分到一個slot,可以充分利用slot資源,同時確保繁重的 subtask 在 TaskManagers 之間公平地獲取資源。
    (2)Flink 的並行度只要控制好合理的slot數就可以了,因爲每個slot都是一個線程。這樣不需要計算作業總共包含多少個 tasks。
    在這裏插入圖片描述
    根據經驗,合理的 slots 數量應該和 CPU 核數相同。這個在實際的工作中,應在是看給自己分到的隊列的資源一共是多少,而自己預估這個任務大概需要多少資源,然後合理的設置slots數,也就是合理的設置並行度。

4.4 Flink的Slot和parallelism有什麼區別?

注意:

  1. Task Slot是靜態的概念,是指TaskManager 具有的併發執行能力 ,可以通過參數taskmanager.numberOfTaskSlots進行配置;
  2. 而並行度parallelism是動態概念,即TaskManager運行程序時實際使用的併發能力,可以通過參數parallelism.default進行配置。

這麼舉例子吧,我們提交一個job,就有了一個JobManger,那麼通過資源的分配,假如現在在3個節點上執行任務,那就等於說有3個TaskManager,假如每一個TaskManager都包含了一定數量的插槽(slots)。插槽的數量限制了TaskManager能夠執行的任務數量。這裏假設每個TaskManager可以接收3個task,一共9個TaskSlot,如果我們設置parallelism.default=1,即運行程序默認的並行度爲1,9個TaskSlot只用了1個,有8個空閒,因此,設置合適的並行度才能提高效率。

4.5 Flink的並行度是什麼?怎麼設置纔算是合理呢?

算子的並行度: 一個特定算子的子任務(subtask)的個數被稱之爲其並行度(parallelism)。一個程序中,不同的算子可能具有不同的並行度。
那麼具體的每個算子的並行度是多少這個我們後面具體說算子的時候再來講,這裏先大致介紹一下:

  1. One-to-one,類似於spark的窄依賴,比如map、filter等
  2. 一對多,類似於spark的寬依賴。

相同並行度的one to one操作,Flink這樣相連的算子鏈接在一起形成一個task,原來的算子成爲裏面的一部分。將算子鏈接成task是非常有效的優化:它能減少線程之間的切換和基於緩存區的數據交換,在減少時延的同時提升吞吐量。

任務鏈必須滿足兩個條件:one-to-one的數據傳輸並且並行度相同
**job的並行度:**任務被分爲多個並行任務來執行,其中每個並行的實例處理一部分數據。這些並行實例的數量被稱爲並行度。

我們在實際生產環境中可以從四個不同層面設置並行度:(具體代碼體現在後續寫)
操作算子層面(Operator Level)
執行環境層面(Execution Environment Level)
客戶端層面(Client Level)
系統層面(System Level)
需要注意的優先級:算子層面>環境層面>客戶端層面>系統層面。

4.6 Flink的基礎編程模型

我們在上述wordCount的代碼中,就發現數據流由3部分組成,數據源source,數據轉換,數據最後的流出sink 3部分組成。那麼這其實也是我們代碼的主要構成,通過合適的轉換算子將數據源的數據進行處理,最後把結果通過sink的方式輸出到別的地方。
每一個dataflow以一個或多個sources開始以一個或多個sinks結束。
在這裏插入圖片描述
Flink 將算子的子任務鏈接成 task。每個 task 由一個線程執行。把算子鏈接成 tasks 能夠減少線程間切換和緩衝的開銷,在降低延遲的同時提高了整體吞吐量。

4.7 Flink的流程圖有哪些?

那麼上述的數據流直接映射成的數據流圖是StreamGraph,也被稱爲邏輯流圖,因爲它們表示的是計算邏輯的高級視圖。爲了執行一個流處理程序,Flink需要將邏輯流圖轉換爲物理數據流圖(也叫執行圖),詳細說明程序的執行方式。
Flink 中的執行圖可以分成四層:StreamGraph -> JobGraph -> ExecutionGraph -> 物理執行圖。

  1. StreamGraph:是根據用戶通過 Stream API 編寫的代碼生成的最初的圖。用來表示程序的拓撲結構。
  2. JobGraph:StreamGraph經過優化後生成了 JobGraph,提交給 JobManager 的數據結構。主要的優化爲,將多個符合條件的節點 chain 在一起作爲一個節點,這樣可以減少數據在節點之間流動所需要的序列化/反序列化/傳輸消耗。
  3. ExecutionGraph:JobManager 根據 JobGraph 生成ExecutionGraph。ExecutionGraph是JobGraph的並行化版本,是調度層最核心的數據結構。
  4. 物理執行圖:JobManager 根據 ExecutionGraph 對 Job 進行調度後,在各個TaskManager 上部署 Task 後形成的“圖”,並不是一個具體的數據結構。

這幾個類在源碼中也能找到。

關於Flink比較基礎的框架概念已經瞭解的差不多了,部分內容也來源於官網中文翻譯。
可能有些概念還沒理解透徹,不過沒關係,在接下來的應用中,使用的多了就會有不一樣的收穫,期望通過一篇文章或者只看官網的介紹理解透徹是不存在的,畢竟這框架是衆多大牛聚集在一起搞了很多年才搞出來的,我們只不過是個框架的使用者,約等於搬磚工。

所以我寫的內容也歡迎大家前來討論。

那麼下一篇Flink的文章我來繼續學習關於Flink的API。期待能和你一起學習!

掃碼關注”後來X大數據“,回覆【電子書】,領取【超多本pdf java及大數據 電子書】

在這裏插入圖片描述

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