1. 简介
此 Codelab 是面向将查询从 Apache Cassandra 迁移到 Google Cloud Bigtable 的所有用户的指南。
在此 Codelab 中,您将:
- 使用 Cloud Bigtable 模拟器
- 探索时间序列使用场景
- 创建表和列族
- 了解 CQL 插入、更新、选择和删除的 Cloud Bigtable Java 等效项
您如何评价自己使用 Google Cloud Platform 的体验?
您打算如何使用本教程?
<ph type="x-smartling-placeholder">2. 设置
您将看到一个只包含几行的示例数据集,以便您快速了解核心概念。
Cassandra
每个步骤都会提供等效的 Cassandra 查询,因此您可以根据需要随时在本地集群进行操作,也可以快速设置一键部署的 Cassandra 集群并通过 SSH 连接到该集群。
如果您一直按照这些说明操作,请创建一个键空间并使用它。复制策略在这里并不重要。
cqlsh> create keyspace mykeyspace with replication = {'class':'SimpleStrategy','replication_factor' : 2}; cqlsh> use mykeyspace;
Cloud Bigtable
您需要为表创建一个 Cloud Bigtable 实例。您可以使用模拟器免费设置本地实例。您无需在 Cloud Bigtable 中创建键空间,复制操作由实例配置处理。
使用以下命令启动模拟器:
gcloud beta emulators bigtable start
然后在另一个 shell 窗口或标签页中使用以下命令设置模拟器环境变量:
$(gcloud beta emulators bigtable env-init) #Sets BIGTAB`LE_EMULATOR_HOST
然后创建一个用于运行代码示例的 Java 项目,并使用 Maven、Gradle 或 SBT 导入 Cloud Bigtable 客户端。然后在新的 Java 文件中创建与数据客户端的连接。
BigtableDataSettings settings =
BigtableDataSettings.newBuilder().setProjectId(projectId).setInstanceId(instanceId).build();
try {
dataClient = BigtableDataClient.create(settings);
} catch (Exception e) {
System.out.println("Error during data client connection: \n" + e.toString());
}
3. 表创建
在 Cassandra 和 Cloud Bigtable 表中,每一行都有一个与之关联的键。Cassandra 键具有可以单独或重叠的分区键和聚簇列。Cloud Bigtable 的全部键都用于分块(分区)和排序。在主键/行键构建方面,这两个系统非常相似。这两个系统基本上都是按字典顺序排序的列表,其中键充当节点之间行分布的主要形式。在大多数情况下,您可以对 Cloud Bigtable 重复使用同一键。
在此 Codelab 中,您将使用 Cloud Bigtable 来存储有关手机和平板电脑的时间序列数据(不要与 Bigtable 平板电脑混淆)。以下是有关如何创建表的说明。
Cassandra
cqlsh:mykeyspace> create table mobileTimeSeries ( deviceid text, devicetype text, date date, connected_cell map<timestamp,Boolean>, os_build text, os_name text, PRIMARY KEY((devicetype, deviceid), date));
Cloud Bigtable
您可以使用 Java 客户端创建表和列族,但最简单的方法是将以下命令与 cbt 工具搭配使用:
cbt createtable mobile-time-series families=stats_summary
Cloud Bigtable 是一个 NoSQL 数据库,因此您无需在创建表时定义架构,但您需要考虑将要运行的查询并为其优化行键。
键迁移最常见的策略就是将所有分区键和聚簇列联接起来,形成一个表示 Cloud Bigtable 行键的字符串。我们通常建议使用基于字符串的键,因为它们有助于通过 Key Visualizer 调试键分布。您可以使用井号“#”等分隔符以提高可读性。
在此示例中,我们将使用行键“[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]”
4. 插入内容
Cassandra 与 Cloud Bigtable 之间的插入非常相似。您将在此处使用行键“[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]”插入一行,然后使用行键插入多行。
Cassandra
单个
cqlsh:mykeyspace> insert into mobileTimeSeries (deviceid, devicetype, date, connected_cell, os_build) values ('4c410523', 'phone',toDate(now()), {toTimeStamp(now()): true}, 'PQ2A.190405.003');
Batch
cqlsh:mykeyspace> BEGIN BATCH insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-01', 'chromeos', '12155.0.0-rc1'); insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-02','chromeos', '12145.0.0-rc6'); APPLY BATCH;
Cloud Bigtable
单个
使用您要使用的行键和数据创建变更,然后在数据客户端中应用变更。您将为一部手机添加一行数据,其中包含有关手机的移动网络连接和操作系统的信息。
try {
System.currentTimeMillis();
long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00
String rowKey = "phone#4c410523#20190501";
ByteString one = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 1});
RowMutation rowMutation =
RowMutation.create(tableId, rowKey)
.setCell(
COLUMN_FAMILY_NAME,
ByteString.copyFrom("connected_cell".getBytes()),
timestamp,
one)
.setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "PQ2A.190405.003");
dataClient.mutateRow(rowMutation);
} catch (Exception e) {
System.out.println("Error during Write: \n" + e.toString());
}
Batch
在 BulkMutation 对象上定义多项更改,然后使用数据客户端通过一次 API 调用应用所有更改。您需要添加几天关于移动设备操作系统名称和版本的数据。
try {
long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00
BulkMutation bulkMutation =
BulkMutation.create(tableId)
.add(
"tablet#a0b81f74#20190501",
Mutation.create()
.setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
.setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc1"))
.add(
"tablet#a0b81f74#20190502",
Mutation.create()
.setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
.setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc6"));
dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
System.out.println("Error during WriteBatch: \n" + e.toString());
}
5. 最新动态
在这里,您将更新一个尚未写入的单元格,然后在该单元格中写入新值,同时保留之前的版本。
Cassandra
添加单元格
cqlsh:mykeyspace> UPDATE mobileTimeSeries SET os_name = 'android' WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';
更新单元格
cqlsh:mykeyspace> UPDATE mobileTimeSeries SET connected_cell = connected_cell + {toTimeStamp(now()): false} WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';
Cloud Bigtable
在 Cloud Bigtable 中,您可以只将更新视为写入。
添加单元格
这与写入单元格相同,只需提供之前没有写入的列。在这里,您可以将操作系统名称添加到手机所在的行中。
try {
long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30
String rowKey = "phone#4c410523#20190501";
RowMutation rowMutation =
RowMutation.create(tableId, rowKey)
.setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "android");
dataClient.mutateRow(rowMutation);
} catch (Exception e) {
System.out.println("Error during update: \n" + e.toString());
}
正在更新单元格
您可以在此处添加有关手机移动网络连接状态的新数据。您可以使用单元格版本轻松存储部分时间序列数据。只需为写入操作提供时间戳,即可为单元格添加一个新版本。如需清理数据,您可以使用垃圾回收功能删除一定数量或一段时间后的版本。
try {
long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30
String rowKey = "phone#4c410523#20190501";
ByteString zero = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 0});
RowMutation rowMutation =
RowMutation.create(tableId, rowKey)
.setCell(
COLUMN_FAMILY_NAME,
ByteString.copyFrom("connected_cell".getBytes()),
timestamp,
zero);
dataClient.mutateRow(rowMutation);
} catch (Exception e) {
System.out.println("Error during update2: \n" + e.toString());
}
6. 选择
现在,您将检索已写入表中的数据。迁移 CQL select 语句时,您需要考虑 select 语句的多个方面,例如列、通过 where 子句进行过滤,以及限制和聚合函数(例如分组依据)。在这里,您只需看两个简单的 select 语句即可了解基本概念,也可以参阅相关文档,详细了解如何选择。在 Cloud Bigtable 中,有两种类型的检索操作:Get(获取)和 Scan(扫描)。Get 检索一行,而扫描则检索一定范围的行。
Cassandra
单个
cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-04';
多个
cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='tablet' AND deviceid = 'a0b81f74' AND date >= '2019-09-04';
Cloud Bigtable
单身
使用行查询可获取指定日期特定手机的数据,这些数据全都在一行内。这将返回值的每个带有时间戳的版本,因此您应该会在不同的时间戳看到 connected_cell 有两行。
try {
String rowKey = "phone#4c410523#20190501";
Row row = dataClient.readRow(tableId, rowKey);
for (RowCell cell : row.getCells()) {
System.out.printf(
"Family: %s Qualifier: %s Value: %s Timestamp: %s%n",
cell.getFamily(),
cell.getQualifier().toStringUtf8(),
cell.getValue().toStringUtf8(),
cell.getTimestamp());
}
} catch (Exception e) {
System.out.println("Error during lookup: \n" + e.toString());
}
多个
使用范围扫描可查看指定移动设备一个月内的数据(这些数据分布在多个行中)。您可以对过滤条件使用过滤条件,以便仅获取特定版本的数据或过滤值。
try {
Query query = Query.create(tableId).range("tablet#a0b81f74#201905", "tablet#a0b81f74#201906");
ServerStream<Row> rowStream = dataClient.readRows(query);
for (Row row : rowStream) {
System.out.println("Row Key: " + row.getKey().toStringUtf8());
for (RowCell cell : row.getCells()) {
System.out.printf(
"Family: %s Qualifier: %s Value: %s Timestamp: %s%n",
cell.getFamily(),
cell.getQualifier().toStringUtf8(),
cell.getValue().toStringUtf8(),
cell.getTimestamp());
}
}
} catch (Exception e) {
System.out.println("Error during scan: \n" + e.toString());
}
7. 删除
在这里,您可以删除已放入表格中的数据。首先,您需要删除一行,然后需要删除多行。
Cassandra 的 CQL 支持在指定了所有主要列的情况下删除单行和范围。您可以对 Bigtable 执行此操作,方法是扫描某个范围,然后执行行级删除。请注意,您得到的结果是相同的,但会有更多操作,因为每次删除都是自己的操作。
Cassandra
单个
cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='phone' and deviceid = '4c410523';
多个
cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='tablet' and deviceid = 'a0b81f74';
Cloud Bigtable
单个
在这里,您可以删除特定电话号码和日期的数据。使用行键一次删除一行。
try {
String rowKey = "phone#4c410523#20190501";
RowMutation mutation = RowMutation.create(tableId, rowKey).deleteRow();
dataClient.mutateRow(mutation);
} catch (Exception e) {
System.out.println("Error during Delete: \n" + e.toString());
}
多个
在这里,您可以删除特定移动设备的所有数据。要迁移删除多行的 CQL 查询,您需要执行扫描,然后使用生成的一组行键删除每一行。
try {
Query query = Query.create(tableId).prefix("tablet#a0b81f7");
ServerStream<Row> rowStream = dataClient.readRows(query);
BulkMutation bulkMutation = BulkMutation.create(tableId);
for (Row row : rowStream) {
bulkMutation.add(row.getKey(), Mutation.create().deleteRow());
}
dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
System.out.println("Error during DeleteMultiple: \n" + e.toString());
}
8. 即将完成
清理
Cassandra
如果您创建了 Cassandra 集群来执行此操作,请照常将其删除。
Cloud Bigtable
如果您在现有 Cloud Bigtable 实例上创建了表,则可以使用 cbt 命令将其删除
cbt deletetable mobile-time-series
如果您使用了模拟器,只需在启动模拟器的终端中输入 CTRL-C,停止模拟器以清除所有工作。
后续步骤
- 如需详细了解 Cloud Bigtable,请参阅文档。
- 深入试用 Cloud Bigtable Codelab
- 试用其他 Google Cloud Platform 功能。查阅我们的教程。
- 了解如何使用 OpenTSDB 集成监控时间序列数据