時間序列資料的結構定義設計

本頁面說明在 Cloud BigTable 中儲存時間序列資料的結構定義設計概念、模式和範例。在您閱讀本頁面之前,請先熟悉 Cloud BigTable 總覽的內容。另外,您也應該熟讀設計您的結構定義一文。

不論何時,當您測量某個東西,並且同時記錄時間與測量結果時,便會建立時間序列。時間序列無所不在:

  • 當您因為電腦執行速度緩慢,而查看記憶體用量圖,您看到的就是時間序列。

  • 當您在新聞報導上查看溫度隨時間的變化時,您看到的就是時間序列。

  • 如果您從事外匯交易,在工作上需要按照美元/日元 (USD/JPY) 的 5、10 和 30 天移動平均價來繪製走勢圖,您看到的就是時間序列。

時間序列的重要性也不容忽視:

  • 時間序列可以幫助我們將資源做最佳利用、減少能源使用、儘可能減少對環境的衝擊,以及降低成本。

  • 時間序列可以幫助我們從資料中找出趨勢,讓我們可以力證過去發生的事實,然後憑藉充足的資訊預測未來的發展。

  • 在金融服務、零售、保險、物理學、化學等領域中,時間序列為某些複雜的數據分析和機器學習奠定了基礎。

本指南提供詳盡策略與逐步指引,說明如何在 Cloud BigTable 中儲存及查詢時間序列資料。

時間序列與 Cloud Bigtable

將時間序列資料儲存到 Cloud Bigtable,可說是天作之合。Cloud Bigtable 會在資料列中,將資料儲存為非結構化的資料欄;每一列都有資料列索引鍵,而資料列索引鍵會按字母順序排列。

從 Cloud Bigtable 擷取資料有兩種常用的方式:

  • 藉由指定資料列索引鍵,取得單一資料列。
  • 藉由指定資料列索引鍵範圍,取得多個資料列。

這些方法非常適合用來查詢時間序列資料,因為您需要的通常是某個特定時間範圍內的資料 (舉例來說,當天所有的市場資料,或過去 15 分鐘的伺服器 CPU 統計)。所以,就功能面而言,Cloud Bigtable 非常適合時間序列。

不過,魔鬼總是藏在細節裡。對 Cloud Bigtable 來說,魔鬼就是資料的結構定義 (資料欄與資料列索引鍵結構),設計時必須審慎小心。良好的結構定義可以帶來卓越效能和擴充性,不適當的結構定義會導致系統效能不佳。然而,沒有任何一種結構定義設計可以一體適用全部的用途。

本文的其餘部分將介紹 Cloud Bigtable 中結構定義設計的幾種模式。您可以使用這些模式設計符合您用途的理想結構定義。在列舉及解說這些結構定義設計的模式後,您可以參考下列幾個用途範例:

  • 金融市場資料
  • 伺服器指標,例如 CPU、記憶體和網路用量
  • 智慧型電表,屬於「物聯網」(或稱為 IoT) 的應用範圍

時間序列的結構定義設計模式

在 Cloud Bigtable 中,用於儲存時間序列的結構定義設計模式分為下列幾類:

  • 一般模式
  • 資料列索引鍵設計模式
  • 資料欄設計模式

一般模式

名稱務求簡短但有意義

從 Cloud Bigtable 傳輸資料時,中繼資料也會一併傳輸,這包括:

  • 資料列索引鍵
  • 資料欄系列,即用於將相關資料欄群組在一起的識別碼
  • 資料欄限定詞,即資料欄系列中的唯一名稱

因此,選用有意義並且盡量簡短的名稱非常重要,因為每個名稱的長度都會增加儲存空間與 RPC 負擔。舉例來說,您可以使用 CELL 作為簡短但有意義的縮寫名稱,而不是使用 CELLPHONE_NUMBER 作為資料欄限定詞。

資料列索引鍵設計模式

使用高窄型的資料表

在高窄型的資料表中,每列的事件數少,可能只有一個事件;而矮寬型的資料表,每列會有較大量的事件。誠如剛才所說的,高窄型的資料表最適合時間序列資料。

舉例來說,假設您每天早上都會測量菜園的溫度。這時,如果您認定一天一列很適合,那麼因為每天早上都會測量溫度,資料表便會呈現高窄樣式。請注意,時間戳記並非資料列索引鍵的第一個元素。後面將會說明,使用時間戳記作為資料列索引鍵的第一個元素,可能會造成各種問題。

資料列索引鍵 資料欄的資料
VEGGIEGARDEN#20150301 DAILY:TEMP:60.4
VEGGIEGARDEN#20150302 DAILY:TEMP:61.2
VEGGIEGARDEN#20150303 DAILY:TEMP:61.0
VEGGIEGARDEN#20150304 DAILY:TEMP:65.1
VEGGIEGARDEN#20150305 DAILY:TEMP:62.2
... ...
VEGGIEGARDEN#20150331 DAILY:TEMP:60.4

