MaxComputeTunnel上傳典型問題場景

付帥發表於2018-09-26

資料問題

Q:使用Tunnel Java SDK上傳資料,上傳資料可以自動分配到各個分割槽嗎?

A:目前Tunnel是無法自動上傳資料並自動分配到各個分割槽的:每一次上傳只支援資料上傳到一張表或表的一個分割槽,有分割槽的表一定要指定上傳的分割槽,多級分割槽一定要指定到末級分割槽。關於JAVA SDK可參考:Java SDK

Q:使用Tunnel Java SDK上傳資料,如果是分割槽表,SDK能夠動態根據資料建立不同的分割槽嗎?

A:分割槽需要首先建立好,在使用SDK上傳資料時指定。您也可以先把資料上傳到MaxCompute上的表中,再用SQL語句動態分割槽。

Q:使用Tunnel命令列tunnel upload D: est test/pt="time" 在 DataIDE上進行分割槽上傳為什麼報錯:FAILED: error occurred while running tunnel command

A:DataIDE是不支援MaxCompute Tunnel命令列工具的upload語句的。

Q:利用Tunnel命令列工具上傳資料時,共分為50個block,開始一切正常,但是在第22個block時,出現Upload fail,retry 5次後,直接跳過開始上傳第23個block,為什麼會發生這種情況?

A:Block 的概念:一個 block 對應一個HTTP request,多個 block 的上傳可以併發而且是原子的,一次同步請求要麼成功要麼失敗,不會汙染其他的 block。
重傳retry有次數的限制的,當重傳的次數超過了這個限制,就會繼續上傳下一個block。上傳完成後,可以通過select count(*)語句,檢查是否有資料丟失。

Q:本地伺服器每天採集的網站日誌有10GB,需要上傳至MaxCompute,在使用Tunnel Upload命令上傳達到的速度約300KB/S 如何提升上傳速度?

A:Tunnel Upload命令上傳是不設速度限制的。上傳速度的瓶頸在網路頻寬以及伺服器效能。為了提升效能,可以考慮分割槽分表,在多臺ECS上傳下載資料。

Q:如何在Shell指令碼中將一個TXT檔案中的資料上傳到MaxCompute的表中, 即把這兩條命令組合成一條?命令如下:

/odpscmd/bin/odpscmd

tunnel upload "$FILE" project.table

A:可參考客戶端設定命令列客戶端的啟動引數,在Shell中啟動命令是:
/odpscmd/bin/odpscmd -e “tunnel upload "$FILE" project.table”

Q:MaxCompute使用TunnelUpload命令上傳資料,如果資料裡面有回車或空格為什麼上傳失敗?

A:如果資料裡有回車空格,可以給資料設定不同與回車或空格的分隔符後,用-rd和-fd指定對應的分隔符實現資料的上傳。如果無法更換資料中的分隔符,可以將資料作為單獨一行上傳,然後使用UDF解析。

例如下列資料中包含回車,使用“,”作為列分隔符rd,使用“@”作為行分隔符fd,可以正常上傳:

資料內容

shopx,x_id,100@
shopy,y_id,200@
shopz,z_i
d,300@

上傳命令

odps@ MaxCompute_DOC>tunnel u d:data.txt sale_detail/sale_date=201312,region=hangzhou -s false -fd "," -rd "@";

上傳結果

+-----------+-------------+-------------+-----------+--------+
| shop_name | customer_id | total_price | sale_date | region |
+-----------+-------------+-------------+-----------+--------+
| shopx     | x_id        | 100.0       | 201312    | hangzhou |
| shopy   | y_id        | 200.0       | 201312    | hangzhou |
| shopz   | z_id
d      | 300.0       | 201312    | hangzhou |
+-----------+-------------+-------------+-----------+--------+

Q:MaxCompute使用TunnelUpload命令上傳資料,使用的”,”進行列分割, 現在description欄位裡, 資料有逗號, 或者”|”符號, 這種情況怎麼分割?

A:如果資料描述欄位內本身有逗號,可以考慮轉換資料的分隔符為其他符號,再通過-fd指定為其他分隔符進行上傳,舉例如下:

