阿里云表格存储Tablestore对接使用完全指南
1. 表格存储Tablestore概述
表格存储(Tablestore,原名OTS)是阿里云提供的一款全托管、Serverless化的NoSQL多模型数据库服务。它面向海量结构化数据,提供高性能、高可用的数据存储与实时查询能力,同时针对物联网场景深度优化,提供一站式的IoTstore解决方案。Tablestore广泛应用于海量账单、IM消息、物联网、车联网、风控和推荐等场景中的结构化数据存储,具备海量数据低成本存储、毫秒级在线数据查询和检索以及灵活的数据分析能力。
Tablestore的核心优势体现在几个方面。首先是Serverless架构,用户无需关心底层服务器的运维和扩容,系统根据数据量和访问量自动弹性伸缩。其次是多模型支持,一份数据可以同时以宽表、时序、消息三种模型进行组织和访问,满足不同业务场景的需求。第三是高性能与低成本兼得,表格存储提供毫秒级延迟的读写能力,同时通过存储分层和冷热数据分离等机制控制成本。最后是强大的索引与检索能力,多元索引支持全文检索、向量检索、模糊查询等多种复杂查询模式。
Tablestore提供了三种数据存储模型。宽表模型是最基础也最常用的模型,类似于Bigtable或HBase的数据模型,适用于大多数结构化数据存储场景。时序模型专门针对时间序列数据的特点进行设计,适用于物联网设备监控、设备采集数据、机器监控数据等场景,能提供高并发写入和查询以及PB级海量数据的低成本存储。消息模型(Timeline模型)针对消息类业务场景优化,适用于IM、Feed流等应用。开发者可以根据实际业务需求选择合适的数据模型。
2. 准备工作:开通服务与创建实例
在使用表格存储之前,需要进行一系列准备工作。首先需要开通Tablestore服务。如果尚未开通,可以登录阿里云控制台,在产品列表中找到表格存储Tablestore,按照页面提示完成开通操作。开通服务本身是免费的,后续按照实际使用的存储量、读写吞吐量和外网流量进行按量计费。
开通服务后,下一步是创建Tablestore实例。实例是表格存储中的资源管理单元,类似于数据库中的集群概念。创建实例时需要选择实例规格和计费模式。表格存储提供两种实例类型:VCU模式(预留模式)和CU模式(按量付费)。VCU模式适合业务负载相对稳定的场景,通过预留计算单元来保障性能;CU模式适合业务负载波动较大的场景,按实际使用的读写吞吐量计费,更加灵活。此外,创建实例时还需要选择地域、配置网络(如VPC或经典网络)和设置访问控制策略。
如果是时序模型的使用场景,需要在创建实例时选择时序模型实例类型。目前支持时序模型功能的地域包括华东1(杭州)、华东2(上海)、华北2(北京)、华北3(张家口)、华北6(乌兰察布)、华南1(深圳)、西南1(成都)、中国香港、日本(东京)、新加坡等。其中,Lastpoint索引、时序分析存储、自定义时间轴标识等功能仅在华东1、华东2、华北2和华北3地域可用。
创建完实例后,需要获取实例的访问地址(Endpoint)。Endpoint的格式通常为:https://<instance>.<region>.ots.aliyuncs.com。例如,在北京地域创建了一个名为myinstance的实例,其Endpoint为https://myinstance.cn-beijing.ots.aliyuncs.com。
3. 访问凭证配置与SDK安装
访问表格存储需要有效的身份凭证。最常用的方式是使用AccessKey(AK)。建议为阿里云账号或RAM用户创建AccessKey,并遵循最小权限原则授予必要的操作权限。强烈建议使用RAM用户的AccessKey而非主账号的AccessKey,以降低密钥泄露带来的安全风险。创建AccessKey后,为了避免在代码中硬编码敏感信息,推荐通过环境变量来配置访问凭证。
在不同操作系统中配置环境变量的方法略有不同。在Linux或macOS的Bash环境中,可以将以下配置追加到~/.bashrc文件中:
export TABLESTORE_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'
export TABLESTORE_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'然后执行source ~/.bashrc使变更生效。如果使用的是Zsh,则需要追加到~/.zshrc文件。在Windows的CMD中,可以使用setx命令设置环境变量:
setx TABLESTORE_ACCESS_KEY_ID "YOUR_ACCESS_KEY_ID"
setx TABLESTORE_ACCESS_KEY_SECRET "YOUR_ACCESS_KEY_SECRET"配置完成后需要重启IDE、终端或其他应用程序,确保最新的环境变量被加载。
表格存储为开发者提供了多种主流编程语言的SDK。Java SDK支持宽表、时序和消息模型的所有操作。Python SDK同样支持三种模型。Node.js SDK支持宽表模型操作。Go SDK支持宽表、时序和消息模型。此外还有.NET、PHP等语言的SDK。不同SDK对不同功能的支持情况略有差异,例如通道服务目前仅Java和Go SDK支持,Python和Node.js SDK暂不支持。
下面是各语言SDK的安装方式。对于Java项目,如果使用Maven构建,在pom.xml中添加以下依赖:
<dependency>
<groupId>com.aliyun.openservices</groupId>
<artifactId>tablestore</artifactId>
<version>5.17.7</version>
</dependency>对于非Maven项目,可以手动下载SDK的JAR包并导入到项目中。Python SDK通过pip安装:
pip install "tablestore>=6.4.5"Node.js SDK通过npm安装:
npm install tablestoreGo SDK通过go get安装:
go get github.com/aliyun/aliyun-tablestore-go-sdk/tablestore需要先登录阿里云控制台,点击:阿里云控制台
4. 客户端初始化
安装完SDK后,下一步是初始化客户端。客户端初始化需要传入三个核心参数:Endpoint(实例访问地址)、AccessKey ID和AccessKey Secret。以下是各语言SDK的客户端初始化示例。
Java SDK客户端初始化:
import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.model.PrimaryKeyType;
public class TablestoreClientExample {
public static void main(String[] args) {
String endpoint = "https://myinstance.cn-beijing.ots.aliyuncs.com";
String accessKeyId = System.getenv("TABLESTORE_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("TABLESTORE_ACCESS_KEY_SECRET");
String instanceName = "myinstance";
SyncClient client = new SyncClient(endpoint, accessKeyId, accessKeySecret, instanceName);
// 使用client进行后续操作
}
}Python SDK客户端初始化:
from tablestore import OTSClient
endpoint = "https://myinstance.cn-beijing.ots.aliyuncs.com"
access_key_id = os.environ.get("TABLESTORE_ACCESS_KEY_ID")
access_key_secret = os.environ.get("TABLESTORE_ACCESS_KEY_SECRET")
instance_name = "myinstance"
client = OTSClient(endpoint, access_key_id, access_key_secret, instance_name)Node.js SDK客户端初始化:
const TableStore = require("tablestore");
const client = new TableStore.Client({
accessKeyId: process.env.TABLESTORE_ACCESS_KEY_ID,
secretAccessKey: process.env.TABLESTORE_ACCESS_KEY_SECRET,
endpoint: "https://myinstance.cn-beijing.ots.aliyuncs.com",
instancename: "myinstance"
});Go SDK客户端初始化:
package main
import (
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
"os"
)
func main() {
endpoint := "https://myinstance.cn-beijing.ots.aliyuncs.com"
accessKeyId := os.Getenv("TABLESTORE_ACCESS_KEY_ID")
accessKeySecret := os.Getenv("TABLESTORE_ACCESS_KEY_SECRET")
instanceName := "myinstance"
client := tablestore.NewClient(endpoint, instanceName, accessKeyId, accessKeySecret)
// 使用client进行后续操作
}初始化客户端后,就可以进行数据表的创建、数据的读写等操作了。
5. 数据表操作
在表格存储中,数据表是数据存储的基本单元。创建数据表时需要定义表的主键(Primary Key)结构。主键由一个或多个主键列组成,每列需要指定数据类型(如STRING、INTEGER等)。与关系型数据库不同,表格存储的数据表不需要预先定义属性列(Attribute Column)的schema,每行可以有不同的属性列,这为灵活的数据模型提供了极大便利。
以下是Java SDK创建数据表的示例:
import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.model.*;
import com.alicloud.openservices.tablestore.model.TableMeta;
import java.util.ArrayList;
import java.util.List;
public class CreateTableExample {
public static void main(String[] args) {
SyncClient client = new SyncClient(endpoint, accessKeyId, accessKeySecret, instanceName);
// 定义表结构
TableMeta tableMeta = new TableMeta("user_table");
tableMeta.addPrimaryKeyColumn("user_id", PrimaryKeyType.STRING);
tableMeta.addPrimaryKeyColumn("timestamp", PrimaryKeyType.INTEGER);
// 设置预留读写吞吐量
ReservedThroughput reservedThroughput = new ReservedThroughput(
new CapacityUnit(1, 1)); // 读1CU,写1CU
// 创建表
CreateTableRequest request = new CreateTableRequest(tableMeta, reservedThroughput);
CreateTableResponse response = client.createTable(request);
System.out.println("表创建成功");
}
}Python SDK创建数据表的示例:
from tablestore import OTSClient, TableMeta, PrimaryKeySchema, CapacityUnit
# 定义主键
primary_key_schema = [
('user_id', 'STRING'),
('timestamp', 'INTEGER')
]
# 创建表
table_meta = TableMeta('user_table', primary_key_schema)
reserved_throughput = CapacityUnit(1, 1) # 读1CU,写1CU
client.create_table(table_meta, reserved_throughput)Node.js SDK创建数据表:
const TableStore = require("tablestore");
const params = {
tableMeta: {
tableName: "user_table",
primaryKey: [
{ name: "user_id", type: "STRING" },
{ name: "timestamp", type: "INTEGER" }
]
},
reservedThroughput: {
capacityUnit: {
read: 1,
write: 1
}
}
};
client.createTable(params, function(err, data) {
if (err) {
console.log("创建表失败:", err);
} else {
console.log("创建表成功");
}
});创建表之后,可以通过describeTable接口查询表的元数据信息,包括主键结构、预留吞吐量、Stream配置、加密设置和二级索引等。如果不再需要某张表,可以使用deleteTable接口删除表。
6. 基础数据操作
表格存储的基础数据操作包括写入数据、读取数据和删除数据。写入数据支持单行插入(putRow)、批量插入(batchWriteRow)和更新行(updateRow)三种方式。读取数据支持单行读取(getRow)、批量读取(batchGetRow)和范围读取(getRange)。
6.1 写入数据
单行插入是写入单行数据到数据表中。插入时需要指定完整的主键值,并可以设置任意数量的属性列。以下是Java SDK的单行插入示例:
import com.alicloud.openservices.tablestore.model.*;
import java.util.Date;
public class PutRowExample {
public void putRow(SyncClient client) {
// 构造主键
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn("user_id", PrimaryKeyValue.fromString("user001"));
primaryKeyBuilder.addPrimaryKeyColumn("timestamp", PrimaryKeyValue.fromLong(System.currentTimeMillis()));
PrimaryKey primaryKey = primaryKeyBuilder.build();
// 构造属性列
RowPutChange rowPutChange = new RowPutChange("user_table", primaryKey);
rowPutChange.addColumn("name", ColumnValue.fromString("张三"));
rowPutChange.addColumn("age", ColumnValue.fromLong(28));
rowPutChange.addColumn("email", ColumnValue.fromString("zhangsan@example.com"));
// 执行写入
PutRowRequest request = new PutRowRequest(rowPutChange);
PutRowResponse response = client.putRow(request);
System.out.println("写入成功,消耗写CU: " + response.getConsumedCapacity().getCapacityUnit().getWriteCapacityUnit());
}
}Python SDK单行插入:
from tablestore import Row, PutRowRequest
primary_key = [('user_id', 'user001'), ('timestamp', int(time.time() * 1000))]
attribute_columns = [
('name', '张三'),
('age', 28),
('email', 'zhangsan@example.com')
]
row = Row(primary_key, attribute_columns)
request = PutRowRequest('user_table', row)
response = client.put_row(request)批量写入可以一次操作多行数据,提高写入效率,适用于数据迁移或批量导入场景。
6.2 读取数据
单行读取通过完整的主键值获取一行数据。读取时可以指定需要返回的属性列名称,也可以指定只返回特定版本范围的数据。
public void getRow(SyncClient client) {
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn("user_id", PrimaryKeyValue.fromString("user001"));
primaryKeyBuilder.addPrimaryKeyColumn("timestamp", PrimaryKeyValue.fromLong(1700000000000L));
PrimaryKey primaryKey = primaryKeyBuilder.build();
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria("user_table", primaryKey);
criteria.setMaxVersions(1); // 只返回最新版本
GetRowRequest request = new GetRowRequest(criteria);
GetRowResponse response = client.getRow(request);
Row row = response.getRow();
System.out.println("读取结果: " + row);
}范围读取可以按照主键范围获取多行数据:
public void getRange(SyncClient client) {
RangeRowQueryCriteria criteria = new RangeRowQueryCriteria("user_table");
// 设置起始主键(包含)
PrimaryKeyBuilder startBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
startBuilder.addPrimaryKeyColumn("user_id", PrimaryKeyValue.fromString("user001"));
startBuilder.addPrimaryKeyColumn("timestamp", PrimaryKeyValue.INF_MIN);
criteria.setInclusiveStartPrimaryKey(startBuilder.build());
// 设置结束主键(不包含)
PrimaryKeyBuilder endBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
endBuilder.addPrimaryKeyColumn("user_id", PrimaryKeyValue.fromString("user999"));
endBuilder.addPrimaryKeyColumn("timestamp", PrimaryKeyValue.INF_MAX);
criteria.setExclusiveEndPrimaryKey(endBuilder.build());
criteria.setMaxVersions(1);
criteria.setLimit(100); // 单次最多返回100行
GetRangeRequest request = new GetRangeRequest(criteria);
GetRangeResponse response = client.getRange(request);
for (Row row : response.getRows()) {
System.out.println(row);
}
}6.3 更新与删除
更新行可以添加、修改或删除指定行的属性列。更新操作支持原子性的条件更新,只有在满足特定条件时才执行更新。删除行通过指定完整主键即可删除整行数据。
7. 多元索引
多元索引(Search Index)是表格存储提供的高效查询能力,支持丰富的查询类型。通过多元索引,开发者可以实现全文检索、向量检索、模糊查询、范围查询、多条件组合查询等多种复杂查询模式。多元索引的创建和使用非常灵活,可以在已有数据表上创建多个索引,每个索引可以包含不同的字段和查询配置。
多元索引的核心优势在于其强大的查询能力和高效的检索性能。与传统的主键查询和二级索引不同,多元索引基于倒排索引和列式存储技术,能够在大规模数据集上实现毫秒级的复杂查询响应。在AI应用场景中,多元索引的向量检索能力尤为突出,支持基于向量相似度的语义检索。
创建多元索引时,需要指定索引名称、索引字段以及字段类型(如KEYWORD、TEXT、LONG、DOUBLE、BOOLEAN、GEO_POINT、VECTOR等)。对于TEXT类型的字段,系统会自动建立分词索引,支持全文检索。对于VECTOR类型的字段,可以指定向量维度,用于向量相似度检索。创建索引后,数据表的新增、修改、删除操作会自动同步到索引中,开发者无需手动维护索引数据。
8. 通道服务
通道服务(Tunnel Service)是基于表格存储数据接口上的全增量一体化服务。通道服务提供了增量、全量、增量加全量三种类型的分布式数据实时消费通道。通过为数据表建立数据通道,开发者可以实时订阅表中的数据变更,实现数据同步、实时计算、事件驱动等应用场景。
通道服务的三种类型各有用途。全量类型用于消费表中已有的全部历史数据。增量类型只消费通道创建之后写入的新数据。增量加全量类型则先消费全量历史数据,再自动切换到增量模式消费新数据。一张数据表上可以创建多个通道,每个通道独立消费数据。
使用通道服务时需要注意一些限制。通道的增量日志保留时间与数据表中Stream的日志过期时长保持一致,最长为7天。当通道处于全量阶段时,如果全量数据在增量日志保留时间内未能完成消费,将会触发OTSTunnelExpired错误。当通道处于增量阶段时,如果增量数据在7天内未能完成消费,通道可能从最近可消费的数据处开始消费,存在漏消费数据的风险。通道过期后,表格存储可能会禁用该通道,如果禁用状态持续超过30天,通道将被彻底删除。
以下是使用Java SDK创建通道的简要示例:
CreateTunnelRequest request = new CreateTunnelRequest("user_table", "my_tunnel", TunnelType.FullAndIncremental);
CreateTunnelResponse response = client.createTunnel(request);
String tunnelId = response.getTunnelId();创建通道后,可以通过TunnelWorker来消费通道中的数据。TunnelWorker需要注册一个IChannelProcessor接口的实现,用于处理从通道中读取到的每条数据记录。
9. 时序模型
时序模型是表格存储针对时间序列数据特点专门设计的存储模型。在时序模型中,采用一张二维的时序表来存储时序数据。每行代表一个时间轴在某个时间点的数据,主键部分为时间轴标识和时间戳,数据列部分为该时间轴在该时间戳下的数据点。时序模型的主键结构和数据列结构无须用户进行预定义,提供了极大的灵活性。
使用时序模型时,首先需要创建时序表。时序表的创建可以通过控制台、命令行工具或SDK完成。创建时序表时,需要指定时序表的名称、时间轴标识字段(即主键中用于标识时间轴的列)和时间戳字段。创建完成后,可以向时序表中写入时序数据。时序数据由元数据和数据两部分组成,如果未预先创建元数据,系统会根据写入的数据自动提取元数据。
时序模型支持通过SDK进行时间轴检索和时序数据查询。时间轴检索可以根据条件筛选符合要求的时间轴;时序数据查询可以按时间范围、标签条件等检索特定时间序列的数据点。时序模型的典型应用场景包括物联网设备监控、服务器性能监控、工业设备数据采集等。
以下是使用Python SDK操作时序模型的简要示例:
# 创建时序表
client.create_timeseries_table("sensor_data", "device_id", "timestamp")
# 写入时序数据
row = {
"device_id": "sensor_001",
"timestamp": int(time.time() * 1000),
"temperature": 25.6,
"humidity": 60.2
}
client.put_timeseries_row("sensor_data", row)10. 与大数据生态集成
表格存储与阿里云大数据生态有着良好的集成能力。通过DataWorks数据集成,可以实现Tablestore与MySQL、Oracle、MaxCompute、OSS等多种异构数据源之间的数据迁移与同步。在DataWorks中,只需要添加Tablestore数据源,即可配置数据同步任务,实现数据库数据迁移到表格存储、表格存储数据跨实例迁移、表格存储数据备份到OSS或MaxCompute等场景。
通过与实时计算Flink版的集成,可以实现对表格存储数据的实时采集与处理。实时计算Flink版内置了Tablestore连接器,支持将Tablestore作为源表、维表和结果表使用。作为源表时,可以实时消费Tablestore通道服务中的数据;作为维表时,可以在流式计算中实时关联查询Tablestore中的维度数据;作为结果表时,可以将流式计算结果实时写入Tablestore。
使用Flink SQL操作Tablestore的示例如下:
CREATE TABLE ots_sink (
name VARCHAR,
age BIGINT,
birthday BIGINT,
primary key(name, age) not enforced
) WITH (
'connector'='ots',
'instanceName'='myinstance',
'tableName'='user_table',
'accessId'='${ak_id}',
'accessKey'='${ak_secret}',
'endPoint'='https://myinstance.cn-beijing.ots.aliyuncs.com',
'valueColumns'='birthday'
);此外,Tablestore还支持通过Spark计算引擎进行数据分析。通过Spark的DataFrame API,可以对Tablestore中的数据进行批量分析和流式处理。这种集成方式使得Tablestore不仅是一个高性能的在线数据库,也可以作为数据湖分析架构中的存储层。
11. 最佳实践
在使用表格存储的过程中,遵循一些最佳实践可以显著提升系统的性能、可用性和成本效益。
主键设计是表格存储表设计中最关键的部分。表格存储按分区键范围自动将数据切分到多个服务节点。分区键选择不当会导致热点、数据倾斜或扩展瓶颈。建议选择离散度高、分布均匀的字段作为分区键。如果业务主键本身不具备良好的离散性,可以考虑将多个字段拼接成分区键。同时,建议表中同一分区键值下的数据量不超过10GB。
属性列设计方面,应避免在属性列中存储过大的数据(如超过1MB的文本或二进制数据),这类数据建议存入OSS并用URL引用。对于经常用于查询过滤的属性列,可以考虑将其纳入多元索引,以提升查询效率。
在成本控制方面,表格存储提供了多种优化手段。首先是合理设置预留吞吐量,避免过度预留造成浪费。其次是利用TTL(数据生命周期)自动过期删除不再需要的历史数据。对于时序数据等冷热分明的数据,可以通过表格存储的冷热分层存储功能,将早期数据自动转移到低成本存储介质上。
在安全性方面,建议始终使用RAM用户的AccessKey而非主账号的AccessKey。通过RAM Policy可以实现细粒度的权限控制,包括对特定实例、特定表的访问控制。此外,还可以结合Network ACL和Instance Policy等多层安全机制,构建全方位的安全防护体系。
12. 常见问题解答
问:表格存储和传统关系型数据库的主要区别是什么?
答:表格存储是NoSQL数据库,采用Schema-free的设计,不需要预先定义所有列,每行可以有不同属性列。它天然支持水平扩展,适合海量数据和高并发场景。而传统关系型数据库需要预先定义表结构,在数据量极大时扩展性受限。
问:如何选择VCU模式和CU模式?
答:VCU模式(预留模式)适合业务负载相对稳定的场景,通过预留计算单元保障性能,成本可预测。CU模式(按量付费)适合业务负载波动较大的场景,按实际使用的读写吞吐量计费,更加灵活经济。
问:多元索引和全局二级索引有什么区别?
答:全局二级索引是基于主键的索引,主要用于加速基于非主键列的查询,查询结果返回完整的行数据。多元索引支持更丰富的查询类型(全文检索、向量检索、范围查询、多条件组合等),基于倒排索引实现,查询能力更强,但索引创建和更新有一定延迟。
问:通道服务的数据消费延迟大概是多少?
答:通道服务的数据消费延迟通常在秒级以内,具体取决于数据量、网络条件和消费端的处理能力。但需要注意通道的增量日志保留时间最长为7天,如果消费不及时可能导致数据丢失。
问:表格存储支持跨账号访问吗?
答:支持。跨账号访问Tablestore实例时,如果使用VPC地址访问,需要与Flink等计算引擎位于同一地域,且AccessKey需要填写Tablestore实例所在账号的AccessKey。也可以通过RAM角色的跨账号授权方式实现。
问:如何监控表格存储的使用情况和性能?
答:表格存储提供了丰富的监控指标,包括存储量、读写吞吐量、请求延迟、请求次数等。可以在阿里云控制台的云监控服务中查看这些指标,也可以设置告警规则,在指标异常时及时收到通知。