相對的,假設您想要繪製每月的溫度變化,那麼就適合使用每月一列的方式。下列範例顯示使用此方法所產生的矮寬型資料表:

資料列索引鍵 資料欄的資料
VEGGIEGARDEN#20150301 TEMP:1:60.4 TEMP:2:61.2 TEMP:3:61.0 TEMP:4:65.1 TEMP:5:62.2 ... TEMP:31:60.4

對於時間序列,通常應該使用高窄型資料表。 這有兩個原因:每一列儲存一個事件,可以更輕鬆地查詢資料。每一列儲存多個事件,總資料列大小更可能會超出建議的上限 (請參閱資料列可以很大,但不能是無限大)。

最佳做法是,您可以使用矮寬型資料表,但要避免用在「事件數量無設限」的情況。 舉例來說,如果您經常需要一次擷取整個月的事件,上述的溫度資料表便是合理的最佳做法,因為資料列的大小會受月份天數限制。

建議使用資料列,而非資料欄版本

在 Cloud Bigtable 中,資料欄可能有加上時間戳記的版本。因此,理論上可以將時間序列儲存為某資料欄的一組版本。舉例來說,如果您要每天記錄 ZXZZT 股票的收盤價,那麼您可以建立單一資料欄,儲存每天加上時間戳記的版本:

資料列索引鍵 資料欄的資料
ZXZZT STOCK:PRICE (V1 03/01/15):558.40 STOCK:PRICE (V2 03/02/15):571.34 STOCK:PRICE (V3 03/03/15):573.64 STOCK:PRICE (V4 03/04/15):573.37 STOCK:PRICE (V5 03/05/15):575.33

不過,這不是儲存這類資料的最好方式。

預設請使用新的資料列,來取代資料欄版本。 使用多列,並在每一列中儲存事件的單一版本,是呈現、理解及查詢您資料的最簡單方式。

若實際上會修改值,而對用途來說,值的歷程很重要時,使用資料欄的版本也是可以接受的。 舉例來說,假設您根據 ZXZZT 的收盤價做了一組計算,一開始誤將收盤價的資料輸入為 559.40,而非 558.40。此時,重要的可能是知道該值的歷程,免得不正確的值繼續造成其他計算錯誤。

以查詢為出發點,來設計資料列索引鍵

Cloud Bigtable 在儲存資料列時,會依資料列索引鍵的字典編纂順序排序資料列。實際上,每個資料表有一個索引,也就是資料列索引鍵。執行存取單一資料列或存取連續的資料列範圍的查詢,迅速又有效率。其他所有查詢則會掃描整個資料表,速度慢很多。掃描整個資料表,正如字面上所言,會逐一檢查資料表的每一列。在 Cloud Bigtable 中,您可以在單一資料表中儲存好幾 TB 的資料,所以整個資料表的掃描效能只會隨著系統增長而變差。

舉例來說,想建立一個資料表來儲存所有玩家的電玩分數,或許可以設計如下。

資料列索引鍵 資料欄的資料
LoL#20150301 GAME:PLAYER:Corrie GAME:WIN:false GAME:KDA:4.25
LoL#20150302 GAME:PLAYER:Jo GAME:WIN:true GAME:KDA:7.00
LoL#20150302 GAME:PLAYER:Sam GAME:WIN:true GAME:KDA:7.00
LoL#20150303 GAME:PLAYER:Corrie GAME:WIN:true GAME:KDA:9.50
Starcraft#20150303 GAME:PLAYER:Eriko GAME:WIN:true GAME:KDA:6.00

假設您要查詢這些資料,以取得「Corrie 在三月打贏幾場 LoL 遊戲?」問題的答案。根據上方所示的結構定義,您幾乎要掃描整個資料表才能回答這個問題。如果您將資料表設計如下,只要擷取特定範圍的資料列索引鍵,即可完成這項查詢:

資料列索引鍵 資料欄的資料
LoL#Corrie#20150301 GAME:WIN:false GAME:KDA:4.25
LoL#Corrie#20150303 GAME:WIN:true GAME:KDA:9.50
LoL#Jo#20150302 GAME:WIN:true GAME:KDA:7.00
LoL#Sam#20150302 GAME:WIN:true GAME:KDA:7.00
Starcraft#Eriko#20150303 GAME:WIN:true GAME:KDA:6.00

對系統的整體效能來說,選擇能簡化常用查詢的資料列索引鍵至關重要。 將您的查詢列舉出來,按重要性的順序排列,然後設計適用於這些查詢的資料列索引鍵。

