Flink - 6 個面試高頻實(shí)戰(zhàn)問題

一.前言

  1. 架構(gòu)設(shè)計(jì)的能力:在實(shí)時數(shù)倉的分層設(shè)計(jì)中,具體的分層設(shè)計(jì)方案是怎樣的?和離線數(shù)倉又有什么區(qū)別?你設(shè)計(jì)的實(shí)時數(shù)倉是怎么兼顧時效性和通用性的?

  2. 架構(gòu)設(shè)計(jì)的能力:你們公司的實(shí)時數(shù)倉用到的維表都有哪些類型?分別是通過什么樣的方式構(gòu)建的?

  3. 架構(gòu)設(shè)計(jì)的能力:你碰到過哪些數(shù)據(jù)傾斜的問題,又是怎么緩解或避免數(shù)據(jù)傾斜問題的?

  4. 架構(gòu)設(shè)計(jì)的能力:你一般是將實(shí)時數(shù)據(jù)存儲到哪里提供對外服務(wù)?為什么這么選擇?flink 寫入的鏈路是怎樣的,遇到過什么坑嘛?

  5. 數(shù)據(jù)保障的能力:你們公司在遇到大促時是怎么估算實(shí)時任務(wù)資源的,有沒有成體系的方案可以參考?

  6. 解決問題的能力:ValueState 和 MapState 各自適合的應(yīng)用場景?

二.在實(shí)時數(shù)倉的分層設(shè)計(jì)中,具體的分層設(shè)計(jì)方案是怎樣的?和離線數(shù)倉又有什么區(qū)別?你設(shè)計(jì)的實(shí)時數(shù)倉是怎么兼顧時效性和通用性的?

(1) 思路:

  1. 陳述事實(shí):離線數(shù)倉的分層設(shè)計(jì)的目標(biāo)以及一般的設(shè)計(jì)方式是怎樣的?

  2. 分析差異:實(shí)時數(shù)倉和離線數(shù)倉的核心區(qū)別是怎樣的?(只有我們準(zhǔn)確的識別出這個區(qū)別,才能對實(shí)時數(shù)倉的分層設(shè)計(jì)有更準(zhǔn)確的理解)

  3. 分析差異:構(gòu)建實(shí)時數(shù)倉肯定會參考離線數(shù)倉構(gòu)建方法,但是如果實(shí)時數(shù)倉按照離線數(shù)倉分層設(shè)計(jì)去做會存在什么問題?

  4. 解決方案:實(shí)時數(shù)倉怎么分層設(shè)計(jì)才能兼顧時效性和通用性?

(2) 答案:

