天天看點

MaxCompute通路TableStore(OTS) 資料(20170601更新)

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

maxcompute與tablestore是兩個獨立的大資料計算以及大資料存儲服務,是以兩者之間的網絡必須保證連通性。 對于maxcompute公共雲服務通路tablestore存儲,推薦使用tablestore私網位址,也就是host名以<code>ots-internal.aliyuncs.com</code>作為結尾的位址,例如<code>tablestore://odps-ots-dev.cn-shanghai.ots-internal.aliyuncs.com</code>。

tablestore與maxcompute都有其自身的類型系統。 在maxcompute處理tablestore資料的時候,兩者之間的類型對應關系如下:

| maxcompute type | tablestore type |

| ------------- |:-------------:|

| string | string |

| bigint | int |

| double | double |

|binary* | blob |

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

需要首先指出的是,maxcompute計算服務要通路tablestore資料需要有一個安全的授權通道。 在這個問題上,maxcompute結合了阿裡雲的通路控制服務(ram)和令牌服務(sts)來實作對資料的安全反問:

首先需要在ram中授權maxcompute通路oss的權限。登入ram控制台,建立角色<code>aliyunodpsdefaultrole</code>,并将政策内容設定為:

然後編輯該角色的授權政策,将權限<code>aliyunodpsrolepolicy</code>授權給該角色。

這個ddl語句将一個tablestore表映射到了maxcompute的一個external table上。 在這個基礎上,後繼對tablestore資料的操作可以直接通過external table進行。 這裡先對上面這個create external table的ddl語句做一些解釋:

<code>com.aliyun.odps.tablestorestoragehandler</code> 是maxcompute内置的處理tablestore資料的storagehandler, 定義了maxcompute和tablestore的互動,相關邏輯由maxcompute實作。

<code>serdeproperites</code>可以了解成提供參數選項的接口,在使用tablestorestoragehandler時,有兩個必須指定的選項,分别是下面介紹的<code>tablestore.columns.mapping</code>和<code>tablestore.table.name</code>。 更多的可選選項将在後面其他例子中提及。

<code>tablestore.columns.mapping</code>選項:必需選項,用來描述對需要maxcompute将通路的tablestore表的列,包括主鍵和屬性列。 這其中以<code>:</code>打頭的用來表示tablestore主鍵,例如這個例子中的<code>:o_orderkey</code>和<code>:o_orderdate</code>。 其他的均為屬性列。 tablestore支援最少1個,最多4個主鍵,主鍵類型為<code>bigint</code>或<code>string</code>,其中第一個主鍵為分區鍵。 在指定映射的時候,使用者必須提供指定tablestore表的所有主鍵,對于屬性列則沒有必要全部提供,可以隻提供需要通過maxcompute來通路的屬性列。

<code>tablestore.table.name</code>:需要通路的tablestore表名。 如果指定的tablestore表名錯誤(不存在),則會報錯,maxcompute不會主動去建立tablestore表。

location clause用來指定tablestore的具體資訊,包括instance名字,endpoint等。 值得注意的是這裡對tablestore資料的安全通路是建立在前文介紹的ram/sts授權的前提上的。

在用上述ddl建立出external table之後,tablestore的資料就引入到了maxcompute的生态中,我們現在就可以通過正常的maxcompute sql文法來通路tablestore資料了,比如:

可以看到,在上面的這個例子,直接使用的就是我們所熟悉的maxcompute sql文法,通路tablestore的所有細節由maxcompute内部處理。 這包括在列名的選擇上:可以看到,在這個sql裡面,使用的列名是<code>odps_orderkey</code>,<code>odps_totalprice</code>等,而不是原始tablestore裡面的主鍵名<code>o_orderkey</code>或屬性列名<code>o_totalprice</code>了,因為我們在建立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(内部)表,比如:

現在<code>internal_orders</code>就是一個我們熟悉的maxcompute表了,也擁有所有maxcompute内部表的特性:包括高效的壓縮列存儲資料格式,完整的内部宏資料以及統計資訊等。 同時因為存儲在maxcompute内部,通路速度會比通路外部的tablestore更快,尤其适用于需要進行多次計算的熱點資料。

打通maxcompute和tablestore的資料生态,除了将tablestore作為批量資料處理的資料來源以外,一個另外的重要場景是将maxcompute的資料處理結果輸出到tablestore,利用tablestore可實時更新和可單行覆寫等特點,迅速的将離線計算的結果回報給線上應用。 這種對tablestore的資料輸出可以使用maxcompute sql的insert overwrite來實作。

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

緊接上面的例子,假設我們已經使用上面的ddl語句建立了<code>ots_table_external</code>這個外部表來打通maxcompute與tablestoreb資料表<code>ots_tpch_orders</code>的鍊路, 而且我們還有一份存儲在在maxcompute内部有一個名為<code>internal_orders</code>的資料,現在希望對<code>internal_orders</code>中的資料進行一定處理後再寫回tablestore上,那麼可以直接通過對外部表做insert overwite table的操作來實作:

在這裡對表中的資料做了一些處理,并且把經過處理過的資料重新寫回到了tablestore裡。 對于tablestore這種kv資料的nosql存儲媒體,從maxcompute的輸出将隻影響相對應主鍵所在的行:在上面這個例子中也就是隻影響所有 <code>odps_orderkey</code> + <code>odps_orderdate</code> 這兩個主鍵值能對應行上的資料。 而且在這些tabelestore行上面,也隻會去更新在建立external table (<code>ots_table_external</code>)時指定的屬性列,而不會去修改未在external table裡面出現的資料列。 關于maxcompute外部表和tablestore表的對應關系,下文會更系統的介紹。

從本質上來看maxcompute表是嚴格結構化的資料表,要求所有的行均遵從嚴格一緻的schema,而tablestore的表中存儲的是nosql的“半結構化”k-v資料。這些基本資料格式上的差別決定了在兩個系統的互動過程中,行為會有一些差別。 同時maxcompute作為一個分布式計算系統,讀寫tablestore通過并發執行來實作,這就需要對tablestore的資料有一個切割的機制。 在預設情況下,maxcompute會提供一個系統認為最合适的處理方法,來實作對tablestore資料的通路和計算,而這些實作也能滿足絕大部分使用者的需求。 但是與此同時,為了滿足一些對系統比較熟悉的進階使用者的特殊需求,maxcompute也提供了更多的可配置選項,這裡做一些介紹。

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技術團隊。

tablestore是一個分布式kv資料存儲系統,每個資料表都可能存儲在多個後端server上,并且根據分區鍵進行分區,具體存儲上的分區政策由tablestore決定。 目前通過maxcompute讀取tablestore資料,預設的并發度将與tablestore後端的分區數目相同。 唯一的例外是,在采用integer64作為分區鍵,且tablestore後端的分區數目大于1時,maxcompute會自動對并發度再做調整,在更高的并發度上讀取資料。 此外tablestore自身的系統也在不斷發展,以後将提供更強大的api接口給maxcompute來使用,到時候将可以根據後端資料的大小,來準确的做出資料切割。 更準确的控制每個并發maxcompute worker處理的資料量和計算時間。 這方面将在這些功能實作後再更新來做具體說明。

最後,如果使用者對自己存儲在tablestore資料有着非常好的了解,比如對于不同key range中的資料量都能做出很好的預估,maxcompute還提供讓使用者自己指定并發度的選型:使用者的控制甚至可以細化到指定每個worker應該處理哪個range的資料。 有這個需求的使用者可以聯系maxcompute技術團隊。

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

繼續閱讀