Cloud Bigtable למשתמשי Cassandra

1. מבוא

ה-Codelab הזה הוא מדריך לכל מי שמעביר שאילתות מ-Apache Cassandra אל Google Cloud Bigtable.

ב-Codelab הזה

  • שימוש באמולטור Cloud Bigtable
  • התנסות בתרחיש לדוגמה של Timeeries
  • יצירה של טבלה ומשפחת עמודות
  • היכרות עם המקבילות הדומות ב-Cloud Bigtable ל-Java של CQL Insert, עדכון, בחירה ומחיקה

איזה דירוג מגיע לדעתך לחוויית השימוש ב-Google Cloud Platform?

מתחילים בינונית בקיאים

איך תשתמשו במדריך הזה?

לקריאה בלבד לקרוא אותו ולבצע את התרגילים

2. הגדרה

אתם תסתכלו במערך נתונים לדוגמה שכולל כמה שורות בלבד כדי לאפשר לכם להבין במהירות את מושגי הליבה.

קסנדרה

שאילתות שוות ערך של Cassandra יופיעו בכל שלב, לכן אפשר לעקוב אחרי אשכול מקומי אם רוצים. לחלופין, אפשר להגדיר במהירות אשכול של Cassandra כדי לפרוס אותו בלחיצה.

אם אתם עוקבים אחריכם, תוכלו ליצור מרחב מפתחות ולהשתמש בו. אסטרטגיית הרפליקציה לא חשובה כאן.

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 שישמש להרצת דוגמאות הקוד, ומייבאים את לקוח Cloud Bigtable עם Maven, Gradle או SBT. לאחר מכן, בקובץ 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). בהמשך מפורטות ההוראות ליצירת הטבלה.

קסנדרה

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

אתם יכולים ליצור טבלה ומשפחת עמודות באמצעות לקוח Java, אבל הכי קל להשתמש בפקודה הבאה עם הכלי cbt:

cbt createtable mobile-time-series families=stats_summary

Cloud Bigtable הוא מסד נתונים מסוג NoSQL, כך שלא צריך להגדיר סכימה כשיוצרים טבלה, אבל כדאי לחשוב על השאילתות שרוצים להריץ ולבצע אופטימיזציה למפתח השורה שלהן.

האסטרטגיה הנפוצה ביותר להעברת מפתחות היא לקחת את כל מפתחות המחיצות ועמודות האשכולות ולחבר אותם למחרוזת שמייצגת את מפתח השורה של Cloud Bigtable. בדרך כלל אנחנו ממליצים להשתמש במפתחות מבוססי מחרוזות, כי הם עוזרים בניפוי באגים בהפצת המפתחות באמצעות Key Visualizer. אפשר להשתמש במפריד כמו גיבוב '#' בין ערכי העמודות כדי להקל על הקריאה.

בדוגמה הזו נשתמש במפתח שורה של '[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]'.

4. תוספות

התוספות די דומות בין Cassandra לבין Cloud Bigtable. כאן תוסיף שורה אחת ולאחר מכן מספר שורות באמצעות מפתח שורה של "[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]".

קסנדרה

סינגל

cqlsh:mykeyspace> insert into mobileTimeSeries (deviceid, devicetype, date, connected_cell, os_build) values ('4c410523', 'phone',toDate(now()), {toTimeStamp(now()): true}, 'PQ2A.190405.003');

אצווה

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

סינגל

יוצרים מוטציה עם מפתח השורה והנתונים שבהם רוצים להשתמש, ואז מחילים את המוטציה על לקוח הנתונים. מוסיפים שורת נתונים של הטלפון עם מידע על החיבור הסלולרי ועל מערכת ההפעלה שלו.

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());
}

אצווה

מגדירים כמה מוטציות על אובייקט bulkMutation, ואז משתמשים בלקוח הנתונים כדי להחיל את כל המוטציות באמצעות קריאה אחת ל-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. עדכונים

כאן תעדכנו תא שעדיין לא נכתב ואז תכתבו ערך חדש בתא, תוך שמירה על הגרסאות הקודמות.

קסנדרה

הוספת תאים

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, צריך להביא בחשבון כמה היבטים של הצהרות נבחרות, כמו עמודות, סינון לפי התנאים ופונקציות הגבלה וצוברות כמו קיבוץ לפי. כאן תסתכלו בשתי הצהרות פשוטות שנבחרו כדי לקבל את הרעיון הבסיסי, אבל תוכלו לעיין במסמכים כדי לקבל מידע נוסף לגבי הבחירה. יש שני סוגים של פעולות אחזור ב-Cloud Bigtable: קבלה וסריקה. אחזור של שורה אחת בזמן שהסריקה מאחזרת טווח של שורות.

קסנדרה

סינגל

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

יחיד

אפשר לחפש שורה כדי לקבל נתונים לגבי טלפון ספציפי בתאריך שצוין, והכול בשורה אחת. הפעולה הזו תחזיר כל גרסה של הערכים עם חותמת הזמן, כך שיופיעו שתי שורות עבור Connect_cell בחותמות זמן שונות.

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. מוחק

כאן תמחקו את הנתונים שהוספתם לטבלה. קודם מוחקים שורה אחת ואז מוחקים כמה שורות.

בדיקת CQL של Cassandra מאפשרת מחיקות בשורה יחידה וגם הסרות של טווחים כשמציינים את כל העמודות הראשיות. כדי לעשות זאת ב-Bigtable, אפשר לסרוק טווח ולאחר מכן לבצע מחיקות ברמת השורה. לתשומת ליבכם: תקבלו את אותה תוצאה, אבל יהיו לכם פעולות נוספות, כי כל מחיקה תהיה פעולה נפרדת.

קסנדרה

סינגל

cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='phone' and deviceid = '4c410523';

ריבוי

cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='tablet' and deviceid = 'a0b81f74';

Cloud Bigtable

סינגל

כאן יימחקו הנתונים של טלפון ותאריך ספציפיים. אפשר להשתמש במקש השורה כדי למחוק שורה אחת בכל פעם.

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 תוך מחיקת כמה שורות, צריך לבצע סריקה ולמחוק כל שורה על סמך קבוצת מפתחות השורות שנוצרו.

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 כדי לעקוב אחריו, אפשר למחוק אותו כרגיל.

Cloud Bigtable

אם יצרתם את הטבלה במכונה קיימת של Cloud Bigtable, אתם יכולים למחוק אותה באמצעות פקודת cbt

cbt deletetable mobile-time-series

אם השתמשתם באמולטור, אפשר פשוט לעצור את האמולטור כדי לנקות את כל העבודה על ידי הקלדת CTRL-C במסוף שבו התחלתם את הפעולה.

השלבים הבאים