找不到最適合的資料列索引鍵時,您會如何處理?舉例來說,假設查詢三月的所有 LoL 遊戲,和查詢 Corrie 在三月玩過的所有 LoL 遊戲,兩者一樣重要。上面的結構定義可以讓我們查詢 Corrie 的三月 LoL 遊戲記錄,但不能幫我們查詢三月的所有 LoL 遊戲,所以您只好先查詢所有的 LoL 遊戲,再篩選三月的遊戲。解決這問題的方法有兩個:

反正規化

  • 使用兩個資料表,每個資料表各有適合於其中一個查詢的資料列索引鍵。由於這個解決方案可讓系統保持穩定且具備擴充性,因此是個不錯的方法。

查詢與篩選

  • 繼續使用上方所示的結構定義進行查詢 (三月所有的 LoL 遊戲),由於有大量的資料列需要篩選,因此查詢作業的效能會不慎理想。通常這不會是有效的解決方法,因為這會造成系統難以擴充,還會隨著使用量的增加,讓情況更加惡化。

確保您的資料列索引鍵不會發生資源使用率不均的問題

在 Cloud Bigtable 中,最常見的時間序列問題是資源使用率不均。任何類型的資料列索引鍵,只要含有單調遞增值,就會受這個問題所影響。

簡單說,當時間序列的資料列索引鍵包括時間戳記時,所有的寫入作業都會鎖定單一節點為目標;在填滿該節點後移到叢集的下一個節點,便會造成資源使用率不均的問題。舉例來說,如果您要儲存手機的電池狀態,而您的資料列索引鍵由「BATTERY」字樣加上時間戳記所組成 (如下所示),則資料列索引鍵會永遠循序遞增。由於 Cloud Bigtable 會儲存同一伺服器節點上的相鄰資料列索引鍵,所以所有的寫入作業只會聚焦於一個節點,直到該節點寫滿,此時,寫入作業將會移到叢集的下一個節點。

資料列索引鍵 資料欄的資料
BATTERY#20150301124501001 METRIC:USER:Corrie METRIC:PERCENTAGE:98
BATTERY#20150301124501002 METRIC:USER:Jo METRIC:PERCENTAGE:54
BATTERY#20150301124501003 METRIC:USER:Corrie METRIC:PERCENTAGE:96
BATTERY#20150301124501004 METRIC:USER:Sam METRIC:PERCENTAGE:43
BATTERY#20150301124501005 METRIC:USER:Sam METRIC:PERCENTAGE:38

以下提供幾個解決這個問題的方法:

  • 欄位升級。 將資料欄資料中的欄位移到資料列索引鍵中,讓寫入作業變成不連續。

  • 加碼。 在資料列索引鍵中,加入額外計算的元素,以人為方式讓寫入作業變成不連續。

使用 Key Visualizer 工具可協助識別熱點,輕鬆排解 Cloud BigTable 的相關問題。

欄位升級

在這個範例中,您會將資料欄中的 USER 升級為資料列索引鍵的一個元素。這項變更會解決資源使用率不均的問題,因為使用者識別碼可使資料列索引鍵更均勻分散。因此,系統會分割寫入作業,使其能分散在叢集的多個節點中。

欄位升級的優點是,查詢也會更有效率,這樣的策略明顯勝出。(小) 缺點是升級後的欄位會限制查詢,如果升級的欄位不正確,就得重做一次。

資料列索引鍵 資料欄的資料
BATTERY#Corrie#20150301124501001 METRIC:PERCENTAGE:98
BATTERY#Corrie#20150301124501003 METRIC:PERCENTAGE:96
BATTERY#Jo#20150301124501002 METRIC:PERCENTAGE:54
BATTERY#Sam#20150301124501004 METRIC:PERCENTAGE:43
BATTERY#Sam#20150301124501005 METRIC:PERCENTAGE:38

加碼

在這個範例中,您會取得時間戳記的雜湊碼,然後將它除以 3;計算出餘數後,將餘數加到資料列索引鍵中。為什麼是 3?因為這會估算出叢集的節點數,進而可以妥善劃分這些節點中的活動。

加碼的優點是簡單,基本上是一個簡單的雜湊函式。缺點之一是,當您查詢時間範圍時,必須掃描多次 (每一個碼值掃描一次),然後將結果結合到自己的程式碼中。另一個缺點是,要選擇一個既可以跨節點分配活動,還可以良好運作而不受系統規模增減影響的加碼值,並不容易。由於這些缺點,加上最好使用大家可理解的資料列索引鍵,所以除非找不到方法來防止資源使用率不均,否則應避免使用加碼的方式。

資料列索引鍵 資料欄的資料
BATTERY#1#20150301124501003 METRIC:USER:Jo METRIC:PERCENTAGE:96
BATTERY#1#20150301124501004 METRIC:USER:Sam METRIC:PERCENTAGE:43
BATTERY#2#20150301124501002 METRIC:USER: Corrie METRIC:PERCENTAGE:54
BATTERY#3#20150301124501005 METRIC:USER:Sam METRIC:PERCENTAGE:38
BATTERY#3#20150301124501001 METRIC:USER:Corrie METRIC:PERCENTAGE:98

依預設,建議使用欄位升級。 幾乎在所有情況下,欄位升級都可以避免資源使用率不均,所以可以更容易設計出能協助查詢的資料列索引鍵。

請在欄位升級無法解決資源使用率不均的問題時,再使用加碼的方式。 在必須提供加碼函式的極為少見情況下,對於叢集的基礎大小,請小心不要做過多的假設。上面的範例使用加碼函式來假設叢集有 3 個節點;這項假設是安全的,因為只能擴充至有限數量的節點,而這些數量的節點可以存在於 Cloud Bigtable 叢集中。如果您可以建立一個具有上百個節點的叢集,您可能想要使用不同的加碼函式。

唯有必要時才反轉時間戳記

您可以從程式設計語言的長整數最大值 (如 Java 的 java.lang.Long.MAX_VALUE) 減去時間戳記,藉此反轉時間戳記。反轉時間戳記後,便可以設計一個資料列索引鍵,其中的最近事件會顯示在資料表的最前面,而不是最後面。如此一來,只要擷取資料表的前 N 個資料列,就可以取得 N 個最近事件。

建議您只有在最常查詢的資料是關於最近的值時,再使用反轉時間戳記的方法。 因為反轉時間戳記會讓其他所有查詢變得更繁雜,整體的結構定義也會變得棘手。

資料欄設計模式

資料列可以很大,但不能是無限大

Cloud Bigtable 中的資料列大約可包含 100 個資料欄系列和數百萬個資料欄,儲存在資料欄中的每一個值,上限皆為 100 MB。這些限制很寬,所以彈性很大。但是也不應該以為大型的資料列就是儲存資料的適當方式,所以應該盡可能將多一點資料填入每一列。請注意,擷取大值需要更多的時間和記憶體。

一般來說,資料列大小應保持約 100 MB 以下。這是原則,而不是規定,資料列可以超過 100 MB 的大小。然而,如果您有許多個超過 100 MB 的資料列,效能問題也會隨之而來。

一般來說,資料欄的值應保持約 10 MB 以下。同樣地,這是原則,而不是規定;您可以儲存超過 10 MB 的值,不過很可能會導致效能問題。

再重述一次,如果您經常使用大型資料列或大型的個別值,系統勢必出現效能問題

Cloud Bigtable 是一種鍵/值存放區,不是關聯存放區。它不支援彙整,除了單一資料列中的交易,其他交易也一概不支援。因此,最適合用於存取個別資料列中或一組連續的資料列中的資料。

這個模式會產生一個相當明顯的結果:在大多數的情況下,時間序列查詢都會存取指定一段時間內的指定資料集。因此,請務必將特定一段時間的所有資料儲存在連續的資料列中,除非這樣做會造成資源使用率不均。

另一個結果是,當您讀取某個資料列或某個資料列範圍的資料時,那些資料本身應該是有用的,照理來說,不需要將那些資料與其他資料結合使用才是。舉例來說,假設您要儲存某個購物網站上的使用者活動,而您經常需要擷取使用者最後執行的五個動作,並將這些動作顯示在側欄中。此時,您應該考慮將資料去標準化,然後將部分使用者和產品詳細資料納入最近動作的資料表中。相形之下,若是使用關聯資料庫,您很可能會將使用者 ID 和產品 ID 儲存到一個資料表中,然後聯結該資料表與個別的使用者資料表和產品資料表,來執行 SQL 查詢。

也就是說,您不需要將有關實體的每一筆資料,都包含在每一個資料列中。舉例來說,如果您要顯示使用者最近動作的資訊,您不需要儲存使用者的電話號碼或產品製造商的地址,因為您並沒有想要在側欄中顯示這類資訊。

您可以設法將資料去標準化,以滿足查詢條件,但是只要包含查詢所需的資料即可。

在單一資料欄系列中,儲存您會在單一查詢中存取的資料

單一資料欄系列中的資料欄限定詞同時具有實體和邏輯關係。一般來說,單一資料欄系列中的所有資料欄限定詞會儲存在一起,然後一起被存取、一起被快取。因此,執行存取單一資料欄系列的查詢,可能比橫跨資料欄系列的查詢更有效率。

從盡可能少的資料欄系列中擷取資料,可確保常用的查詢達到最高的效率。

請勿利用單一資料列的單元性

