ההבדלים בין HBase ל-Bigtable

אחת הדרכים לגשת ל-Bigtable היא להשתמש בגרסה מותאמת אישית של לקוח Apache HBase ל-Java. באופן כללי, הלקוח המותאם אישית חושף את אותו API כמו התקנה רגילה של HBase. בדף הזה מתוארים ההבדלים בין לקוח Cloud Bigtable HBase ל-Java לבין התקנה רגילה של HBase. רבים מההבדלים האלה קשורים למשימות ניהול ש-Bigtable מטפל בהן באופן אוטומטי.

לקוח Cloud Bigtable HBase ל-Java מיועד ללקוחות שעוברים ל-Bigtable מ-HBase ורוצים להמשיך להשתמש ב-HBase API. בכל המקרים האחרים, מפתחי Java צריכים להשתמש בלקוח Cloud Bigtable ל-Java, שקורא ל-Bigtable APIs.

קבוצות עמודות

כשיוצרים קבוצת עמודות, אי אפשר להגדיר את גודל הבלוק או את שיטת הדחיסה, לא באמצעות מעטפת HBase ולא באמצעות HBase API. ‫Bigtable מנהל בשבילכם את גודל הבלוקים והדחיסה.

בנוסף, אם משתמשים במעטפת HBase כדי לקבל מידע על טבלה, המעטפת תמיד תדווח שכל קבוצת עמודות לא משתמשת בדחיסה. בפועל, Bigtable משתמש בשיטות דחיסה קנייניות לכל הנתונים.

המערכת מתעלמת מההגדרות הבאות של קבוצת העמודות, כי Bigtable מנהל בשבילכם את האחסון הבסיסי:

  • BLOCKCACHE
  • BLOCKSIZE
  • BLOOMFILTER
  • CACHE_BLOOMS_ON_WRITE
  • CACHE_DATA_IN_L1
  • CACHE_DATA_ON_WRITE
  • CACHE_INDEX_ON_WRITE
  • COMPRESS_TAGS
  • COMPRESSION
  • COMPRESSION_COMPACT
  • DATA_BLOCK_ENCODING
  • EVICT_BLOCKS_ON_CLOSE
  • IN_MEMORY
  • KEEP_DELETED_CELLS
  • PREFETCH_BLOCKS_ON_OPEN
  • REPLICATION_SCOPE

ההגדרות VERSIONS,‏ MIN_VERSIONS ו-TTL מומרות לכללי מדיניות של איסוף אשפה ב-Bigtable.

שמות של קבוצות עמודות ב-Bigtable חייבים להתאים לביטוי הרגולרי [_a-zA-Z0-9][-_.a-zA-Z0-9]*. אם אתם מייבאים נתונים ל-Bigtable מ-HBase, יכול להיות שתצטרכו קודם לשנות את שמות המשפחות כך שיתאימו לתבנית הזו.

שורות ותאים

  • אי אפשר להגדיר רשימת ACL לשורה בודדת. תצוגות מורשות ב-Bigtable מאפשרות לתת גישה לקבוצת משנה של נתונים בטבלה, אבל הן לא נחשפות דרך HBase API.
  • אי אפשר להגדיר את הרשאות הגישה של תאים ספציפיים.
  • אין תמיכה בתגים. אי אפשר להשתמש במחלקה org.apache.hadoop.hbase.Tag כדי להוסיף מטא-נתונים לתאים ספציפיים. כל התגים שמוסיפים לתא נמחקים לפני שהתא נכתב.

מוטציות ומחיקות

  • פעולות Append ב-Bigtable הן אטומיות לחלוטין גם לקוראים וגם לכותבים. הקוראים אף פעם לא יוכלו לקרוא פעולת Append שהוחלה באופן חלקי.
  • פעולות Increment הן אטומיות, אבל אי אפשר להגדיר טווח זמן ב-Increment.
  • אובייקט RowMutations שאתם מעבירים אל Table#mutateRow() יכול להכיל פעולות Put ו-Delete או פעולות Append ו-Increment, אבל לא את שתיהן. אובייקטים מסוג RowMutations שמכילים פעולות מסוג Append או Increment לא נתמכים ב-batch(), ב-checkAndMutate() או ב-BufferedMutator.
  • אפשר למחוק גרסה ספציפית של עמודה ספציפית על סמך חותמת הזמן שלה. עם זאת, אין תמיכה בסוגי המחיקות הבאים:

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

    לכן, השיטות הבאות במחלקה org.apache.hadoop.hbase.client.Delete לא נתמכות: + new Delete(byte[] row, long timestamp) + addColumn(byte[] family, byte[] qualifier) + addFamily(byte[] family, long timestamp) + addFamilyVersion(byte[] family, long timestamp)

  • ב-HBase, פעולות מחיקה מסתירות פעולות הוספה, אבל ב-Bigtable פעולות הוספה לא מוסתרות אחרי פעולות מחיקה כשבקשות ההוספה נשלחות אחרי בקשות המחיקה. כלומר, ב-Bigtable, בקשת כתיבה שנשלחת לתא לא מושפעת מבקשת מחיקה שנשלחה בעבר לאותו תא.