1. ? 離線數(shù)倉的分層設(shè)計(jì)的目標(biāo)以及一般的設(shè)計(jì)方式是怎樣的?

  • 清晰數(shù)據(jù)結(jié)構(gòu):每一個數(shù)據(jù)分層都有它的作用域,這樣我們在使用表的時候能更方便地定位和理解。源系統(tǒng)間存在復(fù)雜的數(shù)據(jù)關(guān)系,比如客戶信息同時存在于核心系統(tǒng)、信貸系統(tǒng)、理財系統(tǒng)、資金系統(tǒng),取數(shù)時該如何決策呢?數(shù)據(jù)倉庫會對相同主題的數(shù)據(jù)進(jìn)行統(tǒng)一建模,把復(fù)雜的數(shù)據(jù)關(guān)系梳理成條理清晰的數(shù)據(jù)模型,使用時就可避免上述問題了。

  • 數(shù)據(jù)血緣追蹤:簡單來講可以這樣理解,我們最終給業(yè)務(wù)呈現(xiàn)的是一能直接使用的業(yè)務(wù)表,但是它的來源有很多,如果有一張來源表出問題了,我們希望能夠快速準(zhǔn)確地定位到問題,并清楚它的危害范圍。

  • 數(shù)據(jù)復(fù)用,減少重復(fù)開發(fā):規(guī)范數(shù)據(jù)分層,開發(fā)一些通用的中間層數(shù)據(jù),能夠減少極大的重復(fù)計(jì)算。數(shù)據(jù)的逐層加工原則,下層包含了上層數(shù)據(jù)加工所需要的全量數(shù)據(jù),這樣的加工方式避免了每個數(shù)據(jù)開發(fā)人員都重新從源系統(tǒng)抽取數(shù)據(jù)進(jìn)行加工。通過匯總層的引人,避免了下游用戶邏輯的重復(fù)計(jì)算, 節(jié)省了用戶的開發(fā)時間和精力,同時也節(jié)省了計(jì)算和存儲。極大地減少不必要的數(shù)據(jù)冗余,也能實(shí)現(xiàn)計(jì)算結(jié)果復(fù)用,極大地降低存儲和計(jì)算成本。

  • 把復(fù)雜問題簡單化:將一個復(fù)雜的任務(wù)分解成多個步驟來完成,每一層只處理單一的步驟,比較簡單和容易理解。而且便于維護(hù)數(shù)據(jù)的準(zhǔn)確性,當(dāng)數(shù)據(jù)出現(xiàn)問題之后,可以不用修復(fù)所有的數(shù)據(jù),只需要從有問題的步驟開始修復(fù)。

  • 屏蔽原始數(shù)據(jù)、業(yè)務(wù)的影響:業(yè)務(wù)或系統(tǒng)發(fā)生變化時,不必改一次業(yè)務(wù)就需要重新接入數(shù)據(jù)。提高數(shù)據(jù)穩(wěn)定性和連續(xù)性。并且源頭系統(tǒng)可能極為繁雜,而且表命名、字段命名 、字段含義等可能五花八門,通過數(shù)倉層來規(guī)范和屏蔽所有這些復(fù)雜性,保證下游數(shù)據(jù)用戶使用數(shù)據(jù)的便捷和規(guī)范。如果源頭系統(tǒng)業(yè)務(wù)發(fā)生變更,相關(guān)的變更由數(shù)倉層來處理,對下游用戶透明,無須改動下游用戶的代碼和邏輯。數(shù)據(jù)倉庫的可維護(hù)性:分層的設(shè)計(jì)使得某一層的問題只在該層得到解決,無須更改下一層的代碼和邏輯。

良好的數(shù)倉分層設(shè)計(jì)可以更好地組織和存儲數(shù)據(jù),以便在性能、成本、效率和質(zhì)量之間取得最佳平衡!

2. ? 實(shí)時數(shù)倉和離線數(shù)倉的核心區(qū)別是怎樣的?

實(shí)時數(shù)倉相比離線數(shù)倉的特點(diǎn)其實(shí)就兩個字:實(shí)時。具體體現(xiàn)在:

  • 產(chǎn)出速度比離線數(shù)倉快:離線 dwd,ads 通常都是小時、天延遲產(chǎn)出數(shù)據(jù);相同的數(shù)據(jù)在實(shí)時數(shù)倉中,dwd 層常常是毫秒級別產(chǎn)出數(shù)據(jù),ads 層常常是分鐘級別產(chǎn)出數(shù)據(jù)。

  • 數(shù)據(jù)時間粒度比離線數(shù)倉細(xì):離線數(shù)據(jù)的時間粒度通常都是小時、天粒度,比如 ads 層計(jì)算 1 天的 GMV;實(shí)時數(shù)據(jù),相同的 GMV 數(shù)據(jù)在實(shí)時數(shù)倉中,ads 數(shù)據(jù)聚合粒度通常為 1min 級別,比如當(dāng)天實(shí)時GMV,實(shí)時的 ads 將會計(jì)算出 1440(1 天 1440 分鐘)個點(diǎn)的數(shù)據(jù),每一個點(diǎn)的結(jié)果都是當(dāng)天 0 點(diǎn)到當(dāng)前這一分鐘的 GMV 總額。