Cloud Bigtable 不支援交易,除了以下例外:在單一資料列上的作業為交易型。交易也所費不貲,也就是說不仰賴交易的系統,執行效能比仰賴交易的系統好。

使用時間序列時,請勿運用資料列的交易行為。 對現有資料列中的資料所做的變更,應儲存為新的個別資料列,而不是直接在現有資料列中進行變更。這個模式更容易建構,並讓您能夠維護活動的歷程,而不需要依賴資料欄版本。

結構定義設計範例

現在,您要運用結構定義設計模式,針對下列資料類型建立範例:

  • 金融市場資料
  • 伺服器指標
  • 智慧型電表 (物聯網)

注意,這些只是範例!若要找出最適合您時間序列資料的最佳結構定義,您必須考量到所要儲存的資料為何,以及預計的資料查詢頻率,然後再運用上一節中的設計模式。

金融市場資料

這個範例採用假設的股市資料訊息,提供有關一個虛構股票的資訊:

欄位 資料範例
股票代號 ZXZZT
買價 600.55
賣價 600.60
買量 500
賣量 1500
最近成交價 600.58
最近成交量 300
報價時間 12:53:32.156
交易時間 12:53:32.045
交易所 NASDAQ
成交量 89000

開始前,請先瞭解有關股市資料訊息的一些觀察:

  • 這類訊息彙整了報價資料和交易資料,這些資料基本上是分開的。

  • 股票代號數量相當龐大,有好幾千個。

  • 收到訊息的九成只與數百個股票代號相關,因為交易活躍的股票相對稀少。

  • 訊息發佈頻繁,每秒的訊息量少則幾百多則幾萬,平均每秒有數千個訊息。

  • 一般會分別查詢報價資料或交易資料,不會同時查詢兩者。

  • 一般查詢報價資料和交易資料時,會指定下列項目:

    • 交易所 (如 NASDAQ)
    • 股票代號 (如 ZXZZT)
    • 起迄時間

現在,您可以設計適合這個用途的資料表:

將相關的資料放在同一個資料表中,將不相關的資料放在不同的資料表中

  • 將報價資料儲存在一個名為 QUOTE 的資料表中。
  • 將交易資料儲存在一個名為 TRADE 的資料表中。
  • 查詢可能會包含任意的時間範圍,因此您需要在每個資料列中儲存單一訊息中的資料。

資料列可以很大,但不能是無限大

  • 每個資料列皆儲存單一訊息中的資料,因此不會引起任何大小問題。

請勿利用單一資料列的單元性

  • 每一個訊息都是獨立的,所以沒有任何問題。

名稱務求簡短但有意義

  • 為求簡單易懂,本範例使用訊息中的欄位做為名稱,但會刪除欄位的空格並將字母改為大寫。

所以您會得到下列的資料欄配置:

QUOTE 資料表範例:

資料欄的資料
MD:SYMBOL:ZXZZT MD:BID:
600.55
MD:ASK:
600.60
MD:BIDSIZE:
500
MD:ASKSIZE:
1500
MD:QUOTETIME:
1426535612156
MD:EXCHANGE:
NASDAQ

TRADE 資料表範例:

資料欄的資料
MD:SYMBOL:
ZXZZT
MD:LASTSALE:
600.58
MD:LASTSIZE:
300
MD:TRADETIME:
1426535612045
MD:EXCHANGE:
NASDAQ
MD:VOLUME:
89000

接下來,設計資料列索引鍵:

使用高窄型資料表

  • 每個資料列都會儲存一個訊息中的資料,這會產生大量又相當窄的資料列。

建議使用資料列,而非資料欄版本

  • 只在值不正確的例外情況下,才使用資料欄版本。

以查詢為出發點,來設計資料列索引鍵

  • QUOTETRADE 資料列索引鍵可以採用相同的格式。
  • 由於這是時間序列,因此在預設情況下,您可以認定 QUOTETIME 屬於資料列索引鍵的一部分。
  • 如果要依指定起迄時間內的交易所和股票代號進行查詢,請使用 EXCHANGESYMBOLQUOTETIME 的值。
  • 因此,您會升級 EXCHANGE (6 個字元的代號;交易所代號若不足 6 個字元,將會在右邊補上空格)、SYMBOL (5 個字元的代號;股票代號若不足 5 個字元,將會在右邊補上空格) 和 QUOTETIME (13 位數字)。為 EXCHANGESYMBOL 補上空格,可確保資料列索引鍵的每一個組成部分都位於可預測的位置。
  • 這些值一起擷取時,資料列索引鍵將會是 EXCHANGE 加上 SYMBOL 再加上 QUOTETIME 的格式,例如 NASDAQ#ZXZZT#1426535612156

