基本介绍及应用场景

Tunnel是MaxCompute提供的离线批量数据通道服务,主要提供大批量离线数据上传和下载,
仅提供每次批量大于等于64MB数据的场景,小批量流式数据场景请使用DataHub实时数据通道以获得更好的性能和体验。

SDK上传最佳实践

import java.io.IOException;
import java.util.Date; import com.aliyun.odps.Column;
import com.aliyun.odps.Odps;
import com.aliyun.odps.PartitionSpec;
import com.aliyun.odps.TableSchema;
import com.aliyun.odps.account.Account;
import com.aliyun.odps.account.AliyunAccount;
import com.aliyun.odps.data.Record;
import com.aliyun.odps.data.RecordWriter;
import com.aliyun.odps.tunnel.TableTunnel;
import com.aliyun.odps.tunnel.TunnelException;
import com.aliyun.odps.tunnel.TableTunnel.UploadSession; public class UploadSample {
private static String accessId = "<your access id>";
private static String accessKey = "<your access Key>";
private static String odpsUrl = "http://service.odps.aliyun.com/api"; private static String project = "<your project>";
private static String table = "<your table name>";
private static String partition = "<your partition spec>"; public static void main(String args[]) {
// 准备工作,仅需做一次
Account account = new AliyunAccount(accessId, accessKey);
Odps odps = new Odps(account);
odps.setEndpoint(odpsUrl);
odps.setDefaultProject(project);
TableTunnel tunnel = new TableTunnel(odps); try {
// 确定写入分区
PartitionSpec partitionSpec = new PartitionSpec(partition);
// 在服务端创建一个在本表本分区上有效期24小时的session,24小时内该session可以共计上传20000个Block数据
// 创建Session的时耗为秒级,会在服务端使用部分资源、创建临时目录等,操作较重,因此强烈建议同一个分区数据尽可能复用Session上传。
UploadSession uploadSession = tunnel.createUploadSession(project,
table, partitionSpec);
System.out.println("Session Status is : "
+ uploadSession.getStatus().toString());
TableSchema schema = uploadSession.getSchema();
// 准备数据后打开Writer开始写入数据,准备数据后写入一个Block,每个Block仅能成功上传一次,不可重复上传,CloseWriter成功代表该Block上传完成,失败可以重新上传该Block,同一个Session下最多允许20000个BlockId,即0-19999,若超出请CommitSession并且再创建一个新Session使用,以此类推。
// 单个Block内写入数据过少会产生大量小文件 严重影响计算性能, 强烈建议每次写入64MB以上数据(100GB以内数据均可写入同一Block)
// 可通过数据的平均大小与记录数量大致计算总量即 64MB < 平均记录大小*记录数 < 100GB // maxBlockID服务端限制为20000,用户可以根据自己业务需求,每个Session使用一定数量的block例如100个,但是建议每个Session内使用block越多越好,因为创建Session是一个很重的操作
// 如果创建一个Session后仅仅上传少量数据,不仅会造成小文件、空目录等问题,还会严重影响上传整体性能(创建Session花费秒级,真正上传可能仅仅用了十几毫秒)
int maxBlockID = 20000;
for (int blockId = 0; blockId < maxBlockID; blockId++) {
// 准备好至少64MB以上数据,准备完成后方可写入
// 例如:读取若干文件或者从数据库中读取数据
try {
// 在该Block上创建一个Writer,writer创建后任意一段时间内,若某连续2分钟没有写入4KB以上数据,则会超时断开连接
// 因此建议在创建writer前在内存中准备可以直接进行写入的数据
RecordWriter recordWriter = uploadSession.openRecordWriter(blockId); // 将读取到的所有数据转换为Tunnel Record格式并切入
int recordNumber = 1000000;
for (int index = 0; i < recordNumber; i++) {
// 将第index条原始数据转化为odps record
Record record = uploadSession.newRecord();
for (int i = 0; i < schema.getColumns().size(); i++) {
Column column = schema.getColumn(i);
switch (column.getType()) {
case BIGINT:
record.setBigint(i, 1L);
break;
case BOOLEAN:
record.setBoolean(i, true);
break;
case DATETIME:
record.setDatetime(i, new Date());
break;
case DOUBLE:
record.setDouble(i, 0.0);
break;
case STRING:
record.setString(i, "sample");
break;
default:
throw new RuntimeException("Unknown column type: "
+ column.getType());
}
}
// Write本条数据至服务端,每写入4KB数据会进行一次网络传输
// 若120s没有网络传输服务端将会关闭连接,届时该Writer将不可用,需要重新写入
recordWriter.write(record);
}
// close成功即代表该block上传成功,但是在整个Session Commit前,这些数据是在odps 临时目录中不可见的
recordWriter.close();
} catch (TunnelException e) {
// 建议重试一定次数
e.printStackTrace();
System.out.println("write failed:" + e.getMessage());
} catch (IOException e) {
// 建议重试一定次数
e.printStackTrace();
System.out.println("write failed:" + e.getMessage());
}
}
// 提交所有Block,uploadSession.getBlockList()可以自行指定需要提交的Block,Commit成功后数据才会正式写入Odps分区,Commit失败建议重试10次
for (int retry = 0; retry < 10; ++retry) {
try {
// 秒级操作,正式提交数据
uploadSession.commit(uploadSession.getBlockList());
break;
} catch (TunnelException e) {
System.out.println("uploadSession commit failed:" + e.getMessage());
} catch (IOException e) {
System.out.println("uploadSession commit failed:" + e.getMessage());
}
}
System.out.println("upload success!"); } catch (TunnelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

构造器举例说明:

PartitionSpec(String spec):通过字符串构造此类对象。

参数:

spec: 分区定义字符串,比如: pt='1',ds='2'。
因此程序中应该这样配置:private static String partition = "pt='XXX',ds='XXX'";

常见问题

MaxCompute Tunnel是什么?

Tunnel是MaxCompute的数据通道,用户可以通过Tunnel向MaxCompute中上传或者下载数据。目前Tunnel仅支持表(不包括视图View)数据的上传下载。

BlockId是否可以重复?

同一个UploadSession里的blockId不能重复。也就是说,对于同一个UploadSession,用一个blockId打开RecordWriter,写入一批数据后,调用close,
然后再commit完成后,写入成功后不可以重新再用该blockId打开另一个RecordWriter写入数据。 Block默认最多20000个,即0-19999。

Block大小是否存在限制?

一个block大小上限 100GB,强烈建议大于64M的数据,每一个Block对应一个文件,小于64MB的文件统称为小文件,小文件过多将会影响使用性能。
使用新版BufferedWriter可以更简单的进行上传功能避免小文件等问题 Tunnel-SDK-BufferedWriter

Session是否可以共享使用,存在生命周期吗?

每个Session在服务端的生命周期为24小时,创建后24小时内均可使用,也可以跨进程/线程共享使用,但是必须保证同一个BlockId没有重复使用,分布式上传可以按照如下步骤:
创建Session->数据量估算->分配Block(例如线程1使用0-100,线程2使用100-200)->准备数据->上传数据->Commit所有写入成功的Block。

Session创建后不使用是否对系统有消耗?

每个Session在创建时会生成两个文件目录,如果大量创建而不使用,会导致临时目录增多,大量堆积时可能造成系统负担,请一定避免此类行为,尽量共享利用session。

遇到Write/Read超时或IOException怎么处理?

上传数据时,Writer每写入8KB数据会触发一次网络动作,如果120秒内没有网络动作,服务端将主动关闭连接,届时Writer将不可用,请重新打开一个新的Writer写入。

建议使用 [Tunnel-SDK-BufferedWriter]接口上传数据,该接口对用户屏蔽了blockId的细节,并且内部带有数据缓存区,会自动进行失败重试。

下载数据时,Reader也有类似机制,若长时间没有网络IO会被断开连接,建议Read过程连续进行中间不穿插其他系统的接口。

MaxCompute Tunnel目前有哪些语言的SDK?

MaxCompute Tunnel目前提供Java版的SDK。

MaxCompute Tunnel 是否支持多个客户端同时上传同一张表?

支持。

MaxCompute Tunnel适合批量上传还是流式上传

MaxCompute Tunnel用于批量上传,不适合流式上传,流式上传可以使用[DataHub高速流式数据通道],毫秒级延时写入。

MaxCompute Tunnel上传数据时一定要先存在分区吗?

是的,Tunnel不会自动创建分区。

Dship 与 MaxCompute Tunnel的关系?

dship是一个工具,通过MaxCompute Tunnel来上传下载。

Tunnel upload数据的行为是追加还是覆盖?

追加的模式。

Tunnel路由功能是怎么回事?

路由功能指的是Tunnel SDK通过设置MaxCompute获取Tunnel Endpoint的功能。因此,SDK可以只设置MaxCompute的endpoint来正常工作。

用MaxCompute Tunnel上传数据时,一个block的数据量大小多大比较合适

没有一个绝对最优的答案,要综合考虑网络情况,实时性要求,数据如何使用以及集群小文件等因素。一般,如果数量较大是持续上传的模式,可以在64M - 256M,
如果是每天传一次的批量模式,可以设大一些到1G左右

使用MaxCompute Tunnel 下载, 总是提示timeout

一般是endpoint错误,请检查Endpoint配置,简单的判断方法是通过telnet等方法检测网络连通性。

通过MaxCompute Tunnel下载,抛出You have NO privilege ‘odps:Select‘ on {acs:odps:*:projects/XXX/tables/XXX}. project ‘XXX‘ is protected的异常

该project开启了数据保护功能,用户操作这是从一个项目的数据导向另一个项目,这需要该project的owner操作。

Tunnel上传抛出异常ErrorCode=FlowExceeded, ErrorMessage=Your flow quota is exceeded.**

Tunnel对请求的并发进行了控制,默认上传和下载的并发Quota为2000,任何相关的请求发出到结束过程中均会占用一个Quota单位。若出现类似错误,有如下几种建议的解决方案:
1 sleep一下再重试;
2 将project的tunnel并发quota调大,需要联系管理员评估流量压力;
3 报告project owner调查谁占用了大量并发quota,控制一下。

原文链接
本文为云栖社区原创内容,未经允许不得转载。  

离线批量数据通道Tunnel的最佳实践及常见问题的更多相关文章

  1. js-新兴的API,最佳实践,离线应用于客户端存储

    离线应用于客户端存储: 1.离线检测:online以及offline事件,都是在window对象上触发 navigator.online为true的时候是表示设备能够上网 2.使用一个描述文件(man ...

  2. MaxCompute表设计最佳实践

    MaxCompute表设计最佳实践 产生大量小文件的操作 MaxCompute表的小文件会影响存储和计算性能,因此我们先介绍下什么样的操作会产生大量小文件,从 而在做表设计的时候考虑避开此类操作. 使 ...

  3. mybatis 3.x源码深度解析与最佳实践(最完整原创)

    mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...

  4. Web前端开发最佳实践(13):前端页面卡顿?可能是DOM操作惹的祸,你需要优化代码

    文档对象模型(DOM)是一个独立于特定语言的应用程序接口.在浏览器中,DOM接口是以JavaScript语言实现的,通过JavaScript来操作浏览器页面中的元素,这使得DOM成为了JavaScri ...

  5. 《HBase在滴滴出行的应用场景和最佳实践》

    HBase在滴滴出行的应用场景和最佳实践   背景 对接业务类型 HBase是建立在Hadoop生态之上的Database,源生对离线任务支持友好,又因为LSM树是一个优秀的高吞吐数据库结构,所以同时 ...

  6. AWS 架构最佳实践(十二)

    可靠性 基本概念 可靠性 系统从基础设施或服务故障中恢复.动态获取计算资源以满足需求减少中断的能力 系统为最坏情况做好准备,对不同组件实施缓解措施,对恢复程序进行提前测试并且自动执行. 可靠性实践 测 ...

  7. [转]Ethereum-智能合约最佳实践

    主要章节如下: Solidity安全贴士 已知的攻击手段 竞态 可重入 交易顺序依赖 针对Gas的攻击 上溢/下溢 工程技术 参考文献 这篇文档旨在为Solidity开发人员提供一些智能合约的secu ...

  8. [转]10个有关RESTful API良好设计的最佳实践

    Web API已经在最近几年变成重要的话题,一个干净的API设计对于后端系统是非常重要的. 通常我们为Web API使用RESTful设计,REST概念分离了API结构和逻辑资源,通过Http方法GE ...

  9. memcache的最佳实践方案

    1.memcached的基本设置 1)启动Memcache的服务器端 # /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 1 ...

随机推荐

  1. thrift小试--C++

    [转自]http://blog.csdn.net/poechant/article/details/6618284# Thrift可以实现C++.Java.Python等多种语言的自动生成,此处以C+ ...

  2. 学习使用Mendeley1

    原文来自:https://www.mendeley.com/guides/desktop/01-desktop-interface 1.添加文件菜单 - 使用此功能将新条目添加到您的Mendeley库 ...

  3. Django model对象接口

    Django model查询 # 直接获取表对应字段的值,列表嵌元组形式返回 Entry.objects.values_list('id', 'headline') #<QuerySet [(1 ...

  4. window7环境下ZooKeeper的安装及运行

    简介 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...

  5. 动态sql语句,非存储过程,如何判断某条数据是否存在,如果不存在就添加一条

    已知一个表 table 里面有两个字段  A1 和 A2 如何用动态语句 判断 A1 = A , A2=B 的数据是否存在,如果不存在,就添加一条数据, A1 = A , A2 = B INSERT  ...

  6. pycahrm 安装Vue项目

    首先在pycharm > preference > plugins > vue > 点绿色install 创建一个文件夹 然后cmd里cd到这个文件夹 npm install ...

  7. SpringSecurity实现权限管理和页面导航栏动态实现

    用户模块. 3 1.1  需求:获取用户名. 3 1.1.1     分析. 3 1.1.2     服务端获取用户信息. 4 1.1.3     页面获取用户信息. 5 1.2  给用户分配角色. ...

  8. web端本地与服务端时间校验

    当前校验逻辑: 本地和服务端的时间校验绑定在一个通用请求上,这个请求每七分钟会到服务端请求一次,本地拿到服务器时间后,计算请求服务器来回的时间,最后得出与服务器时间的差值,然后每次new Date() ...

  9. 使用abcpdf分页设置的问题

    如果需要在分页时不对模块进行截断,请为相应模块添加打印样式“page-break-inside: avoid” 如果需要在指定位置进行强制分页,请添加:“<div style="pag ...

  10. ASP.NET 4.0验证请求 System.Web.HttpRequestValidationException: A potentially dangerous Request.F

    System.Web.HttpRequestValidationException: A potentially dangerous Request.F 在使用类似eWebedtior 拷贝内容进去的 ...