3. ? 構(gòu)建實(shí)時數(shù)倉肯定會參考離線數(shù)倉構(gòu)建方法,但是如果實(shí)時數(shù)倉按照離線數(shù)倉分層設(shè)計(jì)去做會存在什么問題?

如果你按照離線數(shù)倉分層方案去設(shè)計(jì)實(shí)時數(shù)倉分層后,并且嘗試之后你就會發(fā)現(xiàn)實(shí)時數(shù)倉分層不適合特別多,因?yàn)椋?/p>

  • 分層太多,產(chǎn)出速度必然減慢 舉例:ods -> dwd -> dws(1min 窗口)-> dws(1min 窗口)-> ads(1min 窗口)。這樣 ads 層數(shù)據(jù)產(chǎn)出延遲肯定在 3 min 以上。

  • 分層太多,實(shí)時數(shù)據(jù)粒度又細(xì),多種粒度的 dws 的數(shù)據(jù)量基本一樣,不如不建。舉例:ods -> dwd -> dws1(uid\page\style\1min 粒度)-> dws2(uid\page\1min 粒度)-> ads(uid 1min 粒度),因?yàn)橐粋€用戶在 1min 內(nèi)發(fā)生的行為很少,你可能會發(fā)現(xiàn) dws1\dws2\ads 的 QPS(流量)都差不多;而離線適合多分層的原因在于離線通常都是 1 天的粒度,所以分這幾層的數(shù)據(jù)量是會有驟減的,因此離線數(shù)倉分多層是有價值的。

4. ? 實(shí)時數(shù)倉怎么分層設(shè)計(jì)才能兼顧時效性和通用性?

綜合前面幾個問題的答案,實(shí)時數(shù)倉分層不宜特別多。建議:

  • 如果數(shù)據(jù)量不大,建立實(shí)時數(shù)倉只構(gòu)建 ods -> dwd 就足夠使用。ods -> dwd 是為了字段標(biāo)準(zhǔn)化,通用化,然后后面把 dwd 層導(dǎo)入到 OLAP 中進(jìn)行查詢使用;或者建立 ads 層,ads 層直接消費(fèi) dwd,這樣時效性也可以得到保障。

  • 如果數(shù)據(jù)量大,可以嘗試進(jìn)行 dws 聚合,聚合之后根據(jù)數(shù)據(jù)量(流量)縮減的實(shí)際效果來評估是否需要建立此 dws。

三.你們公司的實(shí)時數(shù)倉用到的維表都有哪些類型?分別是通過什么樣的方式構(gòu)建的?

(1) 思路:

  1. 描述現(xiàn)狀:我們通常以為的實(shí)時數(shù)倉的實(shí)時維表是什么樣的?

  2. 場景分析:一般實(shí)時數(shù)倉中的維表應(yīng)用的場景都有哪些?

  3. 解決方案:針對這些場景,我們有哪些解決方案去構(gòu)建實(shí)時維表?

(2) 答案:

  1. ? 我們通常以為的實(shí)時數(shù)倉的實(shí)時維表是什么樣的?

很多小伙伴對于實(shí)時數(shù)倉的維表理解都是實(shí)時維表一定要實(shí)時。但是這個想法不是非常的全面,具體實(shí)時維表怎樣構(gòu)建還是需要看場景。

  1. ? 一般實(shí)時數(shù)倉中的維表應(yīng)用的場景都有哪些?