確保您的資料列索引鍵不會發生資源使用率不均的問題

  • EXCHANGESYMBOL 放在資料列索引鍵的最前頭位置,就會分配活動。
  • 由於九成的訊息都是集中在數百個股票代號上,所以以會有資源使用率不均的風險,執行進一步的變更之前,請務必先對系統進行壓力測試。如果這種集中現象導致效能不佳,您可以運用加碼方法,以更有效的方式拆分活動。

唯有必要時才反轉時間戳記

  • 在這個情況下,您不會反轉時間戳記,因為查詢並非一律需要存取最新的資料。

在完成這個設計練習之後,會產生下列資料表:

QUOTE 資料表範例:

資料列索引鍵 資料欄的資料
NASDAQ#ZXZZT#1426535612156 MD:SYMBOL:
ZXZZT
MD:BID:
600.55
MD:ASK:
600.60
MD:BIDSIZE:
500
MD:ASKSIZE:1
500
MD:QUOTETIME:
1426535612156
MD:EXCHANGE:
NASDAQ

TRADE 資料表範例:

資料列索引鍵 資料欄的資料
NASDAQ#ZXZZT#1426535612045 MD:SYMBOL:
ZXZZT
MD:LASTSALE:
600.58
MD:LASTSIZE:
300
MD:TRADETIME:
1426535612045
MD:EXCHANGE:
NASDAQ
MD:VOLUME:
89000

這些資料表會以每天幾億個資料列的速率增長,而 Cloud Bigtable 可以輕而易舉地處理這種情況。

伺服器指標

下列的範例使用假設的伺服器監控系統從大量的機器中收集多種不同的指標 (如每核心 CPU、記憶體和磁碟用量)。在這個範例中,您會對結構定義執行多次疊代作業。

對於資料,您可以假設如下:

  • 每台機器收集 100 項指標。
  • 從 100,000 台機器中收集指標。
  • 每 5 秒收集指標一次。
  • 典型的查詢為下列其中一項:

    • 指定起迄時間、指定機器的指標
    • 整批機器的最新指標

根據該用途,您可以這樣設計資料表:

疊代作業 1

將相關的資料放在同一個資料表中,將不相關的資料放在不同的資料表中

  • 將指標資料儲存在一個名稱為 METRIC 的資料表中。
  • 指標有幾個類別,可使用適當的資料欄系列,將這些指標分組。
  • 查詢可能會包含任意的時間範圍,因此您需要讓每個資料列儲存指定時間中某個機器的一組指標。

資料列可以很大,但不能是無限大

  • 每一個資料列儲存一組指標,這不會引起任何大小問題。

請勿利用單一資料列的單元性

  • 在我們的結構定義設計中,您不會依賴資料列的單元性。

名稱務求簡短但有意義

  • 為求簡單易懂,您將使用指標中的欄位名稱做為資料欄限定詞名稱,但會刪除欄位的空格並將字母改為大寫。

所以您會得到下列的資料欄配置:

資料欄的資料
METRIC:
HOSTNAME:
server1.bbb.com
METRIC:
CPU/CPU1_USR:
0.02
METRIC:
CPU/CPU1_NICE:
0.00
... METRIC:
IO/BLK_READ:
253453634
METRIC:
MIO/BLK_WRTN:
657365234

接下來,根據模式設計資料列索引鍵:

使用高窄型資料表

  • 資料表中的每個資料列均會儲存一台機器的一組指標,這會產生非常大量的資料列。

建議使用資料列,而非資料欄版本

  • 不會使用資料欄版本。

以查詢為出發點,來設計資料列索引鍵

  • 由於這是時間序列,所以請將時間戳記 TS 包含在資料列索引鍵中。
  • 為了擷取指定機器在指定起迄時間內的指標,您將使用 HOSTNAME 加上 TS 來擷取資料列範圍。
  • 擷取整批機器的最新指標是十分複雜的作業。您不能只是反轉時間戳記及掃描 N 個資料列,因為這樣的做法無法保證系統會擷取清單中的每一台機器。

現在,您在設計資料列索引鍵上遇到問題了。解決之道就是去正規化。您會另外建立一個資料表來儲存最新的指標版本,其名稱為 CURRENT_METRIC,當您更新 METRIC 時,也會一併更新這個資料表。如此一來,更新某台機器的現有指標時,只要覆寫該機器的資料列即可。

接下來,對原始設計執行疊代作業:

疊代作業 2

將相關的資料放在同一個資料表中,將不相關的資料放在不同的資料表中

  • 將指標資料儲存在一個名稱為 METRIC 的資料表中。
  • 將最新版本的指標儲存在一個名稱為 CURRENT_METRIC 的資料表中。
  • 其他資訊維持與疊代作業 1 相同。

資料列可以很大,但不能是無限大

  • 維持與疊代作業 1 相同。

