1. 簡介
在本程式碼研究室中,您將使用 Cloud Bigtable 的監控工具,透過 Cloud Dataflow 與 Java HBase 用戶端寫入及讀取資料,藉此建立各種藝術作品。
你將瞭解如何
- 使用 Cloud Dataflow 將大量資料載入 Bigtable
- 在擷取資料時監控 Bigtable 執行個體和資料表
- 使用 Dataflow 工作查詢 Bigtable
- 探索 Key Visualizer 工具,該工具可用來找出符合結構定義設計的流量資源使用率不均的問題
- 利用 Key Visualizer 創作藝術

您對 Cloud Bigtable 的使用體驗如何?
您會如何使用這個教學課程?
2. 建立 Bigtable 資料庫
Google BigTable 是 Google 的 NoSQL 大數據資料庫服務,也是許多核心 Google 服務採用的資料庫,包括 Google 搜尋、Analytics、Google 地圖和 Gmail。非常適合執行大型分析工作負載及建構低延遲應用程式。請參閱「Cloud Bigtable 程式碼研究室簡介」
建立專案
首先,請建立新專案。使用內建的 Cloud Shell,只要按一下「啟用 Cloud Shell」即可開啟。

請設定下列環境變數,方便複製及貼上程式碼研究室指令:
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 隨附您將在本程式碼研究室中使用的工具,包括 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 迴圈) 來寫入含有數 MB 隨機資料的資料列。資料列索引鍵將是填充及反轉的序號,因此 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 工作,在資料表產生 40 GB 的資料,比 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 UI 中監控工作。另外,您也可以透過監控 UI 查看 Cloud Bigtable 執行個體的負載。
在 Dataflow UI 中,您可以查看工作圖表和各種工作指標,包括已處理的元素、目前的 vCPU 和處理量。


Bigtable 具備標準監控工具,可在執行個體、叢集和資料表層級執行讀取/寫入作業、使用的儲存空間、錯誤率等。此外,Bigtable 也具備 Key Visualizer,能根據資料列索引鍵細分用量,並在至少 30 GB 的資料產生後使用。

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)));
接著使用設定和 getConnection() 呼叫 super(),取得分散式連線。
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 工作
在本程式碼研究室中,您每秒必須讀取資料表,以便利用產生的序列來啟動管道。這個序列會根據輸入的 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
將「Storage Object Viewer」角色授予 allUsers,即可公開您的 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 分鐘後,您就能開始在金鑰視覺化工具中看到活動。您可以搭配使用多種參數:縮放、亮度和指標。如要縮放,可以使用滑鼠上的滾輪,或是在按鍵視覺化工具格線中拖曳矩形。
亮度會變更圖片的縮放比例,如果你想要細看非常熱的區域,就很適合使用。

您也可以調整要顯示的指標。包括 OP、讀取位元組用戶端、寫入位元組用戶端等等。「讀取位元組用戶端」似乎在「營運」時產生平滑的圖片這種圖像會產生較多線條,在部分圖片上看起來很酷

8. 完成
清除所用資源,以免產生費用
如要避免系統向您的 Google Cloud Platform 帳戶收取這個程式碼研究室所用資源的費用,請刪除執行個體。
gcloud bigtable instances delete $INSTANCE_ID
涵蓋內容
- 使用 Dataflow 寫入 Bigtable
- 使用 Dataflow 從 Bigtable 讀取資料 (在管道一開始時,也就是管道中間)
- 使用 Dataflow 監控工具
- 使用 Bigtable 監控工具 (包括 Key Visualizer)
後續步驟
- 進一步瞭解 Key Visualizer 藝術的建立方式。
- 如要進一步瞭解 Cloud Bigtable,請參閱說明文件。
- 自行試用其他 Google Cloud Platform 功能。歡迎參考我們的教學課程。