Некоторое время назад Neuronus в одном из комментариев к посту "Hadoop возвращается" не согласился с моим кратким определением HBase как "нереляционная база данных" (позаимствованным, собственно говоря, откуда-то с официального портала продукта). Этот факт подтолкнул меня попытаться найти более корректное определение в англоязычных источниках информации, получилось вполне успешно. Хочется прочитать более детально что к чему? Вперед! Если Вам уже приходилось иметь дело с этой системой,возможно Вы уже поняли, что самым сложным этапом работы является просто-напросто осознавание того, чем она на самом деле является. Обычно приходится мысленно отказаться от всех привычек, доставшихся при работе с традиционный RDBMS, и начинать постигать базовые принципы организации хранения данных с нуля.

Стоит напомнить, что проект позиционируется как opensource реализация BigTable от Google. Да, проекты реализованы разными людьми на разных языках программирования, но общие идеи и принципы функционирования у них сильно пересекаются. Наиболее значимой общей характеристикой у них является очень схожие модели данных (о чем упоминается в вики HBase), а в свою очередь в документации BigTable она описывается очень четко и определенно, точно определяя чем эти продукты по сути являются:

A Bigtable is a sparse, distributed, persistent multidimensional sorted map.

Предлагаю по аналогии со статьей в вики, послужившей основой для данного поста, разбить это определение на отдельные слова и последовательно пройтись по ним, попутно составляя в голове полную картину.

map

За этим термином нет четкого устоявшегося обозначения в русском языке (да и в английском тоже все далеко не так однозначно), математики обычно называют это отображением одного множества в другое, в то время как если Вы знакомы с программированием, то Вам наверняка больше знакомы будут более знакомы такие обозначения, как ассоциативный массив (PHP), словарь (Python), хэш (Ruby) или объект (JavaScript).

По сути же имеется ввиду просто набор однозначно соответствующих пар ключ-значение, в роли которых выступают массивы байт. Во все той же статейке в вики все очень наглядно демонстрируется примерами в нотации JSON, позволю себе тоже приводить аналогичные примеры. В JSON наш map выглядел бы следующим образом:

{
  "qqqq" : "some",
  "abc" : "sample",
  "zz" : "JSON",
  "123" : "map",
  "mnbvcxz" : "looks like this"
}

persistent

Это прилагательное обозначает всего лишь "постоянный", то есть в данном контексте оно говорит только о том, что данная система не зависит от использующих ее приложений, а также хранится на устройствах постоянного хранения данных, а не в оперативной памяти.

distributed

Распределенность этих систем можно рассматривать с двух точек зрения:

  • Как HBase, так и BigTable сами по себе могут функционировать на большом количестве серверов, которые можно разделить на две большие категории: master и slave. Slave сервера собственно выполняют всю работу с данными, а master - лишь только координируют их действия и управляют процессом в целом. Этот факт обеспечивают высокую степень устойчивости к сбоям (в HBase правда количество master-серверов ограничено одним, что представляет собой единственную точку, сбой в которой приведет к отказу всей системы, но это лишь временная проблема, которую наверняка устранят в следующих версиях), а также существенно облегчает масштабируемость всей системы так как добавление дополнительных серверов (а значит и увеличение производительности и вместительности системы) достаточно тривиально, безболезненно и не мешает общему ее функционированию.
  • Помимо этого каждая из этих систем обычно использует для хранения данных кластерную файловую систему (HBase - HDFS, а BigTable - GFS), которые тоже по своей природе являются распределенными и функционируют по схожему принципу, обеспечивая дополнительную сохранность данных, реплицируя их в нескольких экземплярах на нескольких серверах (обычно трех).

sorted

HBase и BigTable не строят никакие индексы для ускорения процесса извлечения данных, единственное используемое в них правило заключается в следующем: каждый slave-сервер в системе отвечает за определенный диапазон ключей (от и до определенных его значений), и держит все записи в строгом лексикографическом порядке по ключам (заметьте: сортировку значений никто не гарантирует!). Продолжая пример с JSON это выглядело бы примерно вот так:

