1. 简介
在此 Codelab 中,您将使用 Cloud Bigtable 的监控工具,通过使用 Cloud Dataflow 和 Java HBase 客户端写入和读取数据,来创作各种艺术作品。
您将了解如何
- 使用 Cloud Dataflow 将大量数据加载到 Bigtable 中
- 在提取数据时监控 Bigtable 实例和表
- 使用 Dataflow 作业查询 Bigtable
- 探索 Key Visualizer 工具,该工具可用于根据您的架构设计找出热点
- 使用 Key Visualizer 打造艺术作品

您如何评价自己使用 Cloud Bigtable 的体验?
您打算如何使用本教程?
<ph type="x-smartling-placeholder">2. 创建 Bigtable 数据库
Cloud Bigtable 是 Google 面向大数据领域的 NoSQL 数据库服务。它也是为 Google 搜索、Google Analytics、Google 地图和 Gmail 等众多核心 Google 服务提供支撑的数据库。它非常适合运行大型分析工作负载和构建低延迟应用。查看 Cloud Bigtable 简介 Codelab 以获取深入介绍。
创建项目
首先,创建一个新项目。使用内置的 Cloud Shell(点击“激活 Cloud Shell”即可打开)按钮。

设置以下环境变量,以便更轻松地复制和粘贴 Codelab 命令:
BIGTABLE_PROJECT=$GOOGLE_CLOUD_PROJECT INSTANCE_ID="keyviz-art-instance" CLUSTER_ID="keyviz-art-cluster" TABLE_ID="art" CLUSTER_NUM_NODES=1 CLUSTER_ZONE="us-central1-c" # You can choose a zone closer to you
Cloud Shell 附带您将在此 Codelab 中使用的工具,即 gcloud 命令行工具、cbt 命令行界面和 Maven。
运行此命令来启用 Cloud Bigtable API。
gcloud services enable bigtable.googleapis.com bigtableadmin.googleapis.com
通过运行以下命令来创建实例:
gcloud bigtable instances create $INSTANCE_ID \
--cluster=$CLUSTER_ID \
--cluster-zone=$CLUSTER_ZONE \
--cluster-num-nodes=$CLUSTER_NUM_NODES \
--display-name=$INSTANCE_ID
创建实例后,填充 cbt 配置文件,然后通过运行以下命令创建表和列族:
echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc echo instance = $INSTANCE_ID >> ~/.cbtrc cbt createtable $TABLE_ID cbt createfamily $TABLE_ID cf
3. 学习:使用 Dataflow 向 Bigtable 写入数据
写作基础知识
向 Cloud Bigtable 写入数据时,您必须提供一个 CloudBigtableTableConfiguration 配置对象。此对象指定了表的项目 ID 和实例 ID,以及表本身的名称:
CloudBigtableTableConfiguration bigtableTableConfig =
new CloudBigtableTableConfiguration.Builder()
.withProjectId(PROJECT_ID)
.withInstanceId(INSTANCE_ID)
.withTableId(TABLE_ID)
.build();
然后,流水线可以传递 HBase Mutation 对象,其中可能包括 Put 和 Delete。
p.apply(Create.of("hello", "world"))
.apply(
ParDo.of(
new DoFn<String, Mutation>() {
@ProcessElement
public void processElement(@Element String rowkey, OutputReceiver<Mutation> out) {
long timestamp = System.currentTimeMillis();
Put row = new Put(Bytes.toBytes(rowkey));
row.addColumn(...);
out.output(row);
}
}))
.apply(CloudBigtableIO.writeToTable(bigtableTableConfig));
LoadData Dataflow 作业
下一页将介绍如何运行 LoadData 作业,但我在这里只介绍流水线的重要部分。
要生成数据,您需要创建一个使用 GenerateSequence 类(类似于 for 循环)的流水线,以写入若干行(包含几兆字节的随机数据)。rowkey 将是填充和反转的序列号,因此 250 会变为 0000000052。
LoadData.java
String numberFormat = "%0" + maxLength + "d";
p.apply(GenerateSequence.from(0).to(max))
.apply(
ParDo.of(
new DoFn<Long, Mutation>() {
@ProcessElement
public void processElement(@Element Long rowkey, OutputReceiver<Mutation> out) {
String paddedRowkey = String.format(numberFormat, rowkey);
// Reverse the rowkey for more efficient writing
String reversedRowkey = new StringBuilder(paddedRowkey).reverse().toString();
Put row = new Put(Bytes.toBytes(reversedRowkey));
// Generate random bytes
byte[] b = new byte[(int) rowSize];
new Random().nextBytes(b);
long timestamp = System.currentTimeMillis();
row.addColumn(Bytes.toBytes(COLUMN_FAMILY), Bytes.toBytes("C"), timestamp, b);
out.output(row);
}
}))
.apply(CloudBigtableIO.writeToTable(bigtableTableConfig));
4. 将数据生成到 Bigtable 中并监控流入
以下命令将运行一个 Dataflow 作业,该作业向表中生成 40GB 的数据,这足以让 Key Visualizer 激活它:
启用 Cloud Dataflow API
gcloud services enable dataflow.googleapis.com
从 GitHub 获取代码并切换到该目录
git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git cd java-docs-samples/bigtable/beam/keyviz-art
生成数据(脚本大约需要 15 分钟)
mvn compile exec:java -Dexec.mainClass=keyviz.LoadData \ "-Dexec.args=--bigtableProjectId=$BIGTABLE_PROJECT \ --bigtableInstanceId=$INSTANCE_ID --runner=dataflow \ --bigtableTableId=$TABLE_ID --project=$GOOGLE_CLOUD_PROJECT"
监控导入
您可以在 Cloud Dataflow 界面中监控该作业。此外,您还可以通过 Cloud Bigtable 实例的监控界面查看其负载。
在 Dataflow 界面中,您可以看到作业图和各种作业指标,包括已处理的元素、当前 vCPU 和吞吐量。


