

那些關於後端和 Data Team 之間的故事
source link: https://blog.mz026.rocks/20200221/backend-n-etl-n-analytics
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一直以來, Codementor / Arc 總是依賴著 data 來幫我們發現/驗証各種假設。 這陣子我們使用 data 的方式漸漸有了改變。 Application 的變動、各個不同 team 流程的調整、再乘上各種人為犯錯的可能, 即使 data 的量並不多,但各種變動帶來不預期的錯誤卻越來越多。 在這篇文章裡面,我們想把我們切入問題的方式,評估的方式跟選擇的策略跟大家分享, 希望可以對於在 data 這個領域要 “登大人” 的團隊們有所幫助。
從前從前
打從我們的產品上線的第一天開始,我們總是在用各種 data 幫我們發現、驗証各種事情。 這些 data 的來源,主要分成:
- 我們各個 application DB 放的 data
- 外部 tracking tool 收下來的 data
- 有些流程會把 data 留在 3rd party 那邊,像是sales使用的服務等
整體來說, 我們的 data 的特性是量不大,但是變化很快。 我們各種 data source 的 data 格式、邏輯每天幾乎都在變化,需求也每天都在跑出來。
Stage 1
在過去很長的一段時間內,我們產出想要的數據 + 圖表的流程是:
PM/Data Analyst 寫 SQL query,搭配 metabase , Redash 等的工具把想看的數據呈現出來。
在這個階段,我們其實就有預見潛在的問題是:
- 【問題1】analytical query 是直接依賴 application db。所以當 application db schema 有任何改動(migration)的時候,analytical query 必須立刻跟上。但application這段的改動其實是很頻繁的。
- 【問題2】 application db 的 schema 是完全依照自己的需求( OLTP )而設計,這樣的schema 在分析的情境下( OLAP )未必適合。
但在這個時間點,因為團隊人數還很少,所有的溝通都很快速,所以這兩個問題都還在掌握之內。
Stage 2 – Analyst 參戰
接著,我們開始有 “對 data 細節比較不熟悉的” 夥伴加入了。同時,application data 和 3rd party 的 data 也變得比過去更複雜且多樣。於是上述的【問題2】 開始變得明顯。於是我們加入了 ETL,可以幫我們整理各種複雜的 query。這時候的 ETL 是以 減少分析端 query 的複雜度 為目標。
這時候的架構演進成這樣:
Stage 3 – 到了最近
上述的做法一直持續到了最近,我們的團隊漸漸又長大了。我們發現:
- 【問題1】開始更明顯了,application db migration 常常會有溝通漏接的狀況。再加上 query 的量變多,對於維護 query 來說,要一個一個在 UI 上 update 是一件可怕的事情。
- 【問題2】還是存在:時不時會有因為 application schema 太複雜,導致分析這端的 query 變得很複雜,甚至誤解了 data 的意思。也就是說, stage 2 希望透過 ETL 解決的問題又跑出來了。
- 【問題3】新的問題出現了:在 business logic 沒有大概動的狀況下,卻有越來越多 query 會 同時需要 分析和 ETL 同時加入才能完成,而且似乎並沒有減少的趨勢。這個對我們來說是一種警訊: 如果同一件事還是總需要兩邊來完成,是不是本來的抽象出了什麼問題呢?
- 【問題4】新的問題:開始出現了 “分析端修改了 query,卻影響到 ETL” 的狀況。這個像是 circular dependency 的東西是之前沒有預期到的。
在現行的流程下,上述的問題代表:我們可能會在沒有人發現的狀況下,根據錯誤的資訊做出決定。
雖然說各個發生的問題本身都是可以被修復的,但我們問自己: 有沒有什麼辦法可以讓 PM/Analyst 不用再等工程師,並且讓以後類似的變動再發生的時候,相對應的數據不要壞掉呢?
於是我們覺得是時候好好從頭檢視這一切了。
其中【問題1】、【問題2】對應到上圖 1、2 兩個黃色的箭頭:過去我們一直都沒有認真有技術的方式去解決。而現在我們需要的應該是:
- 【需求1】我們需要一個在分析端和application db/3rd party data 之間的中間層。 它要可以吸收各種變化,並且 expose 給分析端穩定並且直覺的介面。
而針對【問題3】、【問題4】則是對應到 3 號紅色的箭頭和灰色的虛線:過去我們沒有一個很清楚的定義分析端和 ETL 之間的角色定位 – 誰該負責什麼樣的東西。
- 【需求2】在分析端和 ETL 這邊需要有一個明確的介面,定義誰該依賴誰,還有各自負責的東西是什麼。
尋找解法
- 【需求1】我們需要一個在分析端和application db/3rd party data 之間的中間層。 它要可以吸收各種變化,並且 expose 給分析端穩定並且直覺的介面。
- 【需求2】在分析端和 ETL 這邊需要有一個明確的介面,定義誰該依賴誰,還有各自負責的東西是什麼。
針對【需求1】,我們有考慮過一些可能性:
1. 從 application 出發
由 Application 按照 domain model 定義/維護一層抽象。然後 ETL 根據這層抽象去把 data 拿下來。實現的方式之一會是:application 會把這組抽象做成 API 或者是 database 的view,藉此把內部的實作細節包裝起來。
這樣的好處是因為這些抽象是做在 application 內部的,所以測試起來很快 – 在任何的 db migration 下,application 可以透過內部的 unit test 直接確定這個介面的行為沒有壞掉。但壞處則是 application 會知道一大堆這樣的抽象。這些抽象其實是為了分析而存在的,也就是說,當分析有新的需求的時候,會要同時改動到 application 和 ETL。
2. 由 ETL 出發
Application 這端完全不知道分析端要用的抽象,而是由 ETL 來概括承受。 也就是說,由 ETL 去依賴 application 的 schema,而在每一次 schema 改動的時候,去修改內部的實作來吸收這些改動,維持分析端的一致。這樣的作法好處是當分析有新的需求,application 可以完全不用知道。但壞處則是 ETL 這邊要可以找到自動測試的方法。這在各種 data source 的來源多樣的狀況下可能不一定是件單純的事。
上述的”抽象”舉一個例子來說明的話像是:想像我們 application 內部記錄 payment 的 db schema 很複雜,因為要考慮到各種像是 isolation level 的實作細節。但在這個狀況下,其實分析端在乎的”抽象”可能只是 “某一個 user 在什麼時候付了多少錢”,而根據這個 “抽象”,分析端可以延伸出各種 business 上在乎的資訊:好比說 “付費跟時間的關係”,”付費跟 user 所在位置的關係” 等。
後來我們選擇了第二種方法。主要原因是我們覺得當 application 變動的快的時候,讓 application 維護這樣的抽象溝通成本太高了。而以目前我們 data source 的複雜度,ETL 要進行自動的測試並不是太難的事情。
針對【需求2】
在想過上面的東西之後,其實【需求2】的答案就呼之欲出了。我們想要的 “ETL跟分析端之間的介面” 其實就是上面的 “抽象”。當定義了適合的抽象作為介面之後,分析端才可以跟據這些簡單的抽象,去排列組合出各種 business insight。這邊的判斷條件是: 當 ETL expose 出某個結果給分析端的時候,我們問自己一個問題:ETL 放出的這組 data 代表了 domain model 中的哪個部份呢?如果可以順利回答的話,通常沒什麼問題。
但客觀來說,其實在很多時候這是一個要取平衡點的問題,沒有標準的答案。但可以確定的是,絕大多數的時候不會發生分析端說:”欸幫我用ETL建一個我分析要看的 table,schema 長這樣”。而是雙方應該要討論 “這個要看的東西要怎麼用現有的 domain model 來呈現”,而根據這個來建立 ETL 的 output。
如上圖,如果 ETL 抽象太靠近 Application DB 的話,理論上分析可以做出很多變化。但抽象的意義就失去了:對於分析端來說,schema 還是很複雜。並且分析端承受 application 變化的能力也變弱了。反之,如果太靠近分析端的話,對於分析端理論上 query 可以變得很簡單,也把 application 的 schema 包裝得很完整,但這時候可以用這個抽象來做的變化就少了,同時也代表分析端跟 ETL 會多出很多不必要的溝通。
Layered structure
綜合以上,新的架構變成:
首先,我們發現常見的 layered architecture 很適合來表達這個概念:每一個 layer 包裝位於自己下方的 layer,並且提供介面給上方的 layer。下方的 layer 不可以依賴上方的 layer。 在這樣的架構下,我們有一個 ETL layer 介於分析跟 application data 的中間,提供具有 domain model 意義的資訊給上方,但本身並不用知道上方是怎麼使用它的。 最上方的分析端,在”某些特殊的時機” (好比說一些還很不確定的實驗等等) 可以跳過中間的ETL這層,直接取用 application/3rd party 的 data schema,但同時也要承受 query 會不預期壞掉的風險。
其實整體來說,實作上的改動並不大,主要是透過這個過程讓我們更清楚了各種類型的 data 扮演的角色和彼此之間的關係:
- ETL 這層不應該去知道上方分析端的細節,更不該依賴它。
- ETL 放出的 data 必需要具有 domain model 的意義,而不能只具有分析的意義。
但有了這兩個規範之後,從理解整個工作流程到看懂 code 進而維護它,都因此變得直覺許多。
寫在後面
這一切其實都還是個進行中的過程,我們還是持續中過程/錯誤中去學習。 到目前為止,整理出來我們認為學到的功課有:
- 在寫程式的時候我們會有 code smell:一些小地方作為警訊,讓我們發現可能潛在的問題。而在不同 team 的溝通上,可能也有類似的 “smell”:當有一些事情好像總是很不順利,也許是背後的東西有什麼誤會。
- 如同工程的日常,大多數的事情沒有絕對的好壞,而是看我們怎麼做 trade-off。像是 “ETL 該靠 application/分析多近” 就是一個好的例子。但往往難的是 “發現 阿!原來是這個地方要做出 trade-off 阿” 的這個過程。
- 像 refactor code 一樣,在調整各種流程/架構的時候,”如果某個地方有變動,那狀況會變成怎樣” 是個評估流程/架構的改動好不好的標準。
- 也像是寫 code 一樣,domain model 會貫穿整個流程:確保所有人,包括 PM/工程師/分析師、甚至是 marketing/sales 團隊的人,對於 domain model 都有共同的認知之後,大部份的事情才有辦法順利運作。
- 不同領域的概念,有時候可以交替使用:像是一開始的遇到【問題3】其實讓人聯想到 shutgun surgery 、layered architecture 等。當這些本來很不同的概念連結起來之後,就有可能可以變成很有趣的 mental model 讓我們在思考上跳關。
Recommend
-
46
README.md cncf-k8s 這個github的repository主要是個人在學習Kubernetes的一些記錄及練習。希望在學習過程中發現到一些好的資訊與範例也可以對想要學習使用 Kuber...
-
12
閒聊 - 關於 VB.NET 的未來 2021-03-23 10:44 PM 0 896 近期在 2019 年的舊文 - 閒聊 -...
-
9
Linux Kernel 與明尼蘇達大學之間的攻防 Linux Kernel Community 與明尼蘇達大學 (UMN) 之間的事件差不多告一段落了,整理一下裡面比較重要的事件。隔壁棚
-
5
2015 烏雲峰會演講投影片 「關於 HITCON CTF 的那些事 之 Web 狗如何在險惡的 CTF 世界中存活?」 應邀以 HITCON CTF 隊長的身份到 烏雲峰會 講一下過去比賽中遇到的一些趣事順便解釋一下...
-
6
想擁抱 Alder Lake-S?關於 Intel 第 12 代 Core 桌上型處理器的那些事 Intel 多年磨一劍,再次帶來玩家期待的進化。
-
5
MangoDB:拿 PostgreSQL 當作後端的 MongoDB 相容層 在 Hacker News Daily 上看到「A truly Open Source MongoDB alternative」這個東西,在「
-
5
Nic Lin's Blog喜歡在地上滾的工程師delayed_job (https://github.com/collectiveidea/delayed_job) 使用關聯式資...
-
5
地址、ABI 與可升級合約本篇介紹地址和 ABI 之間的關係,以及要如何去和可升級合約互動
-
10
CPU Core 之間溝通的時間成本 在 Hacker News 上看到「
-
7
WordPress 打算要支援 SQLite 作為後端資料庫 目前 WordPress 只有支援 MySQL,而昨天在
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK