Flink系列文章
- 第01講:Flink 的應用場景和架構模型
- 第02講:Flink 入門程式 WordCount 和 SQL 實現
- 第03講:Flink 的程式設計模型與其他框架比較
- 第04講:Flink 常用的 DataSet 和 DataStream API
- 第05講:Flink SQL & Table 程式設計和案例
- 第06講:Flink 叢集安裝部署和 HA 配置
- 第07講:Flink 常見核心概念分析
- 第08講:Flink 視窗、時間和水印
- 第09講:Flink 狀態與容錯
在 Flink 這個框架中,有很多獨有的概念,比如分散式快取、重啟策略、並行度等,這些概念是我們在進行任務開發和調優時必須瞭解的,這一課時我將會從原理和應用場景分別介紹這些概念。
分散式快取
熟悉 Hadoop 的你應該知道,分散式快取最初的思想誕生於 Hadoop 框架,Hadoop 會將一些資料或者檔案快取在 HDFS 上,在分散式環境中讓所有的計算節點呼叫同一個配置檔案。在 Flink 中,Flink 框架開發者們同樣將這個特性進行了實現。
Flink 提供的分散式快取型別 Hadoop,目的是為了在分散式環境中讓每一個 TaskManager 節點儲存一份相同的資料或者檔案,當前計算節點的 task 就像讀取本地檔案一樣拉取這些配置。
分散式快取在我們實際生產環境中最廣泛的一個應用,就是在進行表與表 Join 操作時,如果一個表很大,另一個表很小,那麼我們就可以把較小的表進行快取,在每個 TaskManager 都儲存一份,然後進行 Join 操作。
那麼我們應該怎樣使用 Flink 的分散式快取呢?舉例如下:
public static void main(String[] args) throws Exception {
final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
env.registerCachedFile("/Users/wangzhiwu/WorkSpace/quickstart/distributedcache.txt", "distributedCache");
//1:註冊一個檔案,可以使用hdfs上的檔案 也可以是本地檔案進行測試
DataSource<String> data = env.fromElements("Linea", "Lineb", "Linec", "Lined");
DataSet<String> result = data.map(new RichMapFunction<String, String>() {
private ArrayList<String> dataList = new ArrayList<String>();
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
//2:使用該快取檔案
File myFile = getRuntimeContext().getDistributedCache().getFile("distributedCache");
List<String> lines = FileUtils.readLines(myFile);
for (String line : lines) {
this.dataList.add(line);
System.err.println("分散式快取為:" + line);
}
}
@Override
public String map(String value) throws Exception {
//在這裡就可以使用dataList
System.err.println("使用datalist:" + dataList + "-------" +value);
//業務邏輯
return dataList +":" + value;
}
});
result.printToErr();
}
從上面的例子中可以看出,使用分散式快取有兩個步驟。
- 第一步:首先需要在 env 環境中註冊一個檔案,該檔案可以來源於本地,也可以來源於 HDFS ,並且為該檔案取一個名字。
- 第二步:在使用分散式快取時,可根據註冊的名字直接獲取。
可以看到,在上述案例中,我們把一個本地的 distributedcache.txt 檔案註冊為 distributedCache,在下面的 map 運算元中直接通過這個名字將快取檔案進行讀取並且進行了處理。
我們直接執行該程式,在控制檯可以看到如下輸出:
在使用分散式快取時也需要注意一些問題,需要我們快取的檔案在任務執行期間最好是隻讀狀態,否則會造成資料的一致性問題。另外,快取的檔案和資料不宜過大,否則會影響 Task 的執行速度,在極端情況下會造成 OOM。
故障恢復和重啟策略
自動故障恢復是 Flink 提供的一個強大的功能,在實際執行環境中,我們會遇到各種各樣的問題從而導致應用掛掉,比如我們經常遇到的非法資料、網路抖動等。
Flink 提供了強大的可配置故障恢復和重啟策略來進行自動恢復。
故障恢復
我們在上一課時中介紹過 Flink 的配置檔案,其中有一個引數 jobmanager.execution.failover-strategy: region。
Flink 支援了不同級別的故障恢復策略,jobmanager.execution.failover-strategy 的可配置項有兩種:full 和 region。
當我們配置的故障恢復策略為 full 時,叢集中的 Task 發生故障,那麼該任務的所有 Task 都會發生重啟。而在實際生產環境中,我們的大作業可能有幾百個 Task,出現一次異常如果進行整個任務重啟,那麼經常會導致長時間任務不能正常工作,導致資料延遲。
但是事實上,我們可能只是叢集中某一個或幾個 Task 發生了故障,只需要重啟有問題的一部分即可,這就是 Flink 基於 Region 的區域性重啟策略。在這個策略下,Flink 會把我們的任務分成不同的 Region,當某一個 Task 發生故障時,Flink 會計算需要故障恢復的最小 Region。
Flink 在判斷需要重啟的 Region 時,採用了以下的判斷邏輯:
- 發生錯誤的 Task 所在的 Region 需要重啟;
- 如果當前 Region 的依賴資料出現損壞或者部分丟失,那麼生產資料的 Region 也需要重啟;
- 為了保證資料一致性,當前 Region 的下游 Region 也需要重啟。
重啟策略
Flink 提供了多種型別和級別的重啟策略,常用的重啟策略包括:
- 固定延遲重啟策略模式
- 失敗率重啟策略模式
- 無重啟策略模式
Flink 在判斷使用的哪種重啟策略時做了預設約定,如果使用者配置了 checkpoint,但沒有設定重啟策略,那麼會按照固定延遲重啟策略模式進行重啟;如果使用者沒有配置 checkpoint,那麼預設不會重啟。
下面我們分別對這三種模式進行詳細講解。
無重啟策略模式
在這種情況下,如果我們的作業發生錯誤,任務會直接退出。
我們可以在 flink-conf.yaml 中配置:
複製程式碼
restart-strategy: none
也可以在程式中使用程式碼指定:
複製程式碼
final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
env.setRestartStrategy(RestartStrategies.noRestart());
固定延遲重啟策略模式
固定延遲重啟策略會通過在 flink-conf.yaml 中設定如下配置引數,來啟用此策略:
複製程式碼
restart-strategy: fixed-delay
固定延遲重啟策略模式需要指定兩個引數,首先 Flink 會根據使用者配置的重試次數進行重試,每次重試之間根據配置的時間間隔進行重試,如下表所示:
舉個例子,假如我們需要任務重試 3 次,每次重試間隔 5 秒,那麼需要進行一下配置:
複製程式碼
restart-strategy.fixed-delay.attempts: 3
restart-strategy.fixed-delay.delay: 5 s
當前我們也可以在程式碼中進行設定:
複製程式碼
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(
3, // 重啟次數
Time.of(5, TimeUnit.SECONDS) // 時間間隔
));
失敗率重啟策略模式
首先我們在 flink-conf.yaml 中指定如下配置:
複製程式碼
restart-strategy: failure-rate
這種重啟模式需要指定三個引數,如下表所示。失敗率重啟策略在 Job 失敗後會重啟,但是超過失敗率後,Job 會最終被認定失敗。在兩個連續的重啟嘗試之間,重啟策略會等待一個固定的時間。
這種策略的配置理解較為困難,我們舉個例子,假如 5 分鐘內若失敗了 3 次,則認為該任務失敗,每次失敗的重試間隔為 5 秒。
那麼我們的配置應該是:
複製程式碼
restart-strategy.failure-rate.max-failures-per-interval: 3
restart-strategy.failure-rate.failure-rate-interval: 5 min
restart-strategy.failure-rate.delay: 5 s
當然,也可以在程式碼中直接指定:
複製程式碼
env.setRestartStrategy(RestartStrategies.failureRateRestart(
3, // 每個時間間隔的最大故障次數
Time.of(5, TimeUnit.MINUTES), // 測量故障率的時間間隔
Time.of(5, TimeUnit.SECONDS) // 每次任務失敗時間間隔
));
最後,需要注意的是,在實際生產環境中由於每個任務的負載和資源消耗不一樣,我們推薦在程式碼中指定每個任務的重試機制和重啟策略。
並行度
並行度是 Flink 執行任務的核心概念之一,它被定義為在分散式執行環境中我們的一個運算元任務被切分成了多少個子任務並行執行。我們提高任務的並行度(Parallelism)在很大程度上可以大大提高任務執行速度。
一般情況下,我們可以通過四種級別來設定任務的並行度。
- 運算元級別
在程式碼中可以呼叫 setParallelism 方法來設定每一個運算元的並行度。例如:
複製程式碼
DataSet<Tuple2<String, Integer>> counts =
text.flatMap(new LineSplitter())
.groupBy(0)
.sum(1).setParallelism(1);
事實上,Flink 的每個運算元都可以單獨設定並行度。這也是我們最推薦的一種方式,可以針對每個運算元進行任務的調優。
- 執行環境級別
我們在建立 Flink 的上下文時可以顯示的呼叫 env.setParallelism() 方法,來設定當前執行環境的並行度,這個配置會對當前任務的所有運算元、Source、Sink 生效。當然你還可以在運算元級別設定並行度來覆蓋這個設定。
複製程式碼
final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(5);
- 提交任務級別
使用者在提交任務時,可以顯示的指定 -p 引數來設定任務的並行度,例如:
複製程式碼
./bin/flink run -p 10 WordCount.jar
- 系統配置級別
我們在上一課時中提到了 flink-conf.yaml 中的一個配置:parallelism.default,該配置即是在系統層面設定所有執行環境的並行度配置。
整體上講,這四種級別的配置生效優先順序如下:運算元級別 > 執行環境級別 > 提交任務級別 > 系統配置級別。
在這裡,要特別提一下 Flink 中的 Slot 概念。我們知道,Flink 中的 TaskManager 是執行任務的節點,那麼在每一個 TaskManager 裡,還會有“槽位”,也就是 Slot。Slot 個數代表的是每一個 TaskManager 的併發執行能力。
假如我們指定 taskmanager.numberOfTaskSlots:3,即每個 taskManager 有 3 個 Slot ,那麼整個叢集就有 3 * taskManager 的個數多的槽位。這些槽位就是我們整個叢集所擁有的所有執行任務的資源。
總結
這一課時我們講解了 Flink 中常見的分散式快取、重啟策略、並行度幾個核心的概念和實際配置,這些概念的正確理解和合理配置是後面我們進行資源調優和任務優化的基礎。在下一課時中我們會對 Flink 中最難以理解的“視窗和水印”進行講解。
關注公眾號:
大資料技術派
,回覆資料
,領取1024G
資料。