請勿利用單一資料列的單元性

  • 您會仰賴資料列的單元性來更新每台機器在 CURRENT_METRIC 中的資料。這是簡單的資料列異動作業,發生爭用情況的可能性極低,因此不會造成任何問題。

名稱務求簡短但有意義

  • 維持與疊代作業 1 相同。

接下來,請根據模式設計資料列索引鍵:

使用高窄型資料表

  • 在這兩個資料表中,每個資料列均會儲存一台機器的一組指標,這會產生大量的資料列。

建議使用資料列,而非資料欄版本

  • 維持與疊代作業 1 相同。

以查詢為出發點,來設計資料列索引鍵

  • 由於這是時間序列,所以請將時間戳記 TS 包含在資料列索引鍵中。為了擷取指定機器在指定起迄時間內的指標,您將使用 HOSTNAME 加上 TS,從 METRIC 中擷取資料列範圍。
  • 因此,您會將 HOSTNAME 升級為資料列索引鍵,並使用 HOSTNAME 加上 TS 格式的資料列索引鍵。
  • 如要尋找特定機器的最新指標,請藉由篩選這些機器的資料列索引鍵前置字元 (即「HOSTNAME」) 來掃描 CURRENT_METRIC
  • 如要找到整批機器的最新指標,請直接掃描 CURRENT_METRIC 而不用指定資料列索引鍵。
  • 因此,您不需要再將任何其他欄位升級為資料列索引鍵,而且該資料列索引鍵會使用 HOSTNAME 加上 TS 的簡單格式。這樣可以產生簡單、容易理解的結構定義,讓資料表能夠有效分割。
  • CURRENT_METRIC 資料表中,即使您知道系統始終會儲存各個資料表的最新指標,但是為了簡單易懂,資料列索引鍵一樣會是 HOSTNAME 加上 TS 的格式。

    METRICCURRENT_METRIC 資料列索引鍵範例:server1.aaa.bbb.com#1426535612045

確保您的資料列索引鍵不會發生資源使用率不均的問題

  • METRICCURRENT_METRIC 都不會發生資源使用率不均的問題,因為在資料列索引鍵開頭處有主機名稱,系統將會跨區域分配活動。

唯有必要時才反轉時間戳記

  • 您會將最近指標的資料儲存在獨立的資料表中,因此不用反轉時間戳記。

在完成這個設計練習之後,會產生下列資料表:

METRIC 和 CURRENT_METRIC 資料表範例:

資料列索引鍵 資料欄的資料
server1.bbb.com#1426535612045 METRIC:
CPU/CPU1_USR:
0.02
METRIC:
CPU/CPU1_NICE:
0.00
... METRIC:
IO/BLK_READ:
253453634
METRIC:
MIO/BLK_WRTN:
657365234

這些資料表會以每天約 20 億個資料列的速率增長,而 Cloud Bigtable 可以輕而易舉地處理這種情況。

智慧型電表 (物聯網)

本範例使用一個假設的 IoT 情節,其中的智慧型電表會定期將感應器讀數傳到中央系統。在本範例中,您同樣會對結構定義執行多次疊代作業。

對於資料,您可以假設如下:

  • 有 10,000,000 個可運作的電表。
  • 每一個電表皆每 15 分鐘傳送感應器讀數一次。
  • 電表 ID 是不重複的數值 ID。
  • 典型的查詢為下列其中一項:

    • 指定電表在指定某日的所有資料
    • 指定某日的所有資料

根據該用途,您可以這樣設計資料表:

將相關的資料放在同一個資料表中,將不相關的資料放在不同的資料表中

  • 將感應器資料儲存在一個名稱為 SENSOR 的資料表中。
  • 查詢量會每日遞增,所以您會讓每個資料列儲存一個電表一天的資料。

資料列可以很大,但不能是無限大

  • 每個資料列都會包含一個電表一天的資料,共有 96 個資料欄 (一天 24 小時 * 一小時 60 分鐘 / 每 15 分鐘讀取 1 次),這不會引起任何大小問題。

請勿利用單一資料列的單元性

  • 您將會利用資料列的單元性,因為收到資料時,該資料會加到適當的每日資料列中。這是簡單的資料列異動作業,發生爭用情況的可能性極低,因此不會造成任何問題。

名稱務求簡短但有意義

  • ID 用於儲存電表 ID (不會重複的整數)。
  • 名稱為 00002345 的一系列資料欄會包含當天每 15 分鐘記錄的 96 個值。採用這個結構定義的原因是為了在必要時,您可以將頻率更改為 15 分鐘以外的間隔。

所以您會得到下列的資料欄配置:

疊代作業 1

資料欄的資料
METER:ID:987654 METER:0000:
12.34
METER:0015:
13.45
... METER:2330:
27.89
METER:2345:
28.90

接下來,設計資料列索引鍵:

