Pull to refresh

Riak — веб-ориентированная система хранения данных

Reading time9 min
Views30K


Немного статей на хабре посвящены новому движению в IT индустрии — NoSQL. Я решил изменить это и написал статью-перевод-обзор об одном из докладов с конференции NoSQL прошедшей 5 октября в Нью-Йорке. В этой статье будет говорится о системе Riak, с которой мне довелось иметь счастье работать последнее время.

Что такое Riak? Многие модные слова популярные сейчас, можно отнести к Riak. Riak — это документно-ориентированная база данных. Riak — это децентрализованное key-value хранилище данных, с поддержкой стандартных операций — get, put и delete. Riak — это распределенное, масштабируемое, отказоустойчивое решение для хранения информации. А так же Riak — это система с открытым исходным кодом и поддержкой обращений с помощью HTTP, JSON и REST. Ну и конечно RIAK — это NoSQL.

Если копнуть глубже, можно увидеть, что на Riak оказало сильное влияние Amazon Dynamo, теорема CAP (Consistency, Availability and Partition Tolerance) Эрика Бревера (Eric Brewer), сама система Интернета в целом, а так же опыт команды разработки Basho в разработке сетевых сред. Мы начали разрабатывать Riak осенью 2007 года, для использования в двух приложениях для Basho, которые были запущенны на Riak и работали на нем большую часть времени.

Чтобы понять почему Riak настолько мощный, требуется рассказать немного теории. Вначале поговорим об Amazon Dynamo.В документе описывающем Amazon Dynamo есть три термина для описания поведения распределенной системы хранения данных: N, R и W. N — это количество реплик каждого значения в хранилище. R — количество данных реплик для выполнения операции чтения. W — количество реплик необходимых для выполнения операции записи. Цель Riak — перенести N, R, и W в логику приложения. Это позволяет Riak адаптироваться к требованиям отдельных приложений.



Riak использует разные значения N для каждого сегмента (bucket). Например все объекты в сегменте «artist» будут иметь одинаковое значение N, а объекты в сегменте «album» совсем другое. Система использует непротиворечивый алгоритм хеширования для выбора места сохранения N количества реплик ваших данных. Когда поступает запрос, Riak использует хеширование для преобразования текстового ключа в 160-битное число. Когда узел кластера добавляется в Riak, он получает части от 160-битного пространства ключей. Узел имеющий ближайшее значение хэша от ключа (160-битное число) и содержит в себе первую реплику. Остальные N реплик сохранены на узлах с другими N-1 частями 160-битного пространства ключей.Непротиворечивый алгоритм кэширования очень важен — он позволяет каждому узлу Riak выполнить любой запрос. Поскольку любой узел может вычислить, с какими именно другими узлами необходимо связаться, чтобы выполнить запрос, любой узел может выступать в качестве организатора для любого клиента. Тут нет управляющего сервера, нет единой точки для сбоя в системе.



Riak использует разные значения R для каждого запроса. Каждый раз когда вы делаете запрос на получение данных, вы можете использовать разное значение R. Значение R определяет количество узлов, которым необходимо вернуть успешный ответ, перед тем как Riak вернет запрашивающему клиенту ответ. Riak пытается прочитать все возможные реплики (N), но когда будет достигнуто значение R, данные будут отправлены обратно клиенту.



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

Предоставление клиенту возможности для указания значений R и W во время запроса, означает, что во время запроса приложение может указать точно, сколько узлов могут выйти из строя. Это очень просто: для каждого запроса, N-R (для чтения) или N-W (для записи) узлов может быть недоступно, однако кластер и данные будут по-прежнему вполне доступны.



Итак, в примере который мы использовали с N=3 и R=W=2, мы можем иметь 3–2=1 узел недоступным в кластере, но кластер по прежнему будет предоставлять данные. Для особо важных данных, мы можем увеличить значение N до 10, и если мы все ещё будем использовать значение R или W равное 2, мы можем иметь 8 недоступных узлов в кластере, но запросы на чтение и запись будут проходить успешно. Riak дает возможность изменять значения N/R/W так как это хороший способ улучшить поведение приложения при использовании теоремы CAP.