一般的實(shí)時數(shù)倉中的維表按照使用場景可以分為兩類。

  • 緩慢變化維度的維表:比如用戶畫像,包含年齡、性別等維度的數(shù)據(jù),其實(shí)很長時間用戶的維度的變化都不明顯。舉個例子,當(dāng)已經(jīng)判定一個用戶的年齡在 18-25 之間時,其實(shí)基本上這個維度后續(xù)很長時間內(nèi)就不會發(fā)生改變了?;谶@個特點(diǎn),其實(shí)實(shí)時任務(wù)訪問 t-2\t-1 或者實(shí)時構(gòu)建的維表的差異是不大的,訪問 t-2 和實(shí)時的維表產(chǎn)出的數(shù)據(jù)質(zhì)量幾乎是一樣的,所以基于維表構(gòu)建成本考慮的話,在實(shí)時數(shù)倉中,這類維表可以訪問 t-1\t-2 的維表數(shù)據(jù)。

  • 實(shí)時生成維度的維表:比如用戶發(fā)生購買行為時,這個訂單的維度信息。訂單一般都是隨著購買行為的發(fā)生而生成的,所以其維度信息也需要實(shí)時的構(gòu)建生成,從而滿足其他任務(wù)能夠?qū)崟r獲取到這個訂單的維度信息?;谶@個特點(diǎn),這種維表只能進(jìn)行實(shí)時構(gòu)建。

  1. ? 針對這些場景,我們有哪些解決方案去構(gòu)建實(shí)時維表?
  • ? 緩慢變化維度的維表:

  • a. 應(yīng)用場景:比如畫像類維表,一般畫像類基本很少發(fā)生變化,比如性別、年齡區(qū)間等,所以這類在實(shí)時數(shù)倉中常常是訪問 t-1 維表數(shù)據(jù)的就足夠使用

  • b. 常用存儲介質(zhì):redis,hbase,mysql

  • c. 維表構(gòu)建方式:一般維表數(shù)據(jù)都存儲在 hive 中,可以使用同步工具(比如 Apache SeaTunnel)定時調(diào)度(比如 Apache DolphinScheduler)將 hive 中的數(shù)據(jù)導(dǎo)入 redis,hbase,mysql 中

  • ? 實(shí)時生成維度的維表:

  • a. 應(yīng)用場景:維度實(shí)時發(fā)生更新的,這類在實(shí)時數(shù)倉中需要訪問最新的維度數(shù)據(jù)

  • b. 常用存儲介質(zhì):redis,hbase,mysql

  • c. 維表構(gòu)建方式:這種實(shí)時的維度數(shù)據(jù)一般是實(shí)時生成,存儲在原始日志中,比如常見存儲在 Kafka 這類消息隊(duì)列中,可以通過 Flink 消費(fèi)原始日志,然后實(shí)時構(gòu)建維度數(shù)據(jù)寫入 redis,hbase,mysql 中

四.你碰到過哪些數(shù)據(jù)傾斜的問題,又是怎么緩解或避免數(shù)據(jù)傾斜問題的?

  1. ? 業(yè)務(wù)數(shù)據(jù)本身的特點(diǎn)導(dǎo)致傾斜:
  • 場景:拿計(jì)算直播間的同時在線觀看用戶數(shù)來說,大 v 直播間的人數(shù)會比小直播間的任務(wù)多幾個量級,因此如果計(jì)算一個直播間的數(shù)據(jù)需要注意這種業(yè)務(wù)數(shù)據(jù)傾斜的特點(diǎn)

  • 解決方案:計(jì)算這種數(shù)據(jù)時,我們可以先按照直播間 id 將數(shù)據(jù)進(jìn)行打散,如下 SQL 案例所示(DataStream 也是相同的解決方案),內(nèi)層打散,外層合并:

select 
 id
 , sum(bucket_uv) as uv