使用者有一個崗位需求的EXCEL資料在Windows環境下需要通過Tunnel Upload命令上傳,表格內本身包含“,”。首先可通過Windows環境設定EXCEL轉換為CSV檔案的預設分隔符:Win7系統在控制皮膚 時鐘、語言和區域 選擇 更改日期、時間或數字格式,點選其他設定。本例中考慮到原始資料中沒有“$”字元,設定分隔符為“$”,如下圖所示:

1

完成設定後,使用EXCEL將資料另存為CSV檔案,並且利用Notepad++等文字編輯工具轉碼為UTF-8編碼(Tunnel預設使用的編碼格式),檢查是否檔案分隔符已變成“$”:

標題$所在地$薪資$公司$公司介紹連結$公司型別$公司規模$所屬行業$工作經驗$學歷$所招人數$釋出時間$標籤$職位資訊$上班地址$公司資訊$頁面網址$採集時間

使用TunnelUpload命令上傳資料並指定分隔符(需預先在MaxCompute上建立好表格),即可成功上傳:

odps@ MaxCompute_DOC>tunnel u d:12JD.CSV JD2 -s false -fd "$";
Upload session: 201808201531180d47df0b0b18fa45
Start upload:d:12JD.CSV
Using 
 to split records
Upload in strict schema mode: true
Total bytes:111028       Split input to 1 blocks
2018-08-20 15:31:18     upload block: `1`
2018-08-20 15:31:18     upload block complete, blockid=1
upload complete, average speed is 108.4 KB/s
OK

Q:MaxCompute使用Tunnel Upload命令上傳資料。Tunnel Upload命令預設使用逗號分割的,但資料CSV檔案也是用逗號分割的:檔案裡面有一列資料裡面本身就含有用引號引起來的逗號。這種情況如何處理?

A:CSV檔案使用其他分隔符,可以通過 -fd引數指定。

通常來說,如果資料例有很多符號,可能與分隔符發生衝突,可以自定義資料中分隔符來避免衝突,比如$#@$@ 或者)$*#@$@$。

Q:MaxCompute使用Tunnel Upload命令上傳資料時失敗,記憶體溢位報錯java.lang.OutOfMemoryError:Java heap space是什麼原因?

2

A:從報錯上看是資料上傳的時候的記憶體溢位了。目前TunnelUpload命令是支援海量資料的上傳的,如果出現記憶體溢位,可能是因為資料的行分隔符和列分隔符設定錯誤,導致整個文字會被認為是同一條資料,快取到記憶體裡再做split,導致記憶體溢位報錯。

這種情況下可以先拿少量的資料測試,把-td及-fd除錯過了後再上傳拿全量的資料。

Q:MaxCompute使用Tunnel Upload命令上傳資料,需要上傳很多個資料檔案到一個表中,是否有方法寫一個指令碼就可以把資料夾下的所有資料檔案迴圈上傳上去?

A:TunnelUpload命令上傳支援檔案或目錄(指一級目錄)的上傳。

例如下述命令,上傳資料為資料夾d:data,上傳命令為:

odps@ MaxCompute_DOC>tunnel u d:data sale_detail/sale_date=201312,region=hangzhou -s false;

詳情請參見Tunnel命令操作

Q:匯入資料夾會報錯:欄位不匹配colum mismatch,但是這個資料夾下的檔案單獨匯入時又是可以匯入的,是因為檔案太大嗎?

3

A:這種情況下,可以在upload命令後加上-dbr=false -s true對資料格式進行驗證。出現column mismatch通常是由於列數對不上導致的:可能性較大的原因包括列分隔符設定的不對或檔案的最後有空行,導致空行進行分隔符分割的時候分不出那麼多列。

Q:MaxCompute使用Tunnel Upload命令上傳兩個檔案,上傳完第一個檔案命令結束之後,第二個檔案不會上傳是什麼原因?沒有報錯資訊,就是第一個檔案上傳之後第二個檔案上傳命令不執行了。上傳命令如下:

D:odpsinodpscmd.bat -e"tunnel upload d:data1.txt sale_detail/sale_data=201312 -fd="$" -mbr=5 --scan=true; "

D:odpsinodpscmd.bat -e"tunnel upload d:data2.txt sale_detail/sale_data=201312 -fd="$" -mbr=5 --scan=true; "

A:當使用老版本MaxCompute命令列客戶端,上傳引數有--scan的時候,續跑模式的引數傳遞有問題,將--scan=true 去掉重試即可。

