Cloud Functions에서 Cloud Bigtable 사용

목표

Cloud Bigtable에 액세스하는 HTTP Cloud Functions를 작성, 배포, 트리거합니다.

비용

이 주제에서는 비용이 청구될 수 있는 Google Cloud 구성요소인 Cloud Bigtable과 Cloud Functions를 사용합니다.

시작하기 전에

  1. 이 주제에서는 test-instance라는 Cloud Bigtable 인스턴스와 test-table이라는 테이블이 있다고 가정합니다. 테스트 테이블 만들기의 단계에 따라 이러한 리소스를 만들 수 있습니다. 불필요한 비용이 발생하지 않도록 작업이 완료된 후에는 리소스를 삭제하세요.

  2. Cloud Functions API를 사용 설정합니다.

    API 사용 설정

  3. Cloud SDK를 설치하고 초기화합니다.

    Cloud SDK가 이미 설치되어 있으면 다음 명령어를 실행하여 업데이트하세요.

    gcloud components update
    
  4. 개발 환경을 준비합니다.

애플리케이션 준비

  1. 샘플 앱 저장소를 로컬 머신에 복제합니다.

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    또는 zip 파일로 샘플을 다운로드하고 압축을 풀 수 있습니다.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    또는 zip 파일로 샘플을 다운로드하고 압축을 풀 수 있습니다.

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git

    또는 zip 파일로 샘플을 다운로드하고 압축을 풀 수 있습니다.

  2. Cloud Bigtable에 액세스하기 위한 Cloud Functions 샘플 코드가 있는 디렉터리로 변경합니다.

    Node.js

    cd nodejs-docs-samples/functions/bigtable/

    Python

    cd python-docs-samples/functions/bigtable/

    Go

    cd golang-samples/functions/bigtable/
  3. 다음 샘플 코드를 살펴봅니다.

    Node.js

    // Imports the Google Cloud client library
    const {Bigtable} = require('@google-cloud/bigtable');
    
    // Instantiates a client
    const bigtable = new Bigtable();
    
    exports.readRows = async (req, res) => {
      // Gets a reference to a Cloud Bigtable instance and database
      const instance = bigtable.instance(req.body.instanceId);
      const table = instance.table(req.body.tableId);
    
      // Execute the query
      try {
        const prefix = 'phone#';
        const rows = [];
        await table
          .createReadStream({
            prefix,
          })
          .on('error', err => {
            res.send(`Error querying Bigtable: ${err}`);
            res.status(500).end();
          })
          .on('data', row => {
            rows.push(
              `rowkey: ${row.id}, ` +
                `os_build: ${row.data['stats_summary']['os_build'][0].value}\n`
            );
          })
          .on('end', () => {
            rows.forEach(r => res.write(r));
            res.status(200).end();
          });
      } catch (err) {
        res.send(`Error querying Bigtable: ${err}`);
        res.status(500).end();
      }
    };
    

    Python

    from google.cloud import bigtable
    from google.cloud.bigtable.row_set import RowSet
    
    client = bigtable.Client()
    
    def bigtable_read_data(request):
        instance = client.instance(request.headers.get("instance_id"))
        table = instance.table(request.headers.get("table_id"))
    
        prefix = 'phone#'
        end_key = prefix[:-1] + chr(ord(prefix[-1]) + 1)
    
        outputs = []
        row_set = RowSet()
        row_set.add_row_range_from_keys(prefix.encode("utf-8"),
                                        end_key.encode("utf-8"))
    
        rows = table.read_rows(row_set=row_set)
        for row in rows:
            output = 'Rowkey: {}, os_build: {}'.format(
                row.row_key.decode('utf-8'),
                row.cells["stats_summary"]["os_build".encode('utf-8')][0]
                .value.decode('utf-8'))
            outputs.append(output)
    
        return '\n'.join(outputs)
    

    Go

    
    // Package bigtable contains an example of using Bigtable from a Cloud Function.
    package bigtable
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"net/http"
    	"sync"
    
    	"cloud.google.com/go/bigtable"
    )
    
    // client is a global Bigtable client, to avoid initializing a new client for
    // every request.
    var client *bigtable.Client
    var clientOnce sync.Once
    
    // BigtableRead is an example of reading Bigtable from a Cloud Function.
    func BigtableRead(w http.ResponseWriter, r *http.Request) {
    	clientOnce.Do(func() {
    		// Declare a separate err variable to avoid shadowing client.
    		var err error
    		client, err = bigtable.NewClient(context.Background(), r.Header.Get("projectID"), r.Header.Get("instanceId"))
    		if err != nil {
    			http.Error(w, "Error initializing client", http.StatusInternalServerError)
    			log.Printf("bigtable.NewClient: %v", err)
    			return
    		}
    	})
    
    	tbl := client.Open(r.Header.Get("tableID"))
    	err := tbl.ReadRows(r.Context(), bigtable.PrefixRange("phone#"),
    		func(row bigtable.Row) bool {
    			osBuild := ""
    			for _, col := range row["stats_summary"] {
    				if col.Column == "stats_summary:os_build" {
    					osBuild = string(col.Value)
    				}
    			}
    
    			fmt.Fprintf(w, "Rowkey: %s, os_build:  %s\n", row.Key(), osBuild)
    			return true
    		})
    
    	if err != nil {
    		http.Error(w, "Error reading rows", http.StatusInternalServerError)
    		log.Printf("tbl.ReadRows(): %v", err)
    	}
    }
    

    함수는 테이블에 읽기 요청을 전송하여 row key 프리픽스가 phone인 행의 모든 stats_summary 데이터를 가져옵니다. 이 함수는 함수의 엔드포인트에 HTTP 요청을 보낼 때 실행됩니다.