Если вы знакомы с теоремой CAP Эрика Бревера, вы знаете, что есть три аспекта, которые необходимо учитывать при рассуждениях о хранении данных: целостность данных, доступность данных в хранилище, и устойчивость к разделению. Если вы знакомы с исследованием, вы также знаете, что невозможно реализовать систему отвечающую всем трем условиям.

Поскольку вы не можете реализовать все три условия, большинство систем хранения данных используют два. Riak позволяет, не только выбрать любые из них, но и разные приложения могут выбрать различные объемы каждого. Вероятнее всего вы выберите доступность и устойчивость к разделению. Однако вы разрабатываете аппликации которые работают на реальных машинах и вы хотите чтобы они были доступны в любое время для пользователей. Структура Riak реализована для поддержки этой возможности (мы хотим чтобы наши приложения работали все время). Это означает, что вы готовы пожертвовать целостностью данных. Есть много советов как выв можете гарантировать целостность данных (например read-your-writes) в документе описывающем Amazon Dynamo и я советую вам перечитать этот документ.

Вот простой пример как может быть решен вопрос с целостностью данных. Давайте посмотрим на кластер который уже работает и имеет документ с версией 0.



Вдруг в сети происходит сбой. Узлы 0 и 2 находятся в Нью-Йорке, узлы 1 и 3 в Лос-Анджелесе и трансконтинентальная связь рвется. Как поведет себя каждая часть кластера? Если вы установили значения N/R/W надлежащим образом, обе части кластера по сути будут предоставлять версию 0 документа, как и раньше. Клиенты не будут знать о сбое. Теперь предположим что клиент внес изменения в документ, хранящийся в половине кластера находящегося в Нью-Йорке (вы же указали N/R/W так, чтобы это было разрешено?). Этот клиент ввел некоторое несоответствие. Теперь клиенты присоединившиеся к части кластера находящегося в Нью-Йорке получат версию 1 документа, в то время как клиенты присоединившееся к части находящейся в Лос-Анджелесе получат версию 0 этого документа. Теперь предположим что трансконтинентальная связь восстанавливается и обе половины кластера работают вместе. Что должен сделать Riak с двумя разными версиями документа?

В этом случае Riak использует алгоритм вектора времени, для определения какая версия документа более корректная. Алгоритм вектора времени это специальная реализация алгоритма временных меток Лампорта (Lamport clocks / Lamport timestamps). В отличии от обычных временных меток, система временных меток Лампорта построена таким образом, что происхождение и преемственность, может быть определена путем простого сравнения. Каждый раз когда данные сохраняются в Riak, их вектор времени увеличивается, и когда кластер восстановиться Riak сможет определить какие данные сохранить. В нашем случае Riak определит что версия 1 является приемником версии 0, и версия 0 будет заменена версией 1, и данные снова будут целостны.



Все становится немного более интересно, если в то время как части не связанны, клиенты внесут изменения в обоих частях кластера. Теперь когда кластер восстановится, вектор времени покажет, что ни одна из версий является преемницей другой версии. Riak не может определить какая из версий должна быть выбрана, поэтому в этом случае как и с возможностью изменить значения N/R/W, Riak переносит возможность урегулирования конфликта в приложение. Вместо реализации произвольного правила выбора версии как это сделано в других системах, Riak возвращает оба значения приложению предоставляя возможность выбора более верного варианта. Конечно если вы хотите использовать просто правило — данные пришедшие последними и используются, в Riak есть простой флаг для включения такого поведения (allow_mult свойство сегмента)



После всей этой теории как насчет нескольких примеров кода для демонстрации как легко работать с Riak?

Так как Riak написан на Erlang, давайте начнем с Erlang.



