如何保障數(shù)倉數(shù)據(jù)質(zhì)量?(建議收藏)
導(dǎo)讀
文|傅宇康
有贊數(shù)據(jù)報表中心為商家提供了豐富的數(shù)據(jù)指標(biāo),包括30+頁面,100+數(shù)據(jù)報表以及400+不同類型的數(shù)據(jù)指標(biāo),它們幫助商家更合理、科學(xué)地運營店鋪,同時也直接提供分析決策方法供商家使用。并且,每天在跑的底層任務(wù)和涉及的數(shù)據(jù)表已經(jīng)達到千級別。面對如此龐大的數(shù)據(jù)體系,作為測試如何制定質(zhì)量保障策略呢?這篇文章將從:1.有贊數(shù)據(jù)鏈路 、2.數(shù)據(jù)層測試、 3.應(yīng)用層測試、 4.后續(xù)規(guī)劃這四個方面展開。
一、有贊數(shù)據(jù)鏈路
1、數(shù)據(jù)鏈路介紹
首先介紹有贊的數(shù)據(jù)總體架構(gòu)圖:

自頂向下可以大致劃分為應(yīng)用服務(wù)層、數(shù)據(jù)網(wǎng)關(guān)層、應(yīng)用存儲層、數(shù)據(jù)倉庫,并且作業(yè)開發(fā)、元數(shù)據(jù)管理等平臺為數(shù)據(jù)計算、任務(wù)調(diào)度以及數(shù)據(jù)查詢提供了基礎(chǔ)能力。
以上對整體架構(gòu)做了初步的介紹,對于質(zhì)量把控來說,最核心的兩個部分是:數(shù)據(jù)倉庫以及數(shù)據(jù)應(yīng)用部分。因為這兩部分屬于數(shù)據(jù)鏈路中的核心環(huán)節(jié),相對于其他層級而言,日常改動也更為頻繁,出現(xiàn)問題的風(fēng)險也比較大。
二、數(shù)據(jù)層測試
1、整體概覽
首先,針對數(shù)據(jù)層的質(zhì)量保障,可以分成三個方面:數(shù)據(jù)及時性、完整性、準(zhǔn)確性。

2、 數(shù)據(jù)及時性
數(shù)據(jù)及時性,顧名思義就是測試數(shù)據(jù)需要按時產(chǎn)出。及時性重點關(guān)注的三個要素是:定時調(diào)度時間、優(yōu)先級以及數(shù)據(jù)deadline。其中任務(wù)的優(yōu)先級決定了它獲取數(shù)據(jù)計算資源的多少,影響了任務(wù)執(zhí)行時長。數(shù)據(jù)deadline則是數(shù)據(jù)最晚產(chǎn)出時間的統(tǒng)一標(biāo)準(zhǔn),需要嚴(yán)格遵守。
這三要素中,屬于“普世規(guī)則”且在質(zhì)量保障階段需要重點關(guān)注的是:數(shù)據(jù)deadline。那么我們基于數(shù)據(jù)deadline,針對及時性的保障策略就可分為兩種:
監(jiān)控離線數(shù)據(jù)任務(wù)是否執(zhí)行結(jié)束。這種方式依賴于有贊作業(yè)開發(fā)平臺的監(jiān)控告警,若數(shù)據(jù)任務(wù)在deadline時間點未執(zhí)行完成,則會有郵件、企微、電話等告警形式,通知到相應(yīng)人員。

檢查全表條數(shù)或者檢查分區(qū)條數(shù)。這種方式依賴接口自動化平臺,通過調(diào)用dubbo接口,判斷接口返回的數(shù)據(jù)指標(biāo)是否為0,監(jiān)控數(shù)據(jù)是否產(chǎn)出。

