MaxCompute訪問TableStore(OTS) 數據(20170601更新)

摘要: MaxCompute作爲阿里雲大數據平臺的核心計算組件,承擔了集團內外大部分的分佈式計算需求。

免費開通大數據服務:https://www.aliyun.com/product/odps

0. 前言

MaxCompute作爲阿里雲大數據平臺的核心計算組件,承擔了集團內外大部分的分佈式計算需求。而MaxCompute SQL作爲分佈式數據處理的主要入口,爲快速方便處理/存儲EB級別的離線數據提供了強有力的支持。 隨着大數據業務的不斷擴展,新的數據使用場景在不斷產生,在這樣的背景下,MaxCompute計算框架也在不斷的演化,原來主要面對內部特殊格式數據的強大計算能力,也正在一步步的開放給不同的外部數據。 之前我們介紹了怎樣在MaxCompute上處理存儲在OSS上面的非結構化數據,在這裏我們將進一步介紹如何將來自TableStore(OTS)的數據納入MaxCompute上的計算生態,實現多種數據源之間的無縫連接。

對於在線服務等應用場景,NoSQL KV Store(e.g., BigTable, HBase)相比傳統數據庫,具有schema靈活,易擴展,實時性強等優點。阿里雲TableStore(OTS) 是在阿里飛天分佈式系統之上實現的大規模的NoSQL數據存儲服務,提供海量KV數據的存儲和實時訪問。 在集團內部各BU以及外部阿里雲生態圈中具有廣泛的應用。 尤其是TableStore在行級別上的實時更新和可覆蓋性寫入等特性,相對於MaxCompute內置表append-only批量操作,提供了一個很好的補充。 但是TableStore作爲一個偏存儲的服務,對於存儲在其上的海量數據,在大規模批量並行處理的計算能力有所欠缺。 在這樣的背景下,打通MaxCompute的計算和TableStore存儲之間的數據鏈路就顯得尤其重要。

1. MaxCompute對TableStore數據進行讀取和計算

1.0 使用前提和假設

1.0.1 MaxCompute 2.0計算框架非結構化功能的打開

首先要說明的是MaxCompute新一代的2.0計算框架還在灰度上線的過程中,默認設置下許多功能沒有打開,所以要使用新引進的非結構化數據處理框架,需要申請MaxCompute 2.0試用,具體開通使用方法請參見 如何申請試用MaxCompute 2.0, 簡單來說就是在開通2.0非結構化功能的前提下,在每個SQL query執行時必須帶上如下setting:

set odps.task.major.version=2dot0_demo_flighting;

set odps.sql.planner.mode=lot;

set odps.sql.ddl.odps2=true;

set odps.sql.preparse.odps2=lot;

下面的範例中就不再重複了,但是本文介紹的所有功能均基於以上假設,當然這些特殊設置在2.0計算框架完全上線後就可以省略了。

1.0.2 TabelStore基本概念以及網絡連通性

如果對於TableStore不熟悉或者對於整個KV table的概念比較陌生同學,可以通過TableStore的文檔來先了解一些基本概念(比如主鍵,分區鍵,屬性列等),這裏的討論不對這些基本概念做深入的解釋和探討。 同時對於MaxCompute非結構化框架的整體介紹可以參見之前在MaxCompute上處理存儲在OSS上面的非結構化數據的介紹文章,包括External Table, StorageHandler的概念以及SERDEPROPERTIES的使用等。

MaxCompute與TableStore是兩個獨立的大數據計算以及大數據存儲服務,所以兩者之間的網絡必須保證連通性。 對於MaxCompute公共雲服務訪問TableStore存儲,推薦使用TableStore私網地址,也就是host名以ots-internal.aliyuncs.com作爲結尾的地址,例如tablestore://odps-ots-dev.cn-shanghai.ots-internal.aliyuncs.com

1.0.3 TabelStore類型與MaxCompute類型的對應

TableStore與MaxCompute都有其自身的類型系統。 在MaxCompute處理TableStore數據的時候,兩者之間的類型對應關係如下:

| MaxCompute Type | TableStore Type |
| ------------- |:-------------:| 
| STRING | STRING | 
| BIGINT | INT | 
| DOUBLE | DOUBLE |
|BINARY* | BLOB |

*其中要特別說明的是, 對於MaxCompute而言,BINARY類型是在新的2.0類型系統中引進的,所以如果有需要使用到BINARY類型的時候,除了上文1.0.1 裏面提到的設置之外,還需要額外添加一個設置才能生效:

set odps.sql.type.system.odps2=true;

1.1 使用STS/RAM的方式訪問TableStore數據

