Go Hello world

이 예시에서는 Go로 작성된 매우 간단한 'hello world' 애플리케이션으로 다음 작업을 수행하는 방법을 알 수 있습니다.

  • 인증 설정
  • Bigtable 인스턴스에 연결
  • 새 테이블 만들기
  • 테이블에 데이터 쓰기
  • 데이터 다시 읽기
  • 테이블 삭제

인증 설정

로컬 개발 환경에서 이 페이지의 Go 샘플을 사용하려면 gcloud CLI를 설치 및 초기화한 다음 사용자 인증 정보로 애플리케이션 기본 사용자 인증 정보를 설정하세요.

  1. Google Cloud CLI를 설치합니다.
  2. gcloud CLI를 초기화하려면 다음 명령어를 실행합니다.

    gcloud init
  3. Google 계정의 로컬 인증 사용자 인증 정보를 만듭니다.

    gcloud auth application-default login

자세한 내용은 로컬 개발 환경의 인증 설정를 참조하세요.

샘플 실행

이 예시에서는 Go용 Google Cloud 클라이언트 라이브러리Cloud Bigtable 패키지를 사용하여 Bigtable과 통신합니다.

이 샘플 프로그램을 실행하려면 GitHub에서 샘플 안내를 따르세요.

Cloud 클라이언트 라이브러리를 Bigtable과 함께 사용

샘플 애플리케이션을 Bigtable에 연결하여 몇 가지 간단한 작업을 보여줍니다.

클라이언트 라이브러리 가져오기

이 샘플은 다음 가져오기를 사용합니다.

import (
	"context"
	"flag"
	"fmt"
	"log"

	"cloud.google.com/go/bigtable"
)

Bigtable에 연결하여 테이블 관리

테이블을 관리하려면 bigtable.NewAdminClient()를 사용하여 Bigtable에 연결합니다.

adminClient, err := bigtable.NewAdminClient(ctx, *project, *instance)
if err != nil {
	log.Fatalf("Could not create admin client: %v", err)
}

테이블 만들기

AdminClient.CreateTable()로 테이블을 만든 다음 AdminClient.TableInfo()로 테이블 정보를 가져옵니다. AdminClient.CreateColumnFamily()를 사용하여 column family를 만듭니다.

tables, err := adminClient.Tables(ctx)
if err != nil {
	log.Fatalf("Could not fetch table list: %v", err)
}

if !sliceContains(tables, tableName) {
	log.Printf("Creating table %s", tableName)
	if err := adminClient.CreateTable(ctx, tableName); err != nil {
		log.Fatalf("Could not create table %s: %v", tableName, err)
	}
}

tblInfo, err := adminClient.TableInfo(ctx, tableName)
if err != nil {
	log.Fatalf("Could not read info for table %s: %v", tableName, err)
}

if !sliceContains(tblInfo.Families, columnFamilyName) {
	if err := adminClient.CreateColumnFamily(ctx, tableName, columnFamilyName); err != nil {
		log.Fatalf("Could not create column family %s: %v", columnFamilyName, err)
	}
}

Bigtable에 연결하여 데이터 관리

데이터를 관리하려면 bigtable.NewClient()를 사용하여 Bigtable에 연결합니다.

client, err := bigtable.NewClient(ctx, *project, *instance)
if err != nil {
	log.Fatalf("Could not create data operations client: %v", err)
}

테이블에 행 쓰기

쓰려는 테이블을 엽니다. bigtable.NewMutation()을 사용하여 단일 행에 변형을 만든 다음 Mutation.Set()를 사용하여 행에 값을 설정합니다. 각 행에 고유한 row key를 생성합니다. 이 단계를 반복하여 여러 개의 변형을 만듭니다. 마지막으로 Table.ApplyBulk()를 사용하여 모든 변형을 테이블에 적용합니다.

tbl := client.Open(tableName)
muts := make([]*bigtable.Mutation, len(greetings))
rowKeys := make([]string, len(greetings))

log.Printf("Writing greeting rows to table")
for i, greeting := range greetings {
	muts[i] = bigtable.NewMutation()
	muts[i].Set(columnFamilyName, columnName, bigtable.Now(), []byte(greeting))

	// Each row has a unique row key.
	//
	// Note: This example uses sequential numeric IDs for simplicity, but
	// this can result in poor performance in a production application.
	// Since rows are stored in sorted order by key, sequential keys can
	// result in poor distribution of operations across nodes.
	//
	// For more information about how to design a Bigtable schema for the
	// best performance, see the documentation:
	//
	//     https://cloud.google.com/bigtable/docs/schema-design
	rowKeys[i] = fmt.Sprintf("%s%d", columnName, i)
}

rowErrs, err := tbl.ApplyBulk(ctx, rowKeys, muts)
if err != nil {
	log.Fatalf("Could not apply bulk row mutation: %v", err)
}
if rowErrs != nil {
	for _, rowErr := range rowErrs {
		log.Printf("Error writing row: %v", rowErr)
	}
	log.Fatalf("Could not write some rows")
}

키를 통해 행 읽기

Table.ReadRow()로 키를 사용하여 행을 직접 가져옵니다.

log.Printf("Getting a single greeting by row key:")
row, err := tbl.ReadRow(ctx, rowKeys[0], bigtable.RowFilter(bigtable.ColumnFilter(columnName)))
if err != nil {
	log.Fatalf("Could not read row with key %s: %v", rowKeys[0], err)
}
log.Printf("\t%s = %s\n", rowKeys[0], string(row[columnFamilyName][0].Value))