{
  "123" : "map",
  "abc" : "sample",
  "mnbvcxz" : "looks like this",
  "qqqq" : "some",
  "zz" : "JSON"
}

Этим фактом можно активно пользоваться при планировании использовании системы, например если в качестве ключей планируется использовать доменные именные имена, то имеет смысл использовать их в "развернутом" виде, например: "com.example.www" вместо "www.example.com". Это почти наверняка обеспечит попадание всех поддоменов одного и того же домена на один slave-сервер, а также группировку доменов по зонам.

multidimensional

До сих пор ключ интерпретировался нами как нечто единое и неделимое, но на самом деле в данной ситуации это далеко не так. На самом деле пространство имен HBase и BigTable имеет несколько пространств, по аналогии с трехмерным материальным пространством, где есть ширина, высота и глубина. Если мы попытаемся представить это с помощью JSON, то это будет выглядеть как набор вложенных простых map'ов:

{
  "table-1":
  {
     "column-family-1":
     {
        "column-1":
        {
           "row-1":
           {
              "timestamp-1": "value-1",
              "timestamp-2": "value-2",
              "timestamp-3": "value-3"
           },
           "row-2":
           {
              "timestamp-1": "value-4",
              "timestamp-2": "value-5",
              "timestamp-3": "value-6"
           }
        },
        "column-2":
        {
           "row-1":
           {
              "timestamp-1": "value-1",
              "timestamp-3": "value-3"
           },
           "row-2":
           {
              "timestamp-1": "value-4",
              "timestamp-2": "value-5",
              "timestamp-3": "value-6"
           }
        }
     "column-family-2":
     {
        "column-1":
        {
           // ...
        },
        "":
        {
           "row-1": "some-value"
        }
        // ...
     }
     }
  }
}

Как можно увидеть из примера, таких пространств используется пять:

  • таблицы;
  • наборы столбцов;
  • столбцы;
  • строки;
  • время;

Таким образом, каждое значение в хранилище данных однозначно соответствует ключу, состоящему из пяти компонентов, например в примере значению "value-5" соответствует ключ, состоящий из:

  • table-1;
  • column-family-1;
  • column-1;
  • row-2;
  • timestamp-2;

Принцип очень похож на используемый в более привычных базах данных, с той лишь разницей, что добавляется еще и время (которое обычно представляется в виде целочисленного значения, обозначающего количество секунд с начала эпохи). Изначально оно задумывалось для предоставления возможности отследить историю изменения данных, но этому дополнительному измерению можно найти и массу нестандартных применений, например используя его как самый обыкновенный стек.

Хочется обратить внимание, что ассортимент наборов столбцов (column family) указывается при создании таблиц, и изменения в них должны производиться с помощью специального запроса, в то время как сами столбцы являются динамическими и для его создания достаточно лишь добавить в него данные.

sparse

Развивая мысль предыдущего абзаца, можно понять, что наличие значения столбца в каждой строке вовсе не обязательно, оно запросто может и отсутствовать вовсе. Таким образом каждая строка может содержать произвольное количество значений для столбцов в рамках одной column family, ровно как может и не содержать их вовсе. Несуществующие данные не хранятся в виде какого-либо NULL-значения, они просто отсутствуют. Запрос на несуществующие данные просто вернет пустой результат. Если же взглянуть с другой стороны, то тот же самый факт можно представить и как возможность наличия пробелов в списке ключей строк.

И напоследок...

хочется сказать, что все это лишь дело терминологии, ровно то же самое можно подразумевать и под краткой фразой "нереляционная база данных", не смотря на то, что она существенно менее точна и полноценна. В данном контексте самое главное лишь чтобы люди просто понимали друг друга. Надеюсь после прочтения этого поста в вашем сознании сложилась четкая картина этого продукта и предоставляемых им возможностей, которая Вам пригодится как для "общего развития", так и для потенциального практического применения этого продукта. Если остались неясные моменты - смело оставляйте комментарии. Традиционная подписка на RSS - приветствуется :)