Первая строка кода описывает присоединение нашего клиента к кластеру Riak. Вторая строка создает новый объект (документ, пара ключ/значение). Третья строка сохраняет объект в Riak. Четвертая возвращает объект обратно из Riak. последние две строки изменяют значение нашего объекта и сохраняют его снова в кластер Riak.

Если вы не хотите использовать Erlang, Riak так же поставляется с библиотеками для Python…


…Riak так же имеет библиотеки для Ruby…

… Java…


… PHP…

… JavaScript…

…но на самом деле все эти библиотеки работают с Riak с помощью стандартного RESTful HTTP, и это позволяет использовать Riak на любой системе поддерживающей HTTP — например используя инструменты командной строки такие как curl или wget.


Это хорошо когда вам нужно отправить или получить данные из Riak, но что делать когда вы хотите сделать запрос по нескольким объектам одновременно? Это же NoSQL, ведь так? Как насчет небольшого Map/Reduce?


Система Map/Reduce Riak имеет много общего с другими системами Map/Reduce. Функция Map происходит на узле где находятся данные, увеличивая локальность данных одновременно с распределением вычислений в кластере. Часть Map/Reduce Riak которая более всего отличается от других решений заметна в том, что Riak не запускает метод Map над всеми данными в сегменте (bucket). Вместо этого Riak дает возможность клиенту предоставить список ключей объектов на которых должен быть запущен метод Map. Методы Map могут предоставлять больше ключей для более поздних фаз выполнения методов Map, но список ключей для метода Map должен быть определен всегда. Конечно вы можете указать любое количество ключей которое вы хотите, например если вы хотите выполнить метод Map по всем значениям в сегменте, достаточно включить их все в запрос Map/Reduce (функции list_keys или list_bucket могут быть полезны в таких случаях).

Различия в реализации Map/Reduce Riak при сравнении с другими системами обусловлены сильным желанием поддержки ссылок в Riak. Первый вопрос при переходе из мира RDBMS это — «Как я могу организовать связи между моими данными?» Было решено что лучший ответ на этот вопрос — ссылки.


Например если вы хотите организовать связи между записью исполнителя и несколькими записями альбомов, вы хотите создавать ссылки к альбомам в записи исполнителя. Аналогично вы можете создать ссылки в записи альбома к записям композиций входящим в этот альбом. Как только вы добавите ссылки и определите как Riak может получить эти ссылки из ваших объектов, вы получите доступ к новому синтаксису Map/Reduce. Например в данном примере вы можете видеть простой синтаксис позволяющий нам сказать — «Начни с исполнителя REM, потом следуй ко всем альбомам с которым связан исполнитель, потом следуй ко всем композициям с которыми связан альбом, потом извлеки имена этих композиций." Результатом этого запроса будут имена всех композиций REM которые были когда-либо выпущены.

Разработчики решили что link-walking (переход по ссылкам) настолько полезный, что даже реализовали URL синтаксис для него. Вверху вы можете видеть ссылку похожую на URL, и выполнение GET запроса по этому URL вернет вам список всех объектов композиций, который ранее мы получили в примере с Map/Reduce.

Можно ещё много чего рассказать про Riak, включая как создавать подключаемые бэкэнды, как использовать систему событий, как отслеживать состояние кластеров Riak и как реализовать межкластерную репликацию. Но это подождет до другой презентации.

Если вы заинтересованы в получении дополнительной информации, вы можете посетить сайт http://riak.basho.com/ где вы можете изучить документацию и загрузить Riak для ваших экспериментов. Так же существует список рассылки riak-users@lists.basho.com. Ну и конечно вы можете посмотреть видео данного доклада.

***
Надеюсь вы почерпнули из данной статьи много интересной и полезной информации. В дальнейшем если данная тема найдет отклик на сайте, торжественно заявляю, что буду продолжать серию статей на тему NoSQL. Передаю респекты командам проектов Translated.by и Типограф, благодаря им создание данной статьи было приятным времяпрепровождением.
Tags:
Hubs:
+68
Comments32

Articles

Change theme settings