모든 테이블 행 검색

Table.ReadRows()를 사용하여 테이블의 모든 행을 검색합니다. 사용을 마쳤으면 데이터 클라이언트를 닫습니다.

log.Printf("Reading all greeting rows:")
err = tbl.ReadRows(ctx, bigtable.PrefixRange(columnName), func(row bigtable.Row) bool {
	item := row[columnFamilyName][0]
	log.Printf("\t%s = %s\n", item.Row, string(item.Value))
	return true
}, bigtable.RowFilter(bigtable.ColumnFilter(columnName)))

if err = client.Close(); err != nil {
	log.Fatalf("Could not close data operations client: %v", err)
}

테이블 삭제

AdminClient.DeleteTable()을 사용하여 테이블을 삭제합니다. 사용을 마쳤으면 관리 클라이언트를 닫습니다.

log.Printf("Deleting the table")
if err = adminClient.DeleteTable(ctx, tableName); err != nil {
	log.Fatalf("Could not delete table %s: %v", tableName, err)
}

if err = adminClient.Close(); err != nil {
	log.Fatalf("Could not close admin client: %v", err)
}

요약 정리

다음은 주석이 없는 전체 예시입니다.


package main

import (
	"context"
	"flag"
	"fmt"
	"log"

	"cloud.google.com/go/bigtable"
)

const (
	tableName        = "Hello-Bigtable"
	columnFamilyName = "cf1"
	columnName       = "greeting"
)

var greetings = []string{"Hello World!", "Hello Cloud Bigtable!", "Hello golang!"}

func sliceContains(list []string, target string) bool {
	for _, s := range list {
		if s == target {
			return true
		}
	}
	return false
}

func main() {
	project := flag.String("project", "", "The Google Cloud Platform project ID. Required.")
	instance := flag.String("instance", "", "The Google Cloud Bigtable instance ID. Required.")
	flag.Parse()

	for _, f := range []string{"project", "instance"} {
		if flag.Lookup(f).Value.String() == "" {
			log.Fatalf("The %s flag is required.", f)
		}
	}

	ctx := context.Background()

	adminClient, err := bigtable.NewAdminClient(ctx, *project, *instance)
	if err != nil {
		log.Fatalf("Could not create admin client: %v", err)
	}

	tables, err := adminClient.Tables(ctx)
	if err != nil {
		log.Fatalf("Could not fetch table list: %v", err)
	}

	if !sliceContains(tables, tableName) {
		log.Printf("Creating table %s", tableName)
		if err := adminClient.CreateTable(ctx, tableName); err != nil {
			log.Fatalf("Could not create table %s: %v", tableName, err)
		}
	}

	tblInfo, err := adminClient.TableInfo(ctx, tableName)
	if err != nil {
		log.Fatalf("Could not read info for table %s: %v", tableName, err)
	}

	if !sliceContains(tblInfo.Families, columnFamilyName) {
		if err := adminClient.CreateColumnFamily(ctx, tableName, columnFamilyName); err != nil {
			log.Fatalf("Could not create column family %s: %v", columnFamilyName, err)
		}
	}

	client, err := bigtable.NewClient(ctx, *project, *instance)
	if err != nil {
		log.Fatalf("Could not create data operations client: %v", err)
	}

	tbl := client.Open(tableName)
	muts := make([]*bigtable.Mutation, len(greetings))
	rowKeys := make([]string, len(greetings))

	log.Printf("Writing greeting rows to table")
	for i, greeting := range greetings {
		muts[i] = bigtable.NewMutation()
		muts[i].Set(columnFamilyName, columnName, bigtable.Now(), []byte(greeting))

		rowKeys[i] = fmt.Sprintf("%s%d", columnName, i)
	}

	rowErrs, err := tbl.ApplyBulk(ctx, rowKeys, muts)
	if err != nil {
		log.Fatalf("Could not apply bulk row mutation: %v", err)
	}
	if rowErrs != nil {
		for _, rowErr := range rowErrs {
			log.Printf("Error writing row: %v", rowErr)
		}
		log.Fatalf("Could not write some rows")
	}

	log.Printf("Getting a single greeting by row key:")
	row, err := tbl.ReadRow(ctx, rowKeys[0], bigtable.RowFilter(bigtable.ColumnFilter(columnName)))
	if err != nil {
		log.Fatalf("Could not read row with key %s: %v", rowKeys[0], err)
	}
	log.Printf("\t%s = %s\n", rowKeys[0], string(row[columnFamilyName][0].Value))

	log.Printf("Reading all greeting rows:")
	err = tbl.ReadRows(ctx, bigtable.PrefixRange(columnName), func(row bigtable.Row) bool {
		item := row[columnFamilyName][0]
		log.Printf("\t%s = %s\n", item.Row, string(item.Value))
		return true
	}, bigtable.RowFilter(bigtable.ColumnFilter(columnName)))

	if err = client.Close(); err != nil {
		log.Fatalf("Could not close data operations client: %v", err)
	}

	log.Printf("Deleting the table")
	if err = adminClient.DeleteTable(ctx, tableName); err != nil {
		log.Fatalf("Could not delete table %s: %v", tableName, err)
	}

	if err = adminClient.Close(); err != nil {
		log.Fatalf("Could not close admin client: %v", err)
	}
}