需要首先指出的是,MaxCompute計算服務要訪問TableStore數據需要有一個安全的授權通道。 在這個問題上,MaxCompute結合了阿里雲的訪問控制服務(RAM)和令牌服務(STS)來實現對數據的安全反問:

首先需要在RAM中授權MaxCompute訪問OSS的權限。登錄RAM控制檯,創建角色AliyunODPSDefaultRole,並將策略內容設置爲:

{
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "odps.aliyuncs.com"
        ]
      }
    }
  ],
  "Version": "1"
}

然後編輯該角色的授權策略,將權限AliyunODPSRolePolicy授權給該角色。

如果覺得這些步驟太麻煩,還可以登錄阿里雲賬號點擊此處完成一鍵授權

1.2 創建External Table 關聯MaxCompute與TableStore

處理OSS數據的使用方法類似,MaxCompute通過EXTERNAL TABLE的方式來對接TableStore的數據:用戶通過一個CREATE EXTERNAL TABLE的DDL語句,把對TableStore表數據的描述引入到MaxCompute的meta系統內部後,即可如同使用一個普通TABLE一樣來實現對TableStore數據的處理。 這裏先提供一個最簡單的使用範例,並且通過該範例來討論ODPS對接TableStore的一些概念和實現。


DROP TABLE IF EXISTS ots_table_external;

CREATE EXTERNAL TABLE IF NOT EXISTS ots_table_external
(
odps_orderkey bigint,
odps_orderdate string,
odps_custkey bigint,
odps_orderstatus string,
odps_totalprice double
)
STORED BY 'com.aliyun.odps.TableStoreStorageHandler' -- (1)
WITH SERDEPROPERTIES ( -- (2)
'tablestore.columns.mapping'=':o_orderkey, :o_orderdate, o_custkey, o_orderstatus,o_totalprice', -- (3)
'tablestore.table.name'='ots_tpch_orders' -- (4)
)
LOCATION 'tablestore://odps-ots-dev.cn-shanghai.ots-internal.aliyuncs.com'; -- (5)

這個DDL語句將一個TableStore表映射到了MaxCompute的一個External Table上。 在這個基礎上,後繼對TableStore數據的操作可以直接通過External Table進行。 這裏先對上面這個CREATE EXTERNAL TABLE的DDL語句做一些解釋:

  1. com.aliyun.odps.TableStoreStorageHandler 是MaxCompute內置的處理TableStore數據的StorageHandler, 定義了MaxCompute和TableStore的交互,相關邏輯由MaxCompute實現。
  2. SERDEPROPERITES可以理解成提供參數選項的接口,在使用TableStoreStorageHandler時,有兩個必須指定的選項,分別是下面介紹的tablestore.columns.mappingtablestore.table.name。 更多的可選選項將在後面其他例子中提及。
  3. tablestore.columns.mapping選項:必需選項,用來描述對需要MaxCompute將訪問的TableStore表的列,包括主鍵和屬性列。 這其中以:打頭的用來表示TableStore主鍵,例如這個例子中的:o_orderkey:o_orderdate。 其他的均爲屬性列。 TableStore支持最少1個,最多4個主鍵,主鍵類型爲bigintstring,其中第一個主鍵爲分區鍵。 在指定映射的時候,用戶必須提供指定TableStore表的所有主鍵,對於屬性列則沒有必要全部提供,可以只提供需要通過MaxCompute來訪問的屬性列。
  4. tablestore.table.name:需要訪問的TableStore表名。 如果指定的TableStore表名錯誤(不存在),則會報錯,MaxCompute不會主動去創建TableStore表。
  5. LOCATION clause用來指定TableStore的具體信息,包括instance名字,endpoint等。 值得注意的是這裏對TableStore數據的安全訪問是建立在前文介紹的RAM/STS授權的前提上的。

1.3 通過External Table訪問TableStore數據進行計算

在用上述DDL創建出External Table之後,TableStore的數據就引入到了MaxCompute的生態中,我們現在就可以通過正常的MaxCompute SQL語法來訪問TableStore數據了,比如:


SELECT odps_orderkey, odps_orderdate, SUM(odps_totalprice) AS sum_total
FROM ots_table_external
WHERE odps_orderkey > 5000 AND odps_orderkey < 7000 AND odps_orderdate >= '1996-05-03' AND odps_orderdate < '1997-05-01'
GROUP BY odps_orderkey, odps_orderdate
HAVING sum_total> 400000.0;