其次我們可以關(guān)注失敗、重試次數(shù),當(dāng)任務(wù)執(zhí)行過程中出現(xiàn)多次失敗、重試的異常情況,可以拋出告警讓相關(guān)人員感知。這部分的告警是對deadline告警的補充,目前在有贊作業(yè)開發(fā)平臺上也有功能集成。
3、數(shù)據(jù)完整性
數(shù)據(jù)完整性,顧名思義看數(shù)據(jù)是不是全,重點評估兩點:數(shù)據(jù)不多、數(shù)據(jù)不少。
數(shù)據(jù)不多:一般是檢查全表數(shù)據(jù)、重要枚舉值,看數(shù)據(jù)有沒有多余、重復(fù)或者數(shù)據(jù)主鍵是否唯一。
數(shù)據(jù)不少:一般是檢查全表數(shù)據(jù)、重要字段(比如主鍵字段、枚舉值、日期等),看字段的數(shù)值是否為空、為null等。
可見數(shù)據(jù)完整性和業(yè)務(wù)本身關(guān)聯(lián)度沒有那么密切,更多的是數(shù)倉表的通用內(nèi)容校驗。所以從一些基礎(chǔ)維度,我們可以將測試重點拆成表級別、字段級別兩個方向。

表級別完整性:
全表維度,通過查看全表的總行數(shù)/表大小,若出現(xiàn)表總行數(shù)/總大小不變或下降,說明表數(shù)據(jù)可能出現(xiàn)了問題。
分區(qū)維度,通過查看當(dāng)日分區(qū)表的數(shù)據(jù)行數(shù)/大小,若和之前分區(qū)相比差異太大(偏大或偏小),說明表數(shù)據(jù)可能出現(xiàn)了問題。
目前有贊元數(shù)據(jù)管理平臺已集成相關(guān)數(shù)據(jù)視圖:

字段級別完整性:
唯一性判斷:保證主鍵或某些字段的唯一性,防止數(shù)據(jù)重復(fù)導(dǎo)致和其他表join之后數(shù)據(jù)翻倍,導(dǎo)致最終統(tǒng)計數(shù)據(jù)偏大。
比如判斷ods層訂單表中的訂單號是否唯一,編寫sql:
select count(order_no),count(distinct order_no) from ods.xx_order若兩者相等,則說明order_no值是表內(nèi)唯一的;否則說明order_no表內(nèi)不唯一,表數(shù)據(jù)存在問題。
非空判斷:保證重要字段非空,防止空數(shù)據(jù)造成和表join之后數(shù)據(jù)丟失,導(dǎo)致最終統(tǒng)計數(shù)據(jù)偏少。
比如判斷ods層訂單表中的訂單號是否出現(xiàn)null,編寫sql:
select?count(*)?from?ods.xx_order?where?order_no?is?null若結(jié)果等于0,則說明order_no不存在null;若結(jié)果大于0,則說明order_no存在null值,表數(shù)據(jù)存在問題。
枚舉類型判斷:保證枚舉字段值都在預(yù)期范圍之內(nèi),防止業(yè)務(wù)臟數(shù)據(jù),導(dǎo)致最終統(tǒng)計結(jié)果出現(xiàn)遺漏/多余的數(shù)據(jù)類型。
比如判斷ods層訂單表中的shop_type字段中所有枚舉值是否符合預(yù)期,編寫sql:
select shop_type from ods.xx_order group by shop_type分析查詢結(jié)果是否滿足預(yù)期,確保不會出現(xiàn)遺漏/多余的枚舉類型。
數(shù)據(jù)有效性判斷:判斷數(shù)據(jù)格式是否滿足預(yù)期,防止字段的數(shù)據(jù)格式不正確導(dǎo)致數(shù)據(jù)統(tǒng)計的錯誤以及缺失。常見的有日期格式y(tǒng)yyymmdd。
一旦出現(xiàn)數(shù)據(jù)完整性問題,對數(shù)據(jù)質(zhì)量的影響很大。所以完整性策略更適用于ods層,因為我們更期望從源頭發(fā)現(xiàn)并解決數(shù)據(jù)不合理問題,及時止損,避免臟數(shù)據(jù)進入下游之后,數(shù)據(jù)污染擴大。
另外,我們看到完整性校驗內(nèi)容邏輯簡單,且比較固定,稍微進行簡單的抽象就能將其模板化。那么作為測試,我們更傾向于將數(shù)據(jù)完整性校驗做成工具。目前有贊“數(shù)據(jù)形態(tài)工具”已經(jīng)落地,下面給出我的一些思路:
針對所有表來說,普世性的規(guī)則,比如表主鍵的唯一性。
針對不同類型比如數(shù)值、String、枚舉、日期格式類型,列舉出常見的數(shù)據(jù)判斷規(guī)則。
給每項規(guī)則進行等級劃分,比如表的主鍵不唯一,記為critical。String類型字段的空值比例大于70%,記為warning。
根據(jù)表數(shù)據(jù)是否滿足上述這些規(guī)則,最終落地一份可視化報告,測試人員可根據(jù)報告內(nèi)容評估數(shù)據(jù)質(zhì)量。