使用高窄型的資料表

  • 如上所述,每個資料列會儲存一天的資料。

建議使用資料列,而非資料欄版本

  • 只在值不正確的例外情況下,才使用資料欄版本。

以查詢為出發點,來設計資料列索引鍵

  • 由於這是時間序列,所以請將 DATE 包含在資料列索引鍵中。由於您只需要精確度到「天」的資料,因此時間戳記最後五個數字會是零,而且會遭到省略。
  • 如要查詢指定某日的指定電表,您需要使用 METERDATE 擷取單一資料列。
  • 如要查詢指定某日的所有電表,請使用 DATE 擷取資料列範圍。
  • 因此,請升級 DATE (8 位數字) 和 METER (10 位數字,電表 ID 左邊會補至 10 位數以容納 10 億個潛在電表,同時維持按照字典編列順序排列)。
  • 一併執行查詢作業時,資料列索引鍵需要使用 DATE 加上 METER 的格式,例如 |20170726|0000987654|

此時,您可能會注意到一個問題:在每天開始的時候,所有電表都瞄準單一節點,因為日期在資料列索引鍵中的最前頭位置。若有 1 千萬個電表,很可能會發生問題並影響到每一天的效能。解決之道是找出一個更好的方式,來查詢特定某日的電表資料。如果每個晚上都會執行單一查詢,並將結果儲存為新的資料表並且命名為 SENSOR_YYYYMMDD,則不需要針對以日期為基礎的查詢,最佳化我們的資料列索引鍵。

我們來執行疊代作業,解決這個問題:

疊代作業 2

將相關的資料放在同一個資料表中,將不相關的資料放在不同的資料表中

  • 將感應器資料儲存在一個名稱為 SENSOR 的資料表中。
  • 查詢以每日遞增的方式擷取資料,所以您會讓每個資料列儲存一個電表一天的資料。
  • 您會整夜執行批次查詢並產生名稱為 SENSOR_YYYYMMDD (日期) 的另一個資料表,以儲存該日期的所有電表資料。

資料列可以很大,但不能是無限大

  • 維持與疊代作業 1 相同。

請勿利用單一資料列的單元性

  • 維持與疊代作業 1 相同。

名稱務求簡短但有意義

  • 維持與疊代作業 1 相同。

綜合以上全部,資料列範例如 SENSOR 資料表和 SENSOR_YYYYMMDD 資料表所示:

資料欄的資料
METER:ID:987654 METER:0000:
12.34
METER:0015:
13.45
... METER:2330:
27.89
METER:2345:
28.90

接下來,設計資料列索引鍵:

使用高窄型的資料表

  • 維持與疊代作業 1 相同。

建議使用資料列,而非資料欄版本

  • 維持與疊代作業 1 相同。

以查詢為出發點,來設計資料列索引鍵

  • 由於這是時間序列,所以請將 DATE 包含在資料列索引鍵中。
  • 若要查詢指定某日的指定電表,您必須使用 METERDATE 擷取單一資料列。
  • 因此,請升級 DATE (8 位數字) 和 METER (10 位數字,電表 ID 左邊會補至 10 位數以容納 10 億個潛在電表,同時維持按照字典編列順序排列)。
  • 資料列索引鍵需要使用 METER 加上 DATE 的格式 (例如「0000987654#20170726」),才能執行我們的查詢,以及完善地跨節點分配活動。
  • 您也會每天執行一次批次查詢,這會掃描整個資料表,並將昨天的資料儲存在名稱為 SENSOR_YYYYMMDD 的新資料表,其中 YYYYMMDD 是昨天的日期。

確保您的資料列索引鍵不會發生資源使用率不均的問題

  • SENSOR 資料表來說,資源使用率不均不是問題。因為資料列索引鍵的最前頭位置有 METER,所以系統會均勻分散寫入作業。
  • SENSOR_YYYYMMDD 資料表來說,資源使用率不均不是問題。每一個資料表只會建立成批次查詢作業一次,因此在效能方面不太會發生問題。不過建立這些資料表需要完整掃描 SENSOR,所以當 SENSOR_YYYYMMDD 資料表的其他查詢很少時,您要建立 SENSOR 資料表。

唯有必要時才反轉時間戳記

  • 此時,您不需要反轉時間戳記。

在完成這個設計練習之後,會產生下列 SENSOR 資料表和 SENSOR_YYYYMMDD 資料表:

資料列索引鍵 資料欄的資料
0000987654#20170726 METER:ID:987654 METER:0000:
12.34
METER:0015:
13.45
... METER:2330:
27.89
METER:2345:
8.90

這個資料表會以每天略低於 1 千個資料列的速率增長,而 Cloud Bigtable 可以輕而易舉地處理這種情況。

後續步驟

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Cloud Bigtable 說明文件