可以看到,在上面的這個例子,直接使用的就是我們所熟悉的MaxCompute SQL語法,訪問TableStore的所有細節由MaxCompute內部處理。 這包括在列名的選擇上:可以看到,在這個SQL裏面,使用的列名是odps_orderkeyodps_totalprice等,而不是原始TableStore裏面的主鍵名o_orderkey或屬性列名o_totalprice了,因爲我們在創建External Table的DDL語句裏,已經做了對應的mapping。 當然因爲具體的mapping是每個用戶可以自己控制的,所以如果在創建External Table的時候保留原始的TableStore主鍵/列名也是可以的。

在底層的實現上,MaxCompute框架針對TableStore數據的存儲特點做了各種優化,包括併發讀取,SQL語句的filtering操作轉義等。 舉個例子,有filtering操作(比如上面的WHERE語句)時,MaxCompute會判斷filtering key是否爲TableStore表格的主鍵,來決定如何用TableStore的GetRange API來讀取最小量數據,而不是無條件讀取全量數據讀到MaxCompute計算節點再做過濾操作。 當然這些實現的優化用戶均無需感知,由MaxCompute計算框架負責來提供高效的實現。

另外如果需要對一份數據做多次計算,相較每次從TableStore去遠程讀數據,一個更高效的辦法是先一次性把需要的數據導入到MaxCompute內部成爲一個MaxCompute(內部)表,比如:


CREATE TABLE internal_orders AS
SELECT odps_orderkey, odps_orderdate, odps_custkey, odps_totalprice
FROM ots_table_external
WHERE odps_orderkey > 5000 ;

現在internal_orders就是一個我們熟悉的MaxCompute表了,也擁有所有MaxCompute內部表的特性:包括高效的壓縮列存儲數據格式,完整的內部宏數據以及統計信息等。 同時因爲存儲在MaxCompute內部,訪問速度會比訪問外部的TableStore更快,尤其適用於需要進行多次計算的熱點數據。

2. 數據從MaxCompute寫出到TableStore

打通MaxCompute和TableStore的數據生態,除了將TableStore作爲批量數據處理的數據來源以外,一個另外的重要場景是將MaxCompute的數據處理結果輸出到TableStore,利用TableStore可實時更新和可單行覆蓋等特點,迅速的將離線計算的結果反饋給在線應用。 這種對TableStore的數據輸出可以使用MaxCompute SQL的INSERT OVERWRITE來實現。

需要再次強調的是,MaxCompute不會主動創建外部的TableStore表,所以在對TableStore表進行數據輸出之前,必須保證該表已經在TableStore上創建過(否則將報錯)。 這樣的設計是因爲TableStore建表的過程可能涉及到CU的設置,計費,數據生命週期等一系列選項,這些必須由數據的所有者來決定: MaxCompute不擁有這些外部數據,也無法做出這些選擇。

緊接上面的例子,假設我們已經使用上面的DDL語句創建了ots_table_external這個外部表來打通MaxCompute與TableStoreb數據表ots_tpch_orders的鏈路, 而且我們還有一份存儲在在MaxCompute內部有一個名爲internal_orders的數據,現在希望對internal_orders中的數據進行一定處理後再寫回TableStore上,那麼可以直接通過對外部表做INSERT OVERWITE TABLE的操作來實現:


INSERT OVERWRITE TABLE ots_table_external
SELECT odps_orderkey, odps_orderdate, odps_custkey, CONCAT(odps_custkey, 'SHIPPED'), CEIL(odps_totalprice)
FROM internal_orders;

在這裏對錶中的數據做了一些處理,並且把經過處理過的數據重新寫回到了TableStore裏。 對於TableStore這種KV數據的NoSQL存儲介質,從MaxCompute的輸出將隻影響相對應主鍵所在的行:在上面這個例子中也就是隻影響所有 odps_orderkey + odps_orderdate 這兩個主鍵值能對應行上的數據。 而且在這些TabeleStore行上面,也只會去更新在創建External Table (ots_table_external)時指定的屬性列,而不會去修改未在External Table裏面出現的數據列。 關於MaxCompute外部表和TableStore表的對應關係,下文會更系統的介紹。

3. 技術細節以及高級用法

從本質上來看MaxCompute表是嚴格結構化的數據表,要求所有的行均遵從嚴格一致的schema,而TableStore的表中存儲的是NoSQL的“半結構化”K-V數據。這些基本數據格式上的區別決定了在兩個系統的交互過程中,行爲會有一些區別。 同時MaxCompute作爲一個分佈式計算系統,讀寫TableStore通過併發執行來實現,這就需要對TableStore的數據有一個切割的機制。 在默認情況下,MaxCompute會提供一個系統認爲最合適的處理方法,來實現對TableStore數據的訪問和計算,而這些實現也能滿足絕大部分用戶的需求。 但是與此同時,爲了滿足一些對系統比較熟悉的高級用戶的特殊需求,MaxCompute也提供了更多的可配置選項,這裏做一些介紹。