함수 배포

HTTP 트리거를 사용하여 함수를 배포하려면 bigtable 디렉터리에서 다음 명령어를 실행합니다.

Node.js

gcloud functions deploy get \
--runtime nodejs10 --trigger-http
--runtime 플래그에 다음 값을 사용하여 원하는 Node.js 버전을 지정할 수 있습니다.
  • nodejs10
  • nodejs12
  • nodejs14(공개 미리보기)

Python

gcloud functions deploy bigtable_read_data \
--runtime python38 --trigger-http
--runtime 플래그에 다음 값을 사용하여 선호하는 Python 버전을 지정할 수 있습니다.
  • python37
  • python38
  • python39(공개 미리보기)

Go

gcloud functions deploy HelloBigtable \
--runtime go113 --trigger-http
--runtime 플래그에 다음 값을 사용하여 원하는 Go 버전을 지정할 수 있습니다.
  • go111(지원 중단됨)
  • go113

함수 배포에 최대 2분이 소요될 수 있습니다.

함수 배포가 완료되면 url 값이 반환됩니다. 이 값은 함수를 트리거할 때 사용됩니다.

Google Cloud Console의 Cloud Functions 페이지에서 배포한 함수를 확인할 수 있습니다. 이 페이지에서 함수를 만들고 수정할 수도 있으며 함수에 관한 세부정보와 진단 정보를 확인할 수 있습니다.

함수 트리거

함수에 HTTP 요청을 보냅니다.

Node.js

curl "https://REGION-PROJECT_ID.cloudfunctions.net/get" --trigger-http

Python

curl "https://REGION-PROJECT_ID.cloudfunctions.net/bigtable_read_data" --trigger-http

Go

curl "https://REGION-PROJECT_ID.cloudfunctions.net/HelloBigtable" --trigger-http

REGIONPROJECT_ID는 함수 배포가 끝난 후 터미널에 표시되는 값과 일치합니다. 읽기 요청 결과를 보여주는 출력이 표시됩니다.

브라우저에서 함수의 URL을 방문하여 읽기 요청 결과를 확인할 수도 있습니다.

삭제

이 주제에서 사용한 Cloud Bigtable 및 Cloud Functions 리소스의 비용이 Google Cloud 계정에 추가로 청구되지 않도록 하려면 다음 안내를 따르세요.

  1. 인스턴스를 삭제합니다.

    gcloud bigtable instances delete test-instance
    
  2. 배포한 함수를 삭제합니다.

    Node.js

    gcloud functions delete get --trigger-http

    Python

    gcloud functions delete bigtable_read_data --trigger-http

    Go

    gcloud functions delete HelloBigtable --trigger-http

다음 단계