בקשות GET וסריקות

מעבדי עזר

אין תמיכה במעבדי עזר. אי אפשר ליצור מחלקות שמטמיעות את הממשק org.apache.hadoop.hbase.coprocessor.

מסננים

בטבלה הבאה מפורטים המסננים שנתמכים בחבילה org.apache.hadoop.hbase.filter. כל שאר המסננים בחבילה הזו לא נתמכים ומחזירים את השגיאה UnsupportedOperationException.

נתמך נתמך, עם מגבלות
  1. ברוב המקרים, PrefixFilter סורק שורות ב-PrefixFilter. עם זאת, אם PrefixFilter הוא חלק מ-FilterList ויש לו את האופרטור MUST_PASS_ONE, Bigtable לא יכול לקבוע את הטווח המשתמע, ובמקום זאת מבצע סריקה לא מסוננת משורת ההתחלה ועד שורת העצירה. כדי לשפר את הביצועים במקרה כזה, אפשר להשתמש ב-PrefixFilter עם BigtableExtendedScan או בשילוב של מסננים.
  2. נדרשת קבוצת עמודות אחת רק כשמשתמשים במגדיר עמודה כהיסט העמודה.
  3. תמיכה בקבוצת עמודות אחת בלבד.
  4. תומך רק באופרטור EQUAL, עם האופרטור להשוואה BinaryComparator או האופרטור להשוואה RegexStringComparator.
  5. אין תמיכה ביצירת המסנן באמצעות new KeyOnlyFilter(true).
  6. לא יכול להיות חלק מ-FilterList שמשתמש באופרטור MUST_PASS_ONE.
  7. המסנן PageFilter חייב להיות המסנן ברמה העליונה או המסנן האחרון ב-FilterList ברמה העליונה שמשתמש באופרטור MUST_PASS_ALL, שהוא התנהגות ברירת המחדל. אין תמיכה ב-PageFilter ב-FilterList שמשתמש באופרטור MUST_PASS_ONE.
  8. תומך רק באופרטור ההשוואה BinaryComparator, או באופרטור ההשוואה RegexStringComparator עם האופרטור EQUAL. אם משתמשים באופרטור אחר, לא EQUAL, אפשר להשתמש רק בקבוצת עמודות אחת.
  9. תומך רק באופרטורים הבאים להשוואה:
    • BinaryComparator
    • ‫RegexStringComparator בלי דגלים (המערכת מתעלמת מהדגלים) והאופרטור EQUAL
  10. הוא מסתמך על מסנן התנאים של Bigtable, שיכול להיות איטי. יש תמיכה, אבל לא מומלץ.
  11. בכל סריקה אפשר להוסיף רק WhileMatchFilter אחד.
ColumnCountGetFilter
ColumnPrefixFilter
FilterList
FirstKeyOnlyFilter
FuzzyRowFilter
MultipleColumnPrefixFilter
PrefixFilter 1
RandomRowFilter
TimestampsFilter
ColumnPaginationFilter 2
ColumnRangeFilter 3
FamilyFilter 4
KeyOnlyFilter 5
MultiRowRangeFilter 6
PageFilter 7
QualifierFilter 8
RowFilter 4
SingleColumnValueExcludeFilter 3, 9, 10
SingleColumnValueFilter 9, 10
ValueFilter 9
WhileMatchFilter 6, 11

