1. Wprowadzenie
W ramach tego ćwiczenia w programowaniu użyjesz narzędzi do monitorowania Cloud Bigtable, aby tworzyć różne dzieła sztuki, zapisując i odczytując dane za pomocą Cloud Dataflow oraz klienta Java HBase.
Dowiesz się,
- Wczytywanie do Bigtable dużych ilości danych za pomocą Cloud Dataflow
- Monitorowanie instancji i tabel Bigtable podczas przetwarzania danych
- Wysyłanie zapytania do Bigtable za pomocą zadania Dataflow
- Poznaj narzędzie Key Visualizer, którego można używać do znajdowania hotspotów ze względu na Twój schemat
- Tworzenie dzieł sztuki za pomocą usługi Key Visualizer
Jak oceniasz korzystanie z Cloud Bigtable?
Jak wykorzystasz ten samouczek?
2. Tworzenie bazy danych Bigtable
Cloud Bigtable to oferowana przez Google usługa baz danych NoSQL do obsługi big data. Z tej samej bazy danych korzysta wiele podstawowych usług Google, m.in. wyszukiwarki, Analytics, Map i Gmaila. Idealnie nadaje się do uruchamiania dużych zbiorów zadań analitycznych i tworzenia aplikacji z małymi opóźnieniami. Więcej informacji znajdziesz w przewodniku Wprowadzenie do Cloud Bigtable Codelabs.
Utwórz projekt
Najpierw utwórz nowy projekt. Użyj wbudowanej usługi Cloud Shell, którą możesz otworzyć, klikając „Aktywuj Cloud Shell”. w prawym górnym rogu.
Aby ułatwić sobie kopiowanie i wklejanie poleceń ćwiczenia w programie, ustaw następujące zmienne środowiskowe:
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 zawiera narzędzia, których użyjesz w tym ćwiczeniu z programowania, narzędzie wiersza poleceń gcloud, interfejs wiersza poleceń cbt i Maven.
Włącz interfejsy Cloud Bigtable API, uruchamiając to polecenie.
gcloud services enable bigtable.googleapis.com bigtableadmin.googleapis.com
Utwórz instancję, uruchamiając to polecenie:
gcloud bigtable instances create $INSTANCE_ID \ --cluster=$CLUSTER_ID \ --cluster-zone=$CLUSTER_ZONE \ --cluster-num-nodes=$CLUSTER_NUM_NODES \ --display-name=$INSTANCE_ID
Po utworzeniu instancji wypełnij plik konfiguracji cbt, a następnie utwórz tabelę i grupę kolumn, uruchamiając te polecenia:
echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc echo instance = $INSTANCE_ID >> ~/.cbtrc cbt createtable $TABLE_ID cbt createfamily $TABLE_ID cf
3. Naucz się pisać w Bigtable za pomocą Dataflow
Podstawy pisania
Podczas zapisywania danych w Cloud Bigtable musisz podać obiekt konfiguracji CloudBigtableTableConfiguration
. Ten obiekt określa identyfikator projektu i instancji dla Twojej tabeli oraz nazwę samej tabeli:
CloudBigtableTableConfiguration bigtableTableConfig = new CloudBigtableTableConfiguration.Builder() .withProjectId(PROJECT_ID) .withInstanceId(INSTANCE_ID) .withTableId(TABLE_ID) .build();
Dzięki temu Twój potok może przekazywać obiekty HBase Mutation
, które mogą obejmować Put i 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));
Zadanie LoadData Dataflow
Na następnej stronie pokażemy, jak uruchomić zadanie LoadData, ale tutaj przywołam ważne części potoku.
Aby wygenerować dane, utworzysz potok, który korzysta z klasy GenerateSequence (podobnie do pętli for) do zapisywania szeregu wierszy z kilkoma megabajtami losowych danych. Klucz wiersza będzie numerem seryjnym dopełnionym i odwróconym, więc 250
zmienia się w 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. Generowanie danych do Bigtable i monitorowanie napływu
Te polecenia uruchomią zadanie Dataflow, które wygeneruje 40 GB danych w tabeli, czyli więcej, niż wystarczy, aby aktywować usługę Key Visualizer:
Włączanie Cloud Dataflow API
gcloud services enable dataflow.googleapis.com
Pobierz kod z githuba i przejdź do katalogu
git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git cd java-docs-samples/bigtable/beam/keyviz-art
Wygeneruj dane (skrypt zajmuje około 15 minut)
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"
Monitorowanie importu
Zadanie możesz monitorować w interfejsie użytkownika Cloud Dataflow. Możesz też wyświetlić obciążenie instancji Cloud Bigtable za pomocą jej interfejsu monitorowania.
W interfejsie Dataflow możesz zobaczyć wykres zadań i różne wskaźniki zadań, w tym przetworzone elementy, bieżące procesory wirtualne i przepustowość.
Bigtable udostępnia standardowe narzędzia do monitorowania operacji odczytu i zapisu, wykorzystanego miejsca na dane, odsetka błędów i innych funkcji na poziomie instancji, klastra i tabeli. Oprócz tego Bigtable ma też Key Visualizer, który dzieli wykorzystanie według kluczy wierszy, których użyjemy po wygenerowaniu co najmniej 30 GB danych.
5. Naucz się: odczytywać dane z Bigtable za pomocą Dataflow
Podstawy czytania
Podczas odczytu z Cloud Bigtable musisz podać obiekt konfiguracji CloudBigtableTableScanConfiguration
. To działanie jest podobne do CloudBigtableTableConfiguration
, z tym że możesz określić wiersze do skanowania i odczytywania.
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();
Następnie użyj go do uruchomienia potoku:
p.apply(Read.from(CloudBigtableIO.read(config))) .apply(...
Jeśli jednak chcesz wykonać odczyt w ramach potoku, możesz przekazać CloudBigtableTableConfiguration
do doFn
rozszerzenia AbstractCloudBigtableTableDoFn
.
p.apply(GenerateSequence.from(0).to(10)) .apply(ParDo.of(new ReadFromTableFn(bigtableTableConfig, options)));
Następnie wywołaj super()
ze swoją konfiguracją i getConnection()
, aby uzyskać połączenie rozproszone.
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); } }
Zadanie ReadData Dataflow
W ramach tych ćwiczeń w Codelabs musisz odczytywać dane z tabeli co sekundę, dzięki czemu możesz rozpocząć potok od wygenerowanej sekwencji, która aktywuje wiele zakresów odczytu na podstawie czasu wprowadzenia pliku CSV.
Aby określić, które zakresy wierszy należy przeskanować w danym czasie, należy nieco matematyki, ale jeśli chcesz dowiedzieć się więcej, możesz kliknąć nazwę pliku, aby wyświetlić kod źródłowy.
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. Tworzenie własnego dzieła
Wiesz już, jak wczytać dane do Bigtable i odczytywać je za pomocą Dataflow. Teraz możesz uruchomić ostatnie polecenie, które wygeneruje obraz Mona Lisy w ciągu 8 godzin.
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"
Dostępny jest zasobnik z istniejącymi obrazami, którego możesz użyć. Możesz też utworzyć plik wejściowy na podstawie dowolnego ze swoich obrazów za pomocą tego narzędzia, a potem przesłać go do publicznego zasobnika GCS.
Nazwy plików pochodzą z przykładu gs://keyviz-art/[painting]_[hours]h.txt
: gs://keyviz-art/american_gothic_4h.txt
opcje malowania:
- american_gothic
- mona_lisa
- pearl_earring
- persistence_of_memory
- starry_night
- sunday_afternoon
- the_scream
opcje godzin: 1, 4, 8, 12, 24, 48, 72, 96, 120, 144
Ustaw zasobnik lub plik GCS jako publiczny, nadając usłudze allUsers
rolę Storage Object Viewer
.
Po wybraniu obrazu zmień parametr --file-path
za pomocą tego polecenia:
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. Sprawdź to później
Aktywowanie całego obrazu może potrwać kilka godzin, ale po 30 minutach w usłudze Key Visualizer powinna zacząć pojawiać się aktywność. Jest kilka parametrów, których możesz użyć: zoom, jasność i wskaźnik. Możesz powiększać obraz za pomocą kółka myszy lub przeciągając prostokąt na siatce kluczowej wizualizacji.
Jasność zmienia skalowanie obrazu, co jest pomocne, jeśli chcesz dokładnie przyjrzeć się bardzo gorącemu obszarowi.
Możesz też określić, które dane mają być wyświetlane. Obejmuje to między innymi operacje operacyjne, klienta odczytu bajtów i klienta zapisu bajtów. „Klient odczytujący bajty” pozwala uzyskać płynne obrazy, generuje obrazy z większą liczbą linii, które na niektórych obrazach mogą wyglądać naprawdę atrakcyjnie.
8. Zakończ
Czyszczenie danych w celu uniknięcia opłat
Aby uniknąć obciążenia konta Google Cloud Platform opłatami za zasoby zużyte w tym ćwiczeniu z programowania, usuń instancję.
gcloud bigtable instances delete $INSTANCE_ID
Omówione zagadnienia
- Zapisywanie w Bigtable za pomocą Dataflow
- Odczyt z Bigtable za pomocą Dataflow (na początku potoku, w jego trakcie)
- Korzystanie z narzędzi do monitorowania Dataflow
- Korzystanie z narzędzi do monitorowania Bigtable, w tym narzędzia Key Visualizer
Dalsze kroki
- Dowiedz się więcej o tym, jak powstała grafika Key Visualizer.
- Więcej informacji o Cloud Bigtable znajdziesz w dokumentacji.
- Wypróbuj inne funkcje Google Cloud Platform. Zapoznaj się z naszymi samouczkami.