Bigtable 提供标准监控工具,可用于监控实例级、集群级和表级读写操作、已使用的存储空间、错误率等。除此之外,Bigtable 还具有 Key Visualizer,它会根据行键细分您的使用情况,当至少生成 30GB 的数据后,我们就会使用该行键。

5. 学习:使用 Dataflow 从 Bigtable 读取数据
阅读基础知识
从 Cloud Bigtable 读取数据时,您必须提供一个 CloudBigtableTableScanConfiguration 配置对象。它与 CloudBigtableTableConfiguration 类似,但您可以指定要扫描和读取的行。
Scan scan = new Scan();
scan.setCacheBlocks(false);
scan.setFilter(new FirstKeyOnlyFilter());
CloudBigtableScanConfiguration config =
new CloudBigtableScanConfiguration.Builder()
.withProjectId(options.getBigtableProjectId())
.withInstanceId(options.getBigtableInstanceId())
.withTableId(options.getBigtableTableId())
.withScan(scan)
.build();
然后使用它来启动流水线:
p.apply(Read.from(CloudBigtableIO.read(config)))
.apply(...
不过,如果您想在流水线中执行读取操作,可以将 CloudBigtableTableConfiguration 传递给扩展 AbstractCloudBigtableTableDoFn 的 doFn。
p.apply(GenerateSequence.from(0).to(10))
.apply(ParDo.of(new ReadFromTableFn(bigtableTableConfig, options)));
然后,使用您的配置调用 super() 和 getConnection(),以获取分布式连接。
public static class ReadFromTableFn extends AbstractCloudBigtableTableDoFn<Long, Void> {
public ReadFromTableFn(CloudBigtableConfiguration config, ReadDataOptions readDataOptions) {
super(config);
}
@ProcessElement
public void processElement(PipelineOptions po) {
Table table = getConnection().getTable(TableName.valueOf(options.getBigtableTableId()));
ResultScanner imageData = table.getScanner(scan);
}
}
ReadData Dataflow 作业
在此 Codelab 中,您需要每秒从表中读取数据,因此您可以使用生成的序列启动流水线,该序列根据输入的 CSV 文件的时间触发多个读取范围。
要确定在指定时间内扫描哪些行范围,需要完成一些数学运算,但如果您想了解详情,可以点击文件名来查看源代码。
ReadData.java
p.apply(GenerateSequence.from(0).withRate(1, new Duration(1000)))
.apply(ParDo.of(new ReadFromTableFn(bigtableTableConfig, options)));
ReadData.java
public static class ReadFromTableFn extends AbstractCloudBigtableTableDoFn<Long, Void> {
List<List<Float>> imageData = new ArrayList<>();
String[] keys;
public ReadFromTableFn(CloudBigtableConfiguration config, ReadDataOptions readDataOptions) {
super(config);
keys = new String[Math.toIntExact(getNumRows(readDataOptions))];
downloadImageData(readDataOptions.getFilePath());
generateRowkeys(getNumRows(readDataOptions));
}
@ProcessElement
public void processElement(PipelineOptions po) {
// Determine which column will be drawn based on runtime of job.
long timestampDiff = System.currentTimeMillis() - START_TIME;
long minutes = (timestampDiff / 1000) / 60;
int timeOffsetIndex = Math.toIntExact(minutes / KEY_VIZ_WINDOW_MINUTES);
ReadDataOptions options = po.as(ReadDataOptions.class);
long count = 0;
List<RowRange> ranges = getRangesForTimeIndex(timeOffsetIndex, getNumRows(options));
if (ranges.size() == 0) {
return;
}
try {
// Scan with a filter that will only return the first key from each row. This filter is used
// to more efficiently perform row count operations.
Filter rangeFilters = new MultiRowRangeFilter(ranges);
FilterList firstKeyFilterWithRanges = new FilterList(
rangeFilters,
new FirstKeyOnlyFilter(),
new KeyOnlyFilter());
Scan scan =
new Scan()
.addFamily(Bytes.toBytes(COLUMN_FAMILY))
.setFilter(firstKeyFilterWithRanges);
Table table = getConnection().getTable(TableName.valueOf(options.getBigtableTableId()));
ResultScanner imageData = table.getScanner(scan);
} catch (Exception e) {
System.out.println("Error reading.");
e.printStackTrace();
}
}
/**
* Download the image data as a grid of weights and store them in a 2D array.
*/
private void downloadImageData(String artUrl) {
...
}
/**
* Generates an array with the rowkeys that were loaded into the specified Bigtable. This is
* used to create the correct intervals for scanning equal sections of rowkeys. Since Bigtable
* sorts keys lexicographically if we just used standard intervals, each section would have
* different sizes.
*/
private void generateRowkeys(long maxInput) {
...
}
/**
* Get the ranges to scan for the given time index.
*/
private List<RowRange> getRangesForTimeIndex(@Element Integer timeOffsetIndex, long maxInput) {
...
}
}
6. 创作精彩作品

现在,您已了解如何将数据加载到 Bigtable 中并使用 Dataflow 从中读取数据,您可以运行最后一个命令了,该命令将在 8 小时内生成《蒙娜丽莎》的图片。
mvn compile exec:java -Dexec.mainClass=keyviz.ReadData \ "-Dexec.args=--bigtableProjectId=$BIGTABLE_PROJECT \ --bigtableInstanceId=$INSTANCE_ID --runner=dataflow \ --bigtableTableId=$TABLE_ID --project=$GOOGLE_CLOUD_PROJECT"
您可以使用包含现有图片的存储分区。您也可以使用此工具根据您自己的任何图片创建输入文件,然后将其上传到公开的 GCS 存储分区。
文件名根据 gs://keyviz-art/[painting]_[hours]h.txt 生成,示例:gs://keyviz-art/american_gothic_4h.txt
绘制选项:
- american_gothic
- mona_lisa
- pearl_earring
- persistence_of_memory
- starry_night
- sunday_afternoon
- the_scream
小时选项:1、4、8、12、24、48、72、96、120、144
向 allUsers 授予角色 Storage Object Viewer,以公开您的 GCS 存储分区或文件。

选择图片后,只需在以下命令中更改 --file-path 参数即可:
mvn compile exec:java -Dexec.mainClass=keyviz.ReadData \ "-Dexec.args=--bigtableProjectId=$BIGTABLE_PROJECT \ --bigtableInstanceId=$INSTANCE_ID --runner=dataflow \ --bigtableTableId=$TABLE_ID --project=$GOOGLE_CLOUD_PROJECT \ --filePath=gs://keyviz-art/american_gothic_4h.txt"
7. 稍后再查看
完整图像可能需要几个小时才能生效,但在 30 分钟后,您应该就会开始在 Key Visualizer 中看到活动。您可以使用以下参数:缩放、亮度和公制。您可以通过以下方法进行缩放:使用鼠标上的滚轮,或在 Key Visualizer 网格上拖动矩形。
亮度可以更改图片的缩放比例,如果您想深入观察非常热的区域,这会非常有用。

您还可以调整要显示的指标。有 OP、读取字节客户端、写入字节客户端等等。"读取字节客户端"似乎生成了平滑的图片,而“Ops”生成的图片中的线条越多,这在一些图片上看起来会非常棒。

8. 完成
清理相关资源以避免产生费用
为避免系统因此 Codelab 中使用的资源向您的 Google Cloud Platform 账号收取费用,您应删除您的实例。
gcloud bigtable instances delete $INSTANCE_ID
所学内容
- 使用 Dataflow 向 Bigtable 写入数据
- 使用 Dataflow 从 Bigtable 读取数据(在流水线的起点,流水线的中间)
- 使用 Dataflow 监控工具
- 使用 Bigtable 监控工具(包括 Key Visualizer)
后续步骤
- 详细了解 Key Visualizer 图片的创建方式。
- 如需详细了解 Cloud Bigtable,请参阅文档。
- 试用其他 Google Cloud Platform 功能。查阅我们的教程。