בנוסף, ההבדלים הבאים משפיעים על המסננים של Bigtable:

  • אפשר להשתמש רק באופרטורים להשוואה BinaryComparator ו-RegexStringComparator. כל שאר האופרטורים להשוואה לא נתמכים וגורמים ל-UnsupportedOperationException.
  • במסננים שמשתמשים בהשוואה של ביטויים רגולריים (org.apache.hadoop.hbase.filter.RegexStringComparator), הביטויים הרגולריים משתמשים בתחביר RE2, ולא בתחביר Java.
  • אין תמיכה במסננים בהתאמה אישית. אי אפשר ליצור מחלקות שיורשות מ-org.apache.hadoop.hbase.filter.Filter. כדי להשתמש במסנן Bigtable שאין לו מקביל ב-HBase, צריך לעטוף אותו ב-com.google.cloud.bigtable.hbase.filter.BigtableFilter.
  • גודל הקובץ המקסימלי של ביטויי סינון הוא 20KB, ואי אפשר להגדיר יותר מ-20 רמות של מסננים בתצוגת עץ. כדי לעקוף את הבעיה ולהקטין את הגודל של ביטוי המסנן, אפשר להשתמש בעמודה משלימה שבה מאוחסן ערך ה-hash של הקריטריונים לסינון.

חותמות זמן

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

ספריית הלקוח ממירה בין מיקרו-שניות למילי-שניות, אבל מכיוון שחותמת הזמן הגדולה ביותר של HBase ש-Bigtable יכול לאחסן היא Long.MAX_VALUE/1000, כל ערך שגדול ממנה מומר ל-Long.MAX_VALUE/1000. כתוצאה מכך, יכול להיות שערכים גדולים של חותמות זמן הפוכות לא יומרו בצורה נכונה.

ניהול

בקטע הזה מוסבר איך לקוח Bigtable HBase ל-Java מטמיע את הממשק org.apache.hadoop.hbase.client.Admin. מכיוון ש-Bigtable מטפל ברוב משימות הניהול של האשכולות והאחסון באופן אוטומטי, הרבה שיטות ניהול של HBase לא רלוונטיות. כל שיטה של Admin שלא מופיעה בקטע הזה כנתמכת או כחסרת השפעה, לא נתמכת ומחזירה UnsupportedOperationException.

ניהול טבלאות

אפשר להשתמש ב-Admin בשיטות הבאות לניהול טבלאות וקבוצות עמודות:

  • ‫addColumnFamily(TableName tableName, ColumnFamilyDescriptor columnFamily) ו-addColumnFamilyAsync(TableName tableName, ColumnFamilyDescriptor columnFamily) (HBase 1.x: addColumn(TableName tableName, HColumnDescriptor column))
  • ‫createTable(TableDescriptor desc), createTable(TableDescriptor desc, byte[][] splitKeys), createTable(TableDescriptor desc, byte[] startKey, byte[] endKey, int numRegions), createTableAsync(TableDescriptor desc) וגם createTableAsync(TableDescriptor desc, byte[][] splitKeys)
  • ‫deleteColumnFamily(TableName tableName, byte[] columnName) ו-deleteColumnFamilyAsync(TableName tableName, byte[] columnName) (HBase 1.x: deleteColumn(TableName tableName, byte[] columnName))
  • ‫deleteTable(TableName tableName),‏ deleteTableAsync(TableName tableName),‏ deleteTables(Pattern pattern) וגם deleteTables(String regex)
  • disableTable(TableName tableName), disableTableAsync(TableName tableName), disableTables(Pattern pattern) וגם disableTables(String regex)
  • ‫enableTable(TableName tableName),‏ enableTableAsync(TableName tableName),‏ enableTables(Pattern pattern) וגם enableTables(String regex)
  • getAlterStatus(TableName tableName) וגם getAlterStatus(byte[] tableName)
  • ‫getDescriptor(TableName tableName),‏ getTableDescriptor(TableName tableName),‏ getTableDescriptors(List<String> names) וגם getTableDescriptorsByTableName(List<TableName> tableNames)
  • isTableAvailable(TableName tableName) וגם isTableAvailable(TableName tableName, byte[][] splitKeys)
  • isTableDisabled(TableName tableName) וגם isTableEnabled(TableName tableName)
  • ‫listTableDescriptors(),‏ listTableDescriptors(List<TableName> tableNames),‏ listTableDescriptors(Pattern pattern) ו-listTableDescriptors(Pattern pattern, boolean includeSysTables) (HBase 1.x: ‏listTables(),‏ listTables(Pattern pattern),‏ listTables(Pattern pattern, boolean includeSysTables),‏ listTables(String regex) ו-listTables(String regex, boolean includeSysTables))
  • ‫listTableNames(), listTableNames(Pattern pattern), listTableNames(Pattern pattern, boolean includeSysTables), listTableNames(String regex) וגם listTableNames(String regex, boolean includeSysTables)
  • ‫modifyColumnFamily(TableName tableName, ColumnFamilyDescriptor columnFamily) ו-modifyColumnFamilyAsync(TableName tableName, ColumnFamilyDescriptor columnFamily) (HBase 1.x: modifyColumn(TableName tableName, HColumnDescriptor column))
  • ‫modifyTable(TableDescriptor td),‏ modifyTable(TableName tableName, TableDescriptor td),‏ modifyTableAsync(TableDescriptor td) וגם modifyTableAsync(TableName tableName, TableDescriptor td)
  • tableExists(TableName tableName)
  • ‫truncateTable(TableName tableName, boolean preserveSplits) ו-truncateTableAsync(TableName tableName, boolean preserveSplits)