from (
 select 
 id
 , count(distinct uid) as bucket_uv 
 from source 
 group by
 id
 , mod(uid, 1000) -- 將大 v 分桶打散
)
group by id
  1. ? 數(shù)據(jù)任務(wù)處理時參數(shù)\代碼處理邏輯導(dǎo)致傾斜:
  • 場景:比如有時候雖然用戶已經(jīng)按照 key 進(jìn)行分桶計(jì)算,但是【最大并發(fā)度】設(shè)置為 150,【并發(fā)度】設(shè)置為 100,會導(dǎo)致 keygroup 在 sub-task 的劃分不均勻(其中 50 個 sub-task 的 keygroup 為 2 個,剩下的 50 個 sub-task 為 1 個)導(dǎo)致數(shù)據(jù)傾斜。

  • 解決方案:設(shè)置合理的【最大并發(fā)度】【并發(fā)度】,【最大并發(fā)度】最好為【并發(fā)度】的倍數(shù)關(guān)系,比如【最大并發(fā)度】1024,【并發(fā)度】512

  1. ? 我已經(jīng)設(shè)置【數(shù)據(jù)分桶打散】+【最大并發(fā)為并發(fā) n 倍】,為啥還出現(xiàn)數(shù)據(jù)傾斜?
  • 場景:你的【數(shù)據(jù)分桶】和【最大并發(fā)數(shù)】之間可能是不均勻的。因?yàn)?Flink 會將 keyby 的 key 拿到之后計(jì)算 hash 值,然后根據(jù) hash 值去決定發(fā)送到那個 sub-task 去計(jì)算。這是就有可能出現(xiàn)你的【數(shù)據(jù)分桶】key 經(jīng)過 hash 計(jì)算完成之后,并不能均勻的發(fā)到所有的 keygroup 中。比如【最大并發(fā)數(shù)】4096,【數(shù)據(jù)分桶】key 只有 1024 個,那么這些數(shù)據(jù)必然最多只能到 1024 個 keygroup 中,有可能還少于 1024,從而導(dǎo)致剩下的 3072 個 keygroup 沒有任何數(shù)據(jù)

  • 解決方案:其實(shí)可以利用【數(shù)據(jù)分桶】key 和【最大并行度】兩個參數(shù),在 keyby 中實(shí)現(xiàn)和 Flink key hash 選擇 keygroup 的算法一致的算法,在【最大并發(fā)數(shù)】4096,【數(shù)據(jù)分桶】為 4096 時,做到分桶值為 1 的數(shù)據(jù)一定會發(fā)送到 keygroup1 中,2 一定會發(fā)到 keygroup2 中,從而緩解數(shù)據(jù)傾斜。

五.你一般是將實(shí)時數(shù)據(jù)存儲到哪里提供對外服務(wù)?有沒有標(biāo)準(zhǔn)的數(shù)據(jù)服務(wù)方式?

很多小伙伴都能提到我們是將數(shù)據(jù)寫入到 ClickHouse,Doris,MySQL 提供服務(wù)的。

但是其實(shí)這個問題是聚焦于是否有規(guī)范的數(shù)據(jù)服務(wù)方式。這里的規(guī)范的數(shù)據(jù)服務(wù)方式怎么理解呢?

博主這里舉一個需求案例:

電商場景中需要要給商家出一個實(shí)時 GMV 的數(shù)據(jù),這個數(shù)據(jù)服務(wù)的整體鏈路實(shí)時數(shù)倉 -> 后端 -> 前端。

那么實(shí)時數(shù)倉就是數(shù)據(jù)的提供方,后端就是數(shù)據(jù)的使用方。

  1. ? 后端作為數(shù)據(jù)的使用方來說,后端期望的能達(dá)到的最好的數(shù)據(jù)服務(wù)方式就是實(shí)時數(shù)倉能提供一個 RPC、HTTP 接口給我,后端只需要把商家 ID 傳進(jìn)去,這個接口就能把商家的實(shí)時 GMV 數(shù)據(jù)給我。

  2. ? 實(shí)時數(shù)倉作為數(shù)據(jù)的提供方來說,很多數(shù)據(jù)開發(fā)同學(xué)都只具備數(shù)據(jù)開發(fā)的能力,不具備提供 RPC、HTTP 接口的能力。

