上線之後才是開始。
如果一開始開發和部署沒有「喬好」環境的話,那上線的過程可是會吃一番苦頭。例如搞不清楚環境有哪些套件,只好正式環境亂裝一堆。如果每個開發工程師都用不同的套件,那正式環境會變得異常複雜。如果正式環境是分散式系統的話,狀況又會變得更複雜,需要確保每台節點都有相同的套件。現在大多人用的解法都會使用 Docker Image 來將程式和套件一起打包,這樣一來方便管理上線的版本,二來也是可以讓開發與部屬環境保持一至。
不管是原始資料、加工資料、模型什麼的,上線之後永遠會產生意外的狀況。不是資料格式不對、筆數不對、轉換方式錯誤、或是意外的預測結果,總之「有可能發生的問題就會發生」。這些意外往往是來自於資料產品層層疊疊的影響,只要一層出錯,後面就很有可能接連產生錯誤。
舉例來說,之前我們都是透過 AWS Kinesis 來接收使用者手機傳送過來的資料,後續所有 ETL、使用者報表、模型都是依據這個資料來做處理。有一天 Kinesis 在半夜斷了兩小時,少了這兩小時資料,計算每日使用者數的報表自然就發生異常、另外一張根據每日使用者人數計算存活率的報表自然也不正確、少了那兩小時的資料,針對使用者觀看影片的訓練的推薦模型自然也會受到影響。
這些異常的後續效果會比想像中還來得久以及來的難處理。例如延續上面的例子,儘管後來 Kineis 修復後資料成功進來,但是像是「過去七天使用者人數」的報表、或是「過去三十日觀看熱門影片」都會有一天的資料是「不正確」的,直到那個有問題的資料不會再被查詢之後影響才會消失。
由於壞資料的影響會留存很久,所以我們必須盡量避免壞資料進入生產環境。這時候就很推薦使用「兩階段轉換」。將處理完的結果,先放到別的地方,等資料驗證沒有問題後,再進入正式的 DB。
然而二階段轉換並不是說單純把資料放到 Staging 環境而已,以下就來說明開發 Data Pipeline 通常的做法,以及環境的區分。
ETL 的正確性涵蓋了兩部分:
所以一般來說,比較嚴謹的開發流程會是這樣子:
加入二階段轉換後最終會像這樣:
正式資料 => 正式資料處理程式 => 暫存區 => 確認資料品質 => 正式DB
當然除了放到暫存區之外,也可以直接在程式裡確認程式品質,放在同一個處理程式中:
當然當資料量大,或是需要累積多一點資料一起驗證時,還是會先落地在檢查。
由於資料產品包含許多隱私或是機敏內容,所以在安全性上一定要特別注意,這邊列幾個比較常被忽略的地方:
使用者介面:
像 Airflow Web Server ,這是是使用者觀察 job 執行的和操作的入口。雖然不能直接刪除 Job,但是仍然可以可以看到 DAG 的 Code。那如果您用的是 Jenkins ,或其他可以直接在 UI 上刪除 Job 的套件,在權限控管上更要小心。
Job Runner
Job Runner 通常是用來實際執行 ETL 程式的環境。Job Runner 由於要直接執行各式 ETL,通常會擁有比較多的權限,像是:存取 s3 bucket、存取 Database、Athena,甚至操作其他 AWS 元件等等。所以通常不會直接開放給使用者連線,而是僅開放從公司或特定內部連線存取。
我們可以從兩方面來控制:
連線管理
網路連線需要一邊管理使用者可以從哪連線,另一邊管理服務可以跟誰連線。一般來說會採取這樣的方式:
使用者 > UI > Job Runner > Database。
使用者 > UI > Metadata DB
資源權限管理
在 AWS 上很方便的就是可以透過給予機器 instance_profile 的方式來給予權限,讓 service 可以不用碰到權限管理的問題。但是另外一方面,如果我們都將 Airflow 的 UI / Job Runner 都部署在 k8s 上,要從機器來管理權限恐怕又不是那麼容易。比較理想當然是拆成 node pool,但是現實上…
一個好的程式,就不該把帳號密碼寫在裡面。如果要用到 db connection,可以從環境變數拿,或是像 Airflow 這樣從 secret manager 拿。用統一的 secret manager 拿的好處很多。除了安全之外,當連線資訊要更改時(例如有些公司規定三個月要變更密碼一次),也可以很輕鬆的替換。