Q:MaxCompute使用Tunnel Upload命令把一個目錄下的所有檔案上傳到一個表裡,並且想要自動建立分割槽,具體的命令是 tunnel upload /data/2018/20180813/*.json app_log /dt=20180813 -fd `@@` -acp true; ,執行報錯:

Unrecognized option: -acp
FAILED: error occurred while running tunnel command

A:出現這種報錯通常是因為是用了不支援的命令或字元。MaxCompute使用Tunnel Upload命令上傳不支援萬用字元及正規表示式。

Q:MaxCompute使用Tunnel Upload命令上傳檔案資料包錯,是否有像MySQL的-f的強制跳過錯誤資料繼續進行上傳的命令?

A:出現這種錯誤是因為資料格式問題,例如資料型別不對,可參考Tunnel命令操作,使用-dbr true引數忽略髒資料(多列,少列,列資料型別不匹配等情況)。-dbr引數預設用false,表示不忽視髒資料,當值為true時,將不符合表定義的資料全部忽略。

Q:MaxCompute使用Tunnel Upload命令上傳檔案資料包錯如下是為什麼?

java.io.IOException: RequestId=XXXXXXXXXXXXXXXXXXXXXXXXX, ErrorCode=StatusConflict, ErrorMessage=You cannot complete the specified operation under the current upload or download status.
        at com.aliyun.odps.tunnel.io.TunnelRecordWriter.close(TunnelRecordWriter.java:93)
        at com.xgoods.utils.aliyun.maxcompute.OdpsTunnel.upload(OdpsTunnel.java:92)
        at com.xgoods.utils.aliyun.maxcompute.OdpsTunnel.upload(OdpsTunnel.java:45)
        at com.xeshop.task.SaleStatFeedTask.doWork(SaleStatFeedTask.java:119)
        at com.xgoods.main.AbstractTool.excute(AbstractTool.java:90)
        at com.xeshop.task.SaleStatFeedTask.main(SaleStatFeedTask.java:305)

A:這個錯誤的提示是當前已經是在上傳或下載中,所以無法再操作。

Q:MaxCompute使用Tunnel SDK上傳檔案資料包錯重複提交是為什麼?

RequestId=20170116xxxxxxx, ErrorCode=StatusConflict, ErrorMessage=You cannot complete the specified operation under the current upload or download status. java.io.IOException: RequestId=20170116xxxxxxx, ErrorCode=StatusConflict, ErrorMessage=You cannot complete the specified operation under the current upload or download status.
at com.aliyun.odps.tunnel.io.TunnelRecordWriter.close(TunnelRecordWriter.java:93)

A:由上述報錯可見,這個問題是在準備close這個writer時出現的,可能有以下幾種情況:

  • 對一個已經關閉的writer做了關閉操作。
  • 這個writer對應的session已經關閉。
  • 該session已經被提交過。

    可以針對上述可能出現的原因進行排查,比如列印當前writer和session的狀態。

Q:MaxCompute使用Tunnel SDK上傳資料時,編寫完UDF打成Jar包後上傳,對Jar包大小有要求嗎?

A:Jar包不能超過10M, 如果Jar超過10M,建議轉用MaxCompute Tunnel Upload命令列上傳資料。

Q:MaxCompute使用Tunnel Upload命令列上傳資料,對資料大小有限制嗎?

A:Tunnel Upload命令列通常不會限制需上傳的資料大小。

Q:MaxCompute使用Tunnel Upload命令列上傳CSV檔案,如何跳過第一行表頭上傳其他資料?

A:建議使用-h true引數,跳過table header.

Q:使用Tunnel批量資料通道SDK來匯入MaxCompute資料庫是否有分割槽限制?

A:使用Tunnel批量資料通道SDK來匯入MaxCompute資料庫。目前支援的是6萬個分割槽。

分割槽數量過多,會給統計和分析帶來極大的不便。MaxCompute會限制單個作業中最多不能超過一定數量的instance。作業的instance和使用者輸入的資料量和分割槽數量是密切相關的,所以建議首先評估下業務,選擇合適的分割槽策略,避免分割槽過多帶來的影響。

關於分割槽表的更多資訊請參考分割槽

此外,MaxCompute也支援通過Python SDK來進行Tunnel批量上傳,請參考Python SDK中的資料上傳/下載配置

Q:要一次性上傳8000W的資料,最後在odps tunnel recordWriter.close()時報錯,報錯內容如下:

ErrorCode=StatusConflict, ErrorMessage=You cannot complete the specified operation under the current upload or download status.

A:這個報錯說明session的狀態錯誤,建議重新建立個session重新上傳一下資料。從報錯上看,很可能是前面的操作裡已經close了這個session,或者已經commit了。對於不同的分割槽,需要每個分割槽都是單獨的一個session。

為了防止多次commit導致的這種報錯,可以先檢查資料上傳是否已經傳成功,如果失敗的話重新上傳一次。可參考多執行緒上傳示例

Q:如何使用TunnelBufferedWriter規避使用Tunnel SDK進行批量資料上傳出錯的問題?

A:MaxCompute Java SDK在0.21.3-public版本之後新增了BufferredWriter的SDK,簡化了資料上傳,並且提供了容錯功能。

BufferedWriter對使用者隱藏了block的概念:從使用者角度看,就是在session上開啟一個writer然後進行寫記錄即可。具體實現時,BufferedWriter先將記錄快取在客戶端的緩衝區中,並在緩衝區填滿之後開啟一個http連線進行上傳。

BufferedWriter會盡最大可能容錯,保證資料上傳上去。使用方法請參考BufferedWriter使用指南

Q:MaxCompute使用TunnelUpload命令列上傳CSV檔案,為什麼匯入成功後原文字中有很大一部分內容莫名消失,被“ – ”取代?

A:這種情況很可能是因為資料編碼格式不對導致上傳到表的資料不對,或者是分隔符使用錯誤。建議規範原始資料後上傳.

Q:MaxCompute使用Tunnel Upload命令列上傳是否支援引用一個表的配置?

A:可以shell指令碼方式執行Tunnel Upload命令列上傳實現。可通過/odpscmd/bin/odpscmd -e執行指令碼,並在指令碼內貼上表格配置。

Q:MaxCompute使用Tunnel SDK上傳資料時,經常會發現Select查詢慢,SQL語句的執行效能不好的情況。

遇到類似情況,可能原因是MaxCompute小檔案過多,從而影響效能導致的。如何處理小檔案過多的問題?

A:
小檔案產生的原因:

MaxCompute使用的分散式檔案系統是按塊Block存放,通常檔案大小比塊大小小的檔案(預設塊大小為64M),叫做小檔案。

目前MaxCompute有以下場景可以產生小檔案:

  • Reduce計算過程會產生大量小檔案;
  • Tunnel資料採集過程中會生成小檔案;
  • Job執行過程中生成的各種臨時檔案、回收站保留的過期的檔案等,主要分類為:
  • TABLE_BACKUP:回收站中超過保留天數的表
  • FUXI_JOB_TMP:作業執行臨時目錄
  • TMP_TABLE:作業執行中產生的臨時表
  • INSTANCE:作業執行時保留在meta表中的日誌
  • LIFECYCLE:超過生命週期的的資料表或分割槽
  • INSTANCEPROFILE:作業提交及執行完成後的profile資訊
  • VOLUME_TMP:沒有meta資訊,但在pangu上有路徑的資料
  • TEMPRESOURCE:使用者自定義函式使用的一次性臨時資原始檔
  • FAILOVER:系統發生failover時保留的臨時檔案

小檔案過多會帶來以下影響:

  • 影響Map Instance效能:預設情況下一個小檔案對應一個instance,造成浪費資源,影響整體的執行效能。
  • 過多的小檔案給分散式檔案系統帶來壓力,且影響空間的有效利用,嚴重時會直接導致檔案系統不可用。

檢視錶中的小檔案數量命令:

desc extended + 表名

小檔案處理方式
不同原因產生的小檔案,需要有不同的處理方法:

(1)Reduce過程中產生的小檔案

使用insert overwrite源表(或分割槽),或者寫入到新表刪除源表。

(2)Tunnel資料採集過程中產生的小檔案

  • 呼叫Tunnel SDK時,當buffer達到64MB時提交一次;
  • 使用console時避免頻繁上傳小檔案,建議積累較大時一次性上傳;
  • 如果匯入的是分割槽表,建議給分割槽設定生命週期,過期不用的資料自動清理;
  • Insert overwrite源表(或分割槽):
ALTER合併模式,通過命令列進行合併:set odps.merge.cross.paths=true;
set odps.merge.max.partition.count=100; --預設優化10個分割槽,此時設定為優化100個分割槽。
ALTER TABLE tablename [PARTITION] MERGE SMALLFILES;
  • 臨時表

    在用臨時表建議建立時都加上生命週期,到期後垃圾回收自動回收。

Q:MaxCompute使用Tunnel Upload命令列上傳資料,如果資料使用空格作為列分隔符,或需要對資料做正規表示式過濾時該如何處理?

A:Tunnel Upload命令列不支援正規表示式。如果資料使用空格作為列分隔符,或需要對資料做正規表示式過濾時可藉助MaxCompute的UDF自定義函式功能。

首先,將資料作為單列資料上傳。本例中原始資料如下,列分割符為空格,行分隔符為回車,並且需要取的部分資料在引號內,部分資料例如”-“需要被過濾。這種複雜的需求可通過正規表示式實現。

10.21.17.2 [24/Jul/2018:00:00:00 +0800] - "GET https://help.aliyun.com/document_detail/73477.html" 200 0 81615 81615 "-" "iphone" - HIT - - 0_0_0 001 - - - -
10.17.5.23 [24/Jul/2018:00:00:00 +0800] - "GET https://help.aliyun.com/document_detail/73478.html" 206 0 49369 49369 "-" "huawei" - HIT - - 0_0_0 002 - - - -
10.24.7.16 [24/Jul/2018:00:00:00 +0800] - "GET https://help.aliyun.com/document_detail/73479.html" 206 0 83821 83821 "-" "vivo" - HIT - - 0_0_0 003 - - - -

為使資料單列上傳,首先在MaxCompute專案空間內建立一個單列的表格用於接收資料:
odps@ bigdata_DOC>create table userlog1(data string);

使用一個不存在的列分隔符 “u0000″上傳資料,從而達到不分割列的效果:
odps@ bigdata_DOC>tunnel upload C:userlog.txt userlog1 -s false -fd "u0000" -rd "
";

完成原始資料上傳後,使用MaxCompute IntelliJ IDEA編寫一個Python UDF(您也可以使用JAVA UDF,注意使用Python UDF需提交工單申請許可權),詳情可參見Python開發使用須知

使用程式碼如下:

from odps.udf import annotate
from odps.udf import BaseUDTF
import re           #此處引入正則函式
regex = `([(d.)]+) [(.*?)] - "(.*?)" (d+) (d+) (d+) (d+) "-" "(.*?)" - (.*?) - - (.*?) (.*?) - - - -`             #使用的正規表示式
# line -> ip,date,request,code,c1,c2,c3,ua,q1,q2,q3
@annotate(`string -> string,string,string,string,string,string,string,string,string,string,string`)  #請注意string數量和真實資料保持一致,本例中有11列。
class ParseAccessLog(BaseUDTF):
    def process(self, line):
        try:
            t = re.match(regex, line).groups()
            self.forward(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10])
        except:
            pass

完成函式的編寫後,選擇上傳程式碼。

1

上傳時請注意選擇當前使用的專案。

2

完成上傳後,註冊函式並填寫函式名稱,本例中函式名稱為ParseAccessLog。

3

函式上傳完成後,就可以使用編寫的UDF函式處理上傳到表格userlog1的原始資料了,注意不要寫錯列的名稱,本例中為data。您可以使用正常的SQL語法,新建一個表格userlog2用於存放處理後的資料。

odps@ bigdata_DOC>create table userlog2 as select ParseAccessLog(data) as (ip,date,request,code,c1,c2,c3,ua,q1,q2,q3) from userlog1;

完成處理後,可以觀察到目標表已建立,資料成功分列。

+----+------+---------+------+----+----+----+----+----+----+----+
| ip | date | request | code | c1 | c2 | c3 | ua | q1 | q2 | q3 |
+----+------+---------+------+----+----+----+----+----+----+----+
| 10.21.17.2 | 24/Jul/2018:00:00:00 +0800 | GET https://help.aliyun.com/document_detail/73477.html | 200  | 0  | 81615 | 81615 | iphone | HIT | 0_0_0 | 001 |
| 10.17.5.23 | 24/Jul/2018:00:00:00 +0800 | GET https://help.aliyun.com/document_detail/73478.html | 206  | 0  | 4936 | 4936 | huawei | HIT | 0_0_0 | 002 |
| 10.24.7.16 | 24/Jul/2018:00:00:00 +0800 | GET https://help.aliyun.com/document_detail/73479.html | 206  | 0  | 83821 | 83821 | vivo | HIT | 0_0_0 | 003 |
+----+------+---------+------+----+----+----+----+----+----+----+

Q:MaxCompute使用Tunnel Upload命令上傳資料,如何實現批量上傳一個目錄下的多個檔案到同一張表,並且每個檔案放在不同的分割槽內?

A:可以巧妙的利用Shell指令碼實現上述功能,本章節中以在Windows環境下配合odpscmd客戶端使用Shell指令碼舉例,Linux環境下原理相同。
Shell指令碼內容如下。

#!/bin/sh
C:/odpscmd_public/bin/odpscmd.bat  -e "create table user(data string) partitioned by (dt int);" //首先建立一個分割槽表user,分割槽關鍵字為dt,本例中odpscmd客戶端的安裝路徑為C:/odpscmd_public/bin/odpscmd.bat,您可以根據您的實際環境調整路徑。
dir=$(ls C:/userlog)  //定義變數dir,為存放檔案的資料夾下所有檔案的名稱
pt=0 //變數pt用於作為分割槽值,初始為0,每上傳好一個檔案+1,從而實現每個檔案都存放在不同的分割槽
for i in $dir  //定義迴圈,遍歷資料夾C:/userlog下的所有檔案
do
   let pt=pt+1  //每次迴圈結束,變數pt+1
   echo $i  //顯示檔名稱
   echo $pt //顯示分割槽名稱
    C:/odpscmd_public/bin/odpscmd.bat  -e "alter table user add partition (dt=$pt);tunnel upload C:/userlog/$i user/dt=$pt -s false -fd "%" -rd "@";" //利用odpscmd首先新增分割槽,然後向分割槽中上傳檔案
done

實際執行shell指令碼效果如下,本例中以兩個檔案userlog1及userlog2舉例。

123

完成上傳後,您可以在odpscmd客戶端檢視錶資料。

123444

網路問題

Q:MaxCompute使用Tunnel Upload命令上傳資料時為什麼報錯java.io.IOException: Error writing request body to server

A:這是一個上傳資料到伺服器的時的異常,通常是因為上傳過程中的網路連結斷開/超時導致的:

  • 可能是使用者的資料來源並非是來自本地檔案,而是需要從諸如資料庫等一類的地方獲取,導致資料在寫入的過程中還需要等待資料獲取導致的超時。目前UploadSession在上傳資料的過程中,如果600秒沒有資料上傳,則被認為超時。
  • 使用者通過公網的Endpoint來做資料上傳,由於公網網路質量不穩定導致超時。

解決方法:

  • 在上傳的過程中,先把獲取資料,再呼叫Tunnel SDK上傳資料。
  • 一個block可以上傳64M-1G的資料,最好不要超過1萬條資料以免帶來重試的時間導致的超時。一個Session可以掛最多2萬個block。

    如果使用者的資料是在ECS上,可以參考訪問域名和資料中心配置合適的Endpoint,可以提速並節省費用。

Q:MaxCompute使用Tunnel Upload命令列上傳資料,設定了經典網路的Endpoint,但為什麼會連線到外網的Tunnel Endpoint?

A:配置檔案odps_config.ini裡除了endpoint之外還需要配置tunnel_endpoint。請參考訪問域名和資料中心進行配置。目前只有上海region不需要設定tunnel endpoint

Q:MaxCompute使用Tunnel Upload命令列上傳資料是否支援限速?上傳速率太快的話可能會佔用伺服器過多的I/O效能。

A:目前MaxCompute使用Tunne lUpload命令列不支援限速,需要通過SDK單獨處理。

計費問題

Q:MaxCompute使用Tunnel Upload命令列上傳資料計費的頻寬,是按照資料壓縮前還是壓縮後的大小計費?

A:按照Tunnel壓縮後的頻寬進行計費。


相關文章