השיטות הבאות לניהול טבלאות נתמכות ב-Bigtable, אבל הן פועלות בצורה שונה או מתעלמות מפרמטרים מסוימים:

  • אי אפשר להשבית טבלאות Bigtable. ‫disableTable(), disableTableAsync(), disableTables(), enableTable(), enableTableAsync() ו-enableTables() משנים את מצב הטבלה רק בזיכרון של הלקוח (ש-isTableDisabled() ו-isTableEnabled() קוראים).
  • הפקודות modifyTable() ו-modifyTableAsync() מבצעות שינויים רק בקבוצות של עמודות. המערכת מתעלמת ממאפיינים ברמת הטבלה.
  • הפקודות truncateTable() ו-truncateTableAsync() מוחקות את כל הנתונים בטבלה. המערכת מתעלמת מהפרמטר preserveSplits.
  • עומסי יתר של listTableDescriptors(),‏ listTables() ו-listTableNames() שמקבלים פרמטר includeSysTables מתעלמים מ-includeSysTables, כי ל-Bigtable אין טבלאות מערכת.
  • הפונקציה isTableAvailable(TableName tableName, byte[][] splitKeys) בודקת רק אם הטבלה קיימת ומתעלמת מהפרמטר splitKeys.
  • הפונקציה getAlterStatus() תמיד מחזירה את הערך (0, 0) כי שינויי הסכימה ב-Bigtable הם סינכרוניים.

משימות כמו דחיסה ופיצול של טבלאות מטופלות באופן אוטומטי. לכן, לשיטות הבאות אין השפעה:

  • compact(TableName tableName)
  • compact(TableName tableName, byte[] columnFamily)
  • majorCompact(TableName tableName)
  • majorCompact(TableName tableName, byte[] columnFamily)
  • split(TableName tableName)
  • split(TableName tableName, byte[] splitPoint)

תמונות מצב

שיטות של תמונת מצב של HBase יוצרות ומנהלות גיבויים של Bigtable. מכיוון שהגיבויים מאוחסנים באשכול ספציפי, אם למכונה יש יותר מאשכול אחד, צריך להגדיר את מאפיין ההגדרה google.bigtable.snapshot.cluster.id לאשכול שבו רוצים להשתמש. התוקף של גיבויים שנוצרים באמצעות snapshot() פג אחרי מספר השניות שמוגדר במאפיין ההגדרה google.bigtable.snapshot.default.ttl.secs (ברירת המחדל היא 24 שעות). ‫cloneSnapshot() משחזר מגיבוי לטבלה חדשה.

אפשר להשתמש בשיטות הבאות ליצירת קובץ Snapshot ב-Admin:

  • cloneSnapshot(byte[] snapshotName, TableName tableName)
  • cloneSnapshot(String snapshotName, TableName tableName)
  • deleteSnapshot(byte[] snapshotName)
  • deleteSnapshot(String snapshotName)
  • snapshot(byte[] snapshotName, TableName tableName)
  • snapshot(String snapshotName, TableName tableName)

בנוסף, AsyncAdmin תומך ב-listSnapshots(), ב-listSnapshots(Pattern pattern) וב-snapshot(SnapshotDescription snapshot). כל השיטות האחרות ליצירת תמונות מצב – כולל restoreSnapshot(),‏ deleteSnapshots(),‏ deleteTableSnapshots(),‏ listTableSnapshots() ו-cloneSnapshot(String snapshotName, TableName tableName, boolean restoreAcl) – לא נתמכות וגורמות להצגת השגיאה UnsupportedOperationException.

ניהול אזורים

ב-Bigtable משתמשים בטאבלטים, שדומים לאזורים. אפשר להשתמש בשיטות הבאות כדי לאחזר מידע על אזורים, עם הבדלים מ-HBase רגיל:

  • ‫getRegions(TableName tableName) ו-getTableRegions(TableName tableName), וגם השיטות בממשק org.apache.hadoop.hbase.client.RegionLocator, מחזירות גבולות משוערים על סמך דגימה של מפתחות שורות בטבלה. שמות השרתים באזורים שמוחזרים הם לא שרתים אמיתיים.
  • ‫getRegionMetrics(ServerName serverName, TableName tableName) מתעלם מהפרמטר serverName ומחזיר מדדים משוערים של גודל האזור, על סמך דגימה של מפתחות שורות בטבלה.

