1. 소개
이 Codelab은 Apache Cassandra에서 Google Cloud Bigtable로 쿼리를 마이그레이션하는 모든 사용자를 위한 가이드입니다.
이 Codelab에서는
- Cloud Bigtable 에뮬레이터 사용
- 시계열 사용 사례 살펴보기
- 테이블 및 column family 만들기
- CQL 삽입, 업데이트, 선택, 삭제에 해당하는 Cloud Bigtable Java의 기능에 대해 알아보기
귀하의 Google Cloud Platform 사용 경험을 평가해 주세요.
본 가이드를 어떻게 사용하실 계획인가요?
<ph type="x-smartling-placeholder">2. 설정
핵심 개념을 빠르게 이해할 수 있도록 몇 개의 행만 있는 샘플 데이터 세트를 살펴볼 것입니다.
Cassandra
각 단계에 상응하는 Cassandra 쿼리가 있으므로 원하는 경우 로컬 클러스터를 따르거나 클릭하여 배포 Cassandra 클러스터를 빠르게 설정하고 SSH를 통해 연결할 수 있습니다.
계속 진행하는 경우 키스페이스를 만들어 사용하세요. 여기서는 복제 전략이 중요하지 않습니다.
cqlsh> create keyspace mykeyspace with replication = {'class':'SimpleStrategy','replication_factor' : 2}; cqlsh> use mykeyspace;
Cloud Bigtable
테이블에 Cloud Bigtable 인스턴스가 있어야 합니다. 에뮬레이터를 사용하여 로컬 인스턴스를 무료로 설정할 수 있습니다. Cloud Bigtable에서는 키스페이스를 만들 필요가 없으며 인스턴스 구성에서 복제를 처리합니다.
다음 명령어를 사용하여 에뮬레이터를 시작합니다.
gcloud beta emulators bigtable start
그런 다음 다른 셸 창 또는 탭에서 다음 명령어로 에뮬레이터 환경 변수를 설정합니다.
$(gcloud beta emulators bigtable env-init) #Sets BIGTAB`LE_EMULATOR_HOST
그런 다음 코드 예시를 실행하는 데 사용할 Java 프로젝트를 만들고 Maven, Gradle 또는 SBT로 Cloud Bigtable 클라이언트를 가져옵니다. 그런 다음 새 Java 파일에서 데이터 클라이언트에 대한 연결을 만듭니다.
BigtableDataSettings settings =
BigtableDataSettings.newBuilder().setProjectId(projectId).setInstanceId(instanceId).build();
try {
dataClient = BigtableDataClient.create(settings);
} catch (Exception e) {
System.out.println("Error during data client connection: \n" + e.toString());
}
3. 테이블 만들기
Cassandra 테이블과 Cloud Bigtable 테이블 모두에서 각 행에는 연결된 키가 있습니다. Cassandra 키에는 분리되거나 중복될 수 있는 파티션 키와 클러스터링 열이 있습니다. Cloud Bigtable 키 전체가 분할 (파티션) 및 정렬에 사용됩니다. 이 두 시스템은 기본/행 키 생성에 있어 매우 유사합니다. 두 시스템 모두 기본적으로 사전순으로 정렬된 목록으로, 키가 노드 간 행 분배의 기본 형태를 취합니다. 대부분의 경우 Cloud Bigtable에 동일한 키를 재사용할 수 있습니다.
이 Codelab에서는 Cloud Bigtable을 사용하여 휴대전화 및 모바일 태블릿에 대한 시계열 데이터를 저장합니다 (Bigtable 태블릿과 혼동하지 말 것). 테이블을 만드는 방법은 다음과 같습니다.
Cassandra
cqlsh:mykeyspace> create table mobileTimeSeries ( deviceid text, devicetype text, date date, connected_cell map<timestamp,Boolean>, os_build text, os_name text, PRIMARY KEY((devicetype, deviceid), date));
Cloud Bigtable
자바 클라이언트를 사용하여 테이블 및 column family를 만들 수 있지만 cbt 도구와 함께 다음 명령어를 사용하는 것이 가장 쉽습니다.
cbt createtable mobile-time-series families=stats_summary
Cloud Bigtable은 NoSQL 데이터베이스이므로 테이블 생성 시 스키마를 정의할 필요는 없지만 실행할 쿼리에 대해 생각해 보고 이를 위해 row key를 최적화해야 합니다.
키 마이그레이션을 위한 가장 일반적인 전략은 모든 파티션 키와 클러스터링 열을 가져와 조인하여 Cloud Bigtable row key를 나타내는 문자열을 만드는 것입니다. 일반적으로 문자열 기반 키는 Key Visualizer를 통한 키 배포를 디버깅하는 데 도움이 되므로 사용하는 것이 좋습니다. 해시 '#'과 같은 구분자를 사용할 수 있습니다. 가독성을 높일 수 있습니다.
이 예에서는 '[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]'의 rowkey를 사용합니다.
4. 삽입
삽입은 Cassandra와 Cloud Bigtable 간에 상당히 유사합니다. 여기서는 '[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]'의 rowkey를 사용하여 하나의 행을 삽입한 다음 여러 행을 삽입합니다.
Cassandra
싱글
cqlsh:mykeyspace> insert into mobileTimeSeries (deviceid, devicetype, date, connected_cell, os_build) values ('4c410523', 'phone',toDate(now()), {toTimeStamp(now()): true}, 'PQ2A.190405.003');
Batch
cqlsh:mykeyspace> BEGIN BATCH insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-01', 'chromeos', '12155.0.0-rc1'); insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-02','chromeos', '12145.0.0-rc6'); APPLY BATCH;
Cloud Bigtable
싱글
사용할 row key와 데이터로 변형을 만든 다음 데이터 클라이언트를 사용해 변형을 적용합니다. 휴대전화 연결 및 운영체제에 대한 정보가 포함된 데이터 행을 추가합니다.
try {
System.currentTimeMillis();
long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00
String rowKey = "phone#4c410523#20190501";
ByteString one = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 1});
RowMutation rowMutation =
RowMutation.create(tableId, rowKey)
.setCell(
COLUMN_FAMILY_NAME,
ByteString.copyFrom("connected_cell".getBytes()),
timestamp,
one)
.setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "PQ2A.190405.003");
dataClient.mutateRow(rowMutation);
} catch (Exception e) {
System.out.println("Error during Write: \n" + e.toString());
}
Batch
batchMutation 객체에 여러 변형을 정의한 후 데이터 클라이언트를 사용하여 API 호출 한 번으로 모든 변형을 적용합니다. 모바일 태블릿의 운영체제 이름 및 버전에 관한 며칠 동안의 데이터를 추가합니다.
try {
long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00
BulkMutation bulkMutation =
BulkMutation.create(tableId)
.add(
"tablet#a0b81f74#20190501",
Mutation.create()
.setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
.setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc1"))
.add(
"tablet#a0b81f74#20190502",
Mutation.create()
.setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
.setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc6"));
dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
System.out.println("Error during WriteBatch: \n" + e.toString());
}
5. 업데이트
여기에서는 아직 기록되지 않은 셀을 업데이트하고 이전 버전을 유지하면서 셀에 새 값을 작성합니다.
Cassandra
셀 추가
cqlsh:mykeyspace> UPDATE mobileTimeSeries SET os_name = 'android' WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';
셀 업데이트
cqlsh:mykeyspace> UPDATE mobileTimeSeries SET connected_cell = connected_cell + {toTimeStamp(now()): false} WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';
Cloud Bigtable
Cloud Bigtable에서는 업데이트를 쓰기와 동일하게 취급할 수 있습니다.
셀 추가
이는 셀을 쓰는 것과 같습니다. 이전에 쓰지 않은 열을 제공하기만 하면 됩니다. 여기서 휴대전화 행에 운영체제 이름을 추가하게 됩니다.
try {
long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30
String rowKey = "phone#4c410523#20190501";
RowMutation rowMutation =
RowMutation.create(tableId, rowKey)
.setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "android");
dataClient.mutateRow(rowMutation);
} catch (Exception e) {
System.out.println("Error during update: \n" + e.toString());
}
셀 업데이트 중
여기에서 휴대전화의 모바일 데이터 연결 상태에 관한 새 데이터를 추가합니다. 셀 버전을 사용하면 시계열 데이터의 일부를 쉽게 저장할 수 있습니다. 쓰기에 대한 타임스탬프를 제공하기만 하면 셀에 새 버전을 추가합니다. 데이터를 정리하려면 가비지 컬렉션을 사용하여 특정 횟수 또는 일정 시간이 지난 후 버전을 삭제하면 됩니다.
try {
long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30
String rowKey = "phone#4c410523#20190501";
ByteString zero = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 0});
RowMutation rowMutation =
RowMutation.create(tableId, rowKey)
.setCell(
COLUMN_FAMILY_NAME,
ByteString.copyFrom("connected_cell".getBytes()),
timestamp,
zero);
dataClient.mutateRow(rowMutation);
} catch (Exception e) {
System.out.println("Error during update2: \n" + e.toString());
}
6. 선택
이제 테이블에 작성한 데이터를 검색합니다. CQL select 문을 마이그레이션할 때는 열, WHERE 절을 통한 필터링, 그룹화 기준과 같은 제한 및 집계 함수와 같은 SELECT 문의 여러 측면을 고려해야 합니다. 여기서는 기본적인 아이디어를 얻기 위해 두 개의 간단한 SELECT 문만 살펴보겠지만 선택에 관한 자세한 내용은 문서를 참고하세요. Cloud Bigtable에는 가져오기와 스캔이라는 두 가지 유형의 검색 작업이 있습니다. Get은 행 1개를 가져오는 반면 스캔은 행 범위를 검색합니다.
Cassandra
싱글
cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-04';
여러 개
cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='tablet' AND deviceid = 'a0b81f74' AND date >= '2019-09-04';
Cloud Bigtable
싱글
행 조회를 사용하여 지정된 날짜에 특정 전화에 대한 데이터를 가져옵니다. 이 데이터는 모두 한 행에 포함됩니다. 이렇게 하면 타임스탬프가 지정된 각 버전의 값이 반환되므로 서로 다른 타임스탬프에 연결된_셀이 두 개 표시됩니다.
try {
String rowKey = "phone#4c410523#20190501";
Row row = dataClient.readRow(tableId, rowKey);
for (RowCell cell : row.getCells()) {
System.out.printf(
"Family: %s Qualifier: %s Value: %s Timestamp: %s%n",
cell.getFamily(),
cell.getQualifier().toStringUtf8(),
cell.getValue().toStringUtf8(),
cell.getTimestamp());
}
} catch (Exception e) {
System.out.println("Error during lookup: \n" + e.toString());
}
여러 개
범위 스캔을 사용하여 여러 행에 분산된 지정된 모바일 태블릿에서 한 달 동안의 데이터를 볼 수 있습니다. 이 값과 함께 필터를 사용하면 특정 버전의 데이터만 가져오거나 값으로 필터링할 수 있습니다.
try {
Query query = Query.create(tableId).range("tablet#a0b81f74#201905", "tablet#a0b81f74#201906");
ServerStream<Row> rowStream = dataClient.readRows(query);
for (Row row : rowStream) {
System.out.println("Row Key: " + row.getKey().toStringUtf8());
for (RowCell cell : row.getCells()) {
System.out.printf(
"Family: %s Qualifier: %s Value: %s Timestamp: %s%n",
cell.getFamily(),
cell.getQualifier().toStringUtf8(),
cell.getValue().toStringUtf8(),
cell.getTimestamp());
}
}
} catch (Exception e) {
System.out.println("Error during scan: \n" + e.toString());
}
7. 삭제
여기에서 테이블에 입력한 데이터를 삭제합니다. 먼저 개별 행을 삭제한 다음 여러 행을 삭제합니다.
Cassandra의 CQL은 모든 기본 열이 지정된 경우 단일 행 삭제 및 범위 삭제를 허용합니다. Bigtable에서 범위를 스캔한 후 행 수준 삭제를 수행하면 됩니다. 결과는 동일하지만 각 삭제가 자체 작업이므로 작업이 더 많이 포함됩니다.
Cassandra
싱글
cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='phone' and deviceid = '4c410523';
여러 개
cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='tablet' and deviceid = 'a0b81f74';
Cloud Bigtable
싱글
여기에서 특정 휴대전화 및 날짜의 데이터를 삭제합니다. row key를 사용하여 한 번에 한 행씩 삭제합니다.
try {
String rowKey = "phone#4c410523#20190501";
RowMutation mutation = RowMutation.create(tableId, rowKey).deleteRow();
dataClient.mutateRow(mutation);
} catch (Exception e) {
System.out.println("Error during Delete: \n" + e.toString());
}
여러 개
여기에서 특정 모바일 태블릿의 모든 데이터를 삭제합니다. 여러 행을 삭제하는 CQL 쿼리를 마이그레이션하려면 스캔을 수행한 후 결과 row key 집합을 사용하여 각 행을 삭제해야 합니다.
try {
Query query = Query.create(tableId).prefix("tablet#a0b81f7");
ServerStream<Row> rowStream = dataClient.readRows(query);
BulkMutation bulkMutation = BulkMutation.create(tableId);
for (Row row : rowStream) {
bulkMutation.add(row.getKey(), Mutation.create().deleteRow());
}
dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
System.out.println("Error during DeleteMultiple: \n" + e.toString());
}
8. 완료
정리
Cassandra
이 작업을 수행하기 위해 Cassandra 클러스터를 만든 경우 평소와 같이 삭제해도 됩니다.
Cloud Bigtable
기존 Cloud Bigtable 인스턴스에 테이블을 만든 경우 cbt 명령어를 사용하여 테이블을 삭제할 수 있습니다.
cbt deletetable mobile-time-series
에뮬레이터를 사용한 경우, 에뮬레이터를 시작한 터미널에 Ctrl + C를 입력하여 에뮬레이터를 중지하여 모든 작업을 지울 수 있습니다.
다음 단계
- 이 문서에서 Cloud Bigtable에 대해 자세히 알아보세요.
- 더 심층적인 Cloud Bigtable Codelab 사용해 보기
- 다른 Google Cloud Platform 기능 직접 사용하기. 튜토리얼을 살펴보세요.
- OpenTSDB 통합으로 시계열 데이터를 모니터링하는 방법 알아보기