3.1 MaxCompute外表與TableStore數據表的對應關係

MaxCompute外表與TableStore數據表是多對一(N:1)的關係。 也就是說可以有多個MaxCompute外表(External Table)來描述一張TableStore表。 這裏的N:1是兩個維度上的:

  • 不同的MaxCompute外表可以描述一張TableStore表的不同屬性列子集,比如如果在TableStore的一個表有3個主鍵列,(up to)20個屬性列,那麼通過MaxComptue的外表,主鍵必須提供完備,但是屬性列則不必,比如可以只提供一個屬性列,那麼通過MaxCompute外表進行的所有操作,都只會基於主鍵和所提供的屬性列上的數據。
  • 不同的MaxCompute外表可以描述一張TableStore表的不同range,在本文的例子裏都是一個外表對應一個TableStore表的全range,但實際使用的時候是可以通過額外選項來指定外表對應的range start和range end的, 這可以做到一個外表只映射一個TableStore表的子range。 這個功能這裏不展開介紹,有需求的話可以聯繫MaxCompute技術團隊。

3.2 MaxCompute讀取TableStore數據時的併發度

TableStore是一個分佈式KV數據存儲系統,每個數據表都可能存儲在多個後端server上,並且根據分區鍵進行分區,具體存儲上的分區策略由TableStore決定。 目前通過MaxCompute讀取TableStore數據,默認的併發度將與TableStore後端的分區數目相同。 唯一的例外是,在採用INTEGER64作爲分區鍵,且TableStore後端的分區數目大於1時,MaxCompute會自動對併發度再做調整,在更高的併發度上讀取數據。 此外TableStore自身的系統也在不斷髮展,以後將提供更強大的API接口給MaxCompute來使用,到時候將可以根據後端數據的大小,來準確的做出數據切割。 更準確的控制每個併發MaxCompute worker處理的數據量和計算時間。 這方面將在這些功能實現後再更新來做具體說明。

最後,如果用戶對自己存儲在TableStore數據有着非常好的瞭解,比如對於不同key range中的數據量都能做出很好的預估,MaxCompute還提供讓用戶自己指定併發度的選型:用戶的控制甚至可以細化到指定每個worker應該處理哪個range的數據。 有這個需求的用戶可以聯繫MaxCompute技術團隊。

3.3 MaxCompute寫出TableStore數據時的併發度

在將MaxCompute內部數據寫出到TableStore時,併發度由MaxCompute根據數據量自動進行控制。 當然用戶也可以手動調節SQL執行過程中的mapper/reducer數目來調整併發度。 但是絕大部分情況下, MaxCompute本身適配的併發度都是比較合理的,一般不建議自己手工設置mapper/reducer數目。 另外,在一些場景上,MaxCompute計算服務與TableStore存儲服務之間會存在着需要適配的情況。一般來說MaxCompute可以調度起計算節點都比較充裕,而大量計算節點同時往TableStore寫出數據時可能會打滿網絡。 這種情況下單純調高MaxCompute計算節點數目來併發寫出數據,並不會帶來額外的提速。 所以在特別大的規模上,用戶最好能提前和TableStore服務溝通,以保證TableStore能提供足夠的吞吐量滿足需求。

3.4 MaxCompute訪問TableStore的網絡連通性

因爲MaxCompute與TableStore是兩個分開的雲服務,所以在不同的部署集羣上的網絡連通性有可能影響MaxCompute訪問TableStore的數據的可達性。 關於TableStore的節點,實例,服務地址等概念,可以參見TableStore相關介紹。 如同上文介紹的,在MaxCompute公共雲服務訪問TableStore存儲,推薦使用TableStore私網地址(即以ots-internal.aliyuncs.com結尾的host地址)。

4. 結語:構造大數據生態

隨着MaxCompute非結構化數據處理框架的上線,MaxCompute開放了處理外部數據的接口,包括之前介紹的訪問OSS數據,以及本文描述的訪問TableStore數據。 我們希望藉此來實現整個阿里雲計算與數據的生態融合: 在不同的項目上,我們已經看到了在MaxCompute上處理OSS上的海量視頻,圖像等非結構化數據的巨大潛力。 隨着TableStore數據支持的加入,期待計算和更多數據的碰撞能打通更多的應用場景,讓OSS數據,TableStore數據以及MaxCompute內部存儲的數據,能在MaxCompute的核心計算引擎上產生更大的價值。

本文作者:隱林

原文鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章