那么為了解決上面這個實(shí)時數(shù)倉和后端之間數(shù)據(jù)服務(wù)的問題。就誕生了阿里的那套 OneService 能力。數(shù)據(jù)開發(fā)同學(xué)可以通過簡單的拖拽就能生成一個 RPC、HTTP 的接口提供給后端進(jìn)行使用,從而打通了數(shù)據(jù)服務(wù)化這個流程。

博主這里找了一篇關(guān)于快手的 OneService 體系的設(shè)計(jì)文章,小伙伴萌感興趣可以進(jìn)行參考:

六.你們公司在遇到大促時是怎么估算實(shí)時任務(wù)資源的,有沒有成體系的方案可以參考?

看到很多小伙伴的回答就是: 能多要資源就多要。

但是其實(shí)如果我們能對資源預(yù)估有一個成體系、有數(shù)據(jù)支撐的方案在向 Sre 要資源時是更有說服力的。

一般有 3 種思路去成體系預(yù)估資源:

  1. ? 目前在線任務(wù)的資源占用情況評估:
  • 適用場景:目前存量(在線)任務(wù)要在大促中使用時的場景。

  • 舉例:比如歷史大促時,流量是 n,資源會用 x,今年預(yù)估流量最大是 2n,則資源可以認(rèn)為也是 2x 就足夠。

  • 預(yù)估的準(zhǔn)確率

  1. ? 按照目前很多云廠商提供的標(biāo)準(zhǔn)評估:
  • 適用場景:大促新開發(fā)的任務(wù),并且沒有之前的經(jīng)驗(yàn)可以借鑒的場景。

  • 舉例:比如我們的 dwd 任務(wù)(簡單業(yè)務(wù)),一般就 1CU 處理 1w qps 數(shù)據(jù),復(fù)雜的清洗可能流量會講到更低;dws,ads 任務(wù)(復(fù)雜任務(wù))一般就 1CU 處理 5k qps 數(shù)據(jù);涉及到訪問外部接口時,則要使用訪問外部接口的 qps / 接口請求時延評估。

  • 預(yù)估準(zhǔn)確率。

    這些標(biāo)準(zhǔn)都是云廠商經(jīng)過無數(shù)的測試、壓測得到的,大家可以參考。

圖片
  1. ? 新模塊、新任務(wù)評估:
  • 適用場景:大促新開發(fā)的任務(wù),之前的經(jīng)驗(yàn)可以借鑒的場景。

  • 舉例:比如按照歷史大促情況來看,一個模塊、一類任務(wù)的處理能力。比如分模塊來說,歷史經(jīng)驗(yàn) 1 個模塊基本需要 n cu(云廠商 1cu = 1core 4GB),當(dāng)前有 5 個模塊,則大致需要 5n cu;又比如分任務(wù)類型來說,歷史經(jīng)驗(yàn) dwd 可以達(dá)到 1CU x qps,dws、ads 可以到達(dá) 1CU y qps,根據(jù)需求來看總共 3 dwd,每個 dwd 2x qps,5 ads,每個 ads 3y qps,則 dwd 總共需要 6CU,ads 總共需要 15CU

  • 預(yù)估準(zhǔn)確率。

    這個一般都是自己公司內(nèi)部的歷史經(jīng)驗(yàn),所以可參考性更高。

七.ValueState 和 MapState 各自適合的應(yīng)用場景?

  1. ? ValueState
  • 應(yīng)用場景:簡單的一個變量存儲,比如 Long\String 等。如果狀態(tài)后端為 RocksDB,極其不建議在 ValueState 中存儲一個大 Map,這種場景下序列化和反序列化的成本非常高,這種常見適合使用 MapState。其實(shí)這種場景也是很多小伙伴一開始使用 State 的誤用之痛,一定要避免。

  • TTL:針對整個 Value 起作用

  1. ? MapState
  • 應(yīng)用場景:和 Map 使用方式一樣一樣的

  • TTL:針對 Map 的 key 生效,每個 key 一個 TTL

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容