מכיוון ש-Bigtable מנהל את הטאבלטים באופן אוטומטי, לשיטות הבאות אין השפעה:

  • assign(byte[] regionName)
  • compactRegion(byte[] regionName)
  • compactRegion(byte[] regionName, byte[] columnFamily)
  • flushRegion(byte[] regionName)
  • majorCompactRegion(byte[] regionName)
  • majorCompactRegion(byte[] regionName, byte[] columnFamily)
  • splitRegion(byte[] regionName)
  • splitRegion(byte[] regionName, byte[] splitPoint)

ב-HBase 1.x, גם הערכים הבאים לא מושפעים: compactRegionServer(ServerName sn, boolean major),‏ mergeRegions(byte[] encodedNameOfRegionA, byte[] encodedNameOfRegionB, boolean forcible),‏ move(byte[] encodedRegionName, byte[] destServerName) ו-unassign(byte[] regionName, boolean force). המקבילות שלהם ב-HBase 2.x לא נתמכות וגורמות ל-UnsupportedOperationException.

סטטוס האשכול והחיבור

‫Bigtable מטפל במשימות התחזוקה של האשכולות באופן אוטומטי, ולכן שיטות התחזוקה ב-Admin מחזירות UnsupportedOperationException. רק השיטות הבאות לחיבור ולסטטוס נתמכות:

  • ל-close() אין השפעה.
  • הפונקציות getClusterMetrics(),‏ getClusterMetrics(EnumSet<Option> options) ו-getClusterStatus() מחזירות ערכים זמניים לשמירת מקום (פלייסהולדרים) עם רשימות שרתים ריקות, והפונקציה getClusterMetrics(EnumSet<Option> options) מתעלמת מהפרמטר options.
  • ‫getConfiguration() מחזיר את האובייקט Configuration של הלקוח.
  • ‫getConnection() מחזיר את האובייקט Connection של הלקוח.

מרחבי שמות

ב-Bigtable לא משתמשים במרחבי שמות. אפשר להשתמש בתחיליות של מפתחות שורות כדי לדמות מרחבי שמות.

כברירת מחדל, כל השיטות של מרחב השמות מחזירות UnsupportedOperationException. עם זאת, אם מגדירים את מאפיין ההגדרה google.bigtable.namespace.warnings כ-true, השיטות הבאות מתעדות אזהרה ביומן ואין להן השפעה (הן מחזירות null או תוצאה ריקה) במקום להציג חריגה:

  • createNamespace(NamespaceDescriptor descriptor)
  • deleteNamespace(String name)
  • deleteNamespaceAsync(String name)
  • getNamespaceDescriptor(String name)
  • listNamespaceDescriptors()
  • listTableDescriptorsByNamespace(byte[] name)
  • listTableDescriptorsByNamespace(String name)
  • listTableNamesByNamespace(String name)
  • modifyNamespace(NamespaceDescriptor descriptor)

גם אם google.bigtable.namespace.warnings מוגדר ל-true, listNamespaces() זורק UnsupportedOperationException.

תכונות ניהוליות אחרות

‫Bigtable לא תומך ב-methods של Admin בקטגוריות הבאות, וקריאה להן גורמת ל-UnsupportedOperationException:

  • קבוצות מקומיות: ב-Bigtable אי אפשר לציין קבוצות מקומיות למשפחות של עמודות.
  • מעבדי עזר ופרוצדורות מבוזרות: Bigtable לא תומך במעבדי עזר או בפרוצדורות מבוזרות.
  • מכסות: במאמר מכסות ומגבלות מוסבר על המכסות של Bigtable.
  • רפליקציה: Bigtable משכפל נתונים באופן אוטומטי בין האשכולות במכונה. לפרטים נוספים, קראו את הסקירה הכללית על רפליקציה. במאמר שכפול מ-HBase ל-Bigtable מוסבר איך לשכפל מ-HBase ל-Bigtable.
  • בקרת גישה: ב-Bigtable משתמשים ב-IAM לבקרת גישה.
  • קבוצות RegionServer: שירות Bigtable מנהל את השרתים באופן אוטומטי ולא חושף קבוצות RegionServer.