4、數(shù)據(jù)準(zhǔn)確性
數(shù)據(jù)準(zhǔn)確性,顧名思義數(shù)據(jù)要“準(zhǔn)確”。“準(zhǔn)確”這個概念比較抽象,因為我們很難通過一個強邏輯性的判斷,來說明數(shù)據(jù)有多準(zhǔn),大部分都存在于感性的認(rèn)知中。所以準(zhǔn)確性測試也是在數(shù)據(jù)質(zhì)量保障過程中思維相對發(fā)散的一個方向。經(jīng)過總結(jié),我們可以從字段自身檢查、數(shù)據(jù)橫向?qū)Ρ取⒖v向?qū)Ρ取ode review等方面,去把控數(shù)據(jù)的準(zhǔn)確性,這些測試點和業(yè)務(wù)的關(guān)聯(lián)也比較密切。

4.1 自身檢查
數(shù)據(jù)自身檢查,是指在不和其他數(shù)據(jù)比較的前提下,用自身數(shù)據(jù)來檢查準(zhǔn)確的情況,屬于最基本的一種檢查。常見的自身檢查包括:檢查數(shù)值類指標(biāo)大于0、比值類指標(biāo)介于0-1范圍。這類基礎(chǔ)規(guī)則,同數(shù)據(jù)完整性,也可以結(jié)合“數(shù)據(jù)形態(tài)工具”輔助測試。
舉個例子,比如針對訂單表,支付金額必然是大于等于0,不會出現(xiàn)負(fù)數(shù)的情況,編寫sql:
select count(pay_price) from dw.dws_xx_order where par = 20211025 and pay_price<0若結(jié)果為0,說明支付金額都是大于0,滿足預(yù)期;否則若count結(jié)果大于0,說明數(shù)據(jù)存在問題。
4.2 表內(nèi)橫向數(shù)據(jù)對比
表內(nèi)橫向?qū)Ρ瓤梢岳斫鉃橥粡埍韮?nèi),業(yè)務(wù)上相關(guān)聯(lián)的兩個或多個字段,他們存在一定的邏輯性關(guān)系,那么就可以用來做數(shù)據(jù)對比。
比如針對訂單表,根據(jù)實際業(yè)務(wù)分析易得:針對任何一家店鋪的任意一款商品,都滿足訂單數(shù) >=下單人數(shù),編寫sql:
select?kdt_id,goods_id,count(order_no),count(distinct?buyer_id)?from?dw.dws_xx_orderwhere par = '20211025'group by kdt_id,goods_idhaving count(order_no)
若查詢結(jié)果不存在記錄,則說明不存在 訂單數(shù)<下單人數(shù),反向說明訂單數(shù)>=下單人數(shù),則符合預(yù)期;否則若查詢結(jié)果的記錄大于0,則不符合預(yù)期。
4.3 表間橫向數(shù)據(jù)對比
表間橫向?qū)Ρ瓤梢岳斫鉃閮蓮埍砘蚨鄰埍碇g,其中具有業(yè)務(wù)關(guān)聯(lián)或者業(yè)務(wù)含義一致的字段,可以用來做數(shù)據(jù)對比:
同類型表之間對比:針對hive里的支付表A和支付表B,里面都有支付金額字段,那么同樣維度下的 表A.支付金額 = 表B.支付金額。
多套存儲之間對比:比如有贊數(shù)據(jù)報表中心針對支付表,應(yīng)用層存儲分別用到了mysql和kylin,用作主備切換,那么相同維度下的kylin-表A.支付金額 = mysql-表B.支付金額。
多個系統(tǒng)之間對比:跨系統(tǒng)之間,比如有贊的數(shù)據(jù)報表中心和crm系統(tǒng),兩個系統(tǒng)都有客戶指標(biāo)數(shù)據(jù),那么相同維度下的數(shù)據(jù)報表中心-表A.客戶指標(biāo) = crm-表B.客戶指標(biāo)。
我們深度剖析數(shù)據(jù)橫向?qū)Ρ鹊牡讓舆壿嫞举|(zhì)就是兩張表的不同字段,進行邏輯運算符的比較,也比較容易抽象成工具。目前有贊“數(shù)據(jù)比對工具”已經(jīng)落地,下面給出我的一些思路:
輸入兩張表,分別設(shè)置兩表的主鍵。
輸入兩張表中需要對比的字段,且設(shè)置對比的運算符,比如>、=、<。
根據(jù)設(shè)置的規(guī)則,最終數(shù)據(jù)對比通過、不通過的記錄,落地一份可視化報告,測試人員可根據(jù)報告內(nèi)容評估數(shù)據(jù)質(zhì)量。

4.4 縱向數(shù)據(jù)對比
縱向?qū)Ρ染褪巧舷掠蔚臄?shù)據(jù)比較,目的是確保重要字段在上下游的加工過程中沒有出現(xiàn)問題。
比如數(shù)倉dw層存在訂單的明細(xì)表,數(shù)據(jù)產(chǎn)品dm層存在訂單數(shù)的聚合表,那么二者在相同維度下的數(shù)據(jù)統(tǒng)計結(jié)果,應(yīng)該保持一致。
4.5 code review
首先,在進行code review之前的需求評審階段,我們先要明確數(shù)據(jù)統(tǒng)計的詳細(xì)口徑是什么,下面舉兩個實際的需求例子。
需求1:(錯誤示例)統(tǒng)計時間內(nèi)店鋪內(nèi)所有用戶的支付金額。問題所在:需求描述太過于簡潔,沒有闡述清楚數(shù)據(jù)統(tǒng)計的時間維度以及過濾條件,導(dǎo)致統(tǒng)計口徑不清晰,要求產(chǎn)品明確口徑。
需求2:(正確示例)有贊全網(wǎng)商家域店鋪維度的離線支付金額。支持自然日、自然周、自然月。統(tǒng)計時間內(nèi),所有付款訂單金額之和(剔除抽獎拼團、剔除禮品卡、剔除分銷供貨訂單)。
明確需求之后,下面詳細(xì)介紹code review的一些常見關(guān)注點:
1)關(guān)聯(lián)關(guān)系 & 過濾條件
關(guān)聯(lián)表使用 outer join 還是 join,要看數(shù)據(jù)是否需要做過濾。
關(guān)聯(lián)關(guān)系 on 字句中,左右值類型是否一致。
關(guān)聯(lián)關(guān)系如果是1:1,那么兩張表的關(guān)聯(lián)鍵是否唯一。如果不唯一,那么關(guān)聯(lián)會產(chǎn)生笛卡爾導(dǎo)致數(shù)據(jù)膨脹。
where 條件是否正確過濾,以上述需求為例子,關(guān)注sql中是否正確剔除抽獎拼團、禮品卡和分銷供貨訂單。

2)指標(biāo)的統(tǒng)計口徑處理
數(shù)據(jù)指標(biāo)的統(tǒng)計涉及到兩個基本概念:
可累加指標(biāo):比如支付金額,瀏覽量等,可以通過簡單數(shù)值相加來進行統(tǒng)計的指標(biāo),針對這類指標(biāo),sql中使用的函數(shù)一般是sum。
不可累加指標(biāo):比如訪客數(shù),不能通過簡單相加,而是需要先去重再求和的方式進行統(tǒng)計,針對這類指標(biāo),sql中一般使用count(distinct )。

3)insert插入數(shù)據(jù)
是否支持重跑。等價于看插入時是否有overwrite關(guān)鍵字,如果沒有該關(guān)鍵字,重跑數(shù)據(jù)(多次執(zhí)行該工作流)時不會覆蓋臟數(shù)據(jù),而是增量往表插入數(shù)據(jù),進而可能會導(dǎo)致最終數(shù)據(jù)統(tǒng)計翻倍。
插入的數(shù)據(jù)順序和被插入表結(jié)構(gòu)順序是否完全一致。我們要保證數(shù)據(jù)字段寫入順序沒有出錯,否則會導(dǎo)致插入值錯亂。

三、應(yīng)用層測試
1、整體概覽

基本的前端頁面 + 服務(wù)端接口測試,和一般業(yè)務(wù)測試關(guān)注點是一致的,不再贅述。本篇重點展開“數(shù)據(jù)應(yīng)用“測試需要額外關(guān)注的地方。
2、 降級策略
在頁面新增數(shù)據(jù)表的時候,需求、技術(shù)評審階段確認(rèn)是否需要支持“藍(lán)條”的功能,屬于“測試左移”。
藍(lán)條介紹:有贊告知商家離線數(shù)據(jù)尚未產(chǎn)出的頁面頂部藍(lán)條,其中的“產(chǎn)出時間” = 當(dāng)前訪問時間 +2小時,動態(tài)計算得到。


測試比率類指標(biāo)時,關(guān)注被除數(shù) = 0 的特殊場景。在后端code review、測試頁面功能階段,關(guān)注該點。目前有贊針對這種情況,前端統(tǒng)一展示的是“-”。

3、 主備策略
遇到有主備切換策略時,測試過程中注意數(shù)據(jù)正常雙寫,且通過配置,取數(shù)時能在主備數(shù)據(jù)源之間切換。

4、 數(shù)據(jù)安全
關(guān)注數(shù)據(jù)查詢的權(quán)限管控,重點測試橫向越權(quán)、縱向越權(quán)的場景。
四、后續(xù)規(guī)劃
目前在實際項目的數(shù)據(jù)準(zhǔn)確性對比中,數(shù)據(jù)對比工具因為暫不支持sql函數(shù),所以只能代替50%的手工測試,一些復(fù)雜的橫向和縱向數(shù)據(jù)對比還是需要編寫sql。后續(xù)計劃支持sum、count、max、min等sql函數(shù),把工具覆蓋范圍提升到75%以上,大大降低數(shù)據(jù)對比的成本。
目前“數(shù)據(jù)形態(tài)報告”、“數(shù)據(jù)對比工具”更多的運用項目測試當(dāng)中,后續(xù)計劃將形態(tài)檢查和數(shù)據(jù)對比做成線上巡檢,將自動化和數(shù)據(jù)工具相結(jié)合,持續(xù)保障數(shù)倉表的質(zhì)量。
目前針對sql code review的方式主要靠人工,我們計劃把一些基礎(chǔ)的sql檢查,比如insert into檢查,join on條件的唯一性檢查、字段插入順序檢查等作成sql靜態(tài)掃描,整合到大數(shù)據(jù)測試服務(wù)中,并且賦能給其他業(yè)務(wù)線。
