Статьи

Гибридный NoSQL: варианты использования значения ключа

Я говорил о том, как поставщики баз данных NoSQL пытаются поддерживать больше моделей данных из других типов баз данных NoSQL. Я называю эти гибридные базы данных NoSQL. В этой статье серии Hybrid NoSQL я рассказываю о том, как другие типы баз данных NoSQL могут обрабатывать случаи использования Key-Value.

Что такое хранилище ключей?

Хранилище KV — это относительно простая модель данных, но позволяющая ослепительно быстро обрабатывать данные Поскольку скорость важна, более продвинутая функциональность обычно не поддерживается.

Большинство вещей может быть хранилищем ключей. Файловая система вашего ноутбука — это хранилище ключей и значений. Ключ — это имя файла, а значение — содержимое файла. Ваш ноутбук (как правило) ничего не знает о файле и не обрабатывает его специально — он просто позволяет открывать, читать, изменять и сохранять содержимое. Никаких модных операций вообще.

Что могут делать магазины KV?

Вот операции, которые могут выполнять все магазины KV:

  • Сохраните это двоичное значение с этим ключевым идентификатором
  • Получить двоичное значение для этого ключевого идентификатора
  • Разделите мои данные между несколькими серверами, равномерно распределяя мои пары KV, чтобы обеспечить производительность

Вот некоторые не очень распространенные функции:

  • Увеличить / уменьшить значение этого ключа (Redis DECR, DECRBY, INCR, INCRBY, INCRBYFLOAT)
  • Проверьте ключ существует (Redis EXISTS)
  • Добавить эти данные в список (или набор), содержащийся в значении этого ключа (Redis APPEND)
  • Стековые операции (Redis LPUSH и LPOP)
  • Операции с хеш-полями (команды Redis, начинающиеся с H * — их много!)
  • Геопространственные полевые операции (бета-тестирование, функция Redis с GEOADD, GEODIS, GEOHASH, GEORADIUS, GEOPOS)
  • Опубликовать / подписаться (Redis позволяет клиентам подписываться на уведомления о ключах! Классно!)

Зачем мне делать эти операции в другом типе базы данных NoSQL?

Возможно, потому что у вас уже есть его, или у вас также есть необходимость в хранилище документов или хранилище столбцов в другом приложении — и вам интересно, можете ли вы использовать его повторно. Конечно, он никогда не будет таким ослепительно быстрым, как чистый магазин KV, но, возможно, вам не нужно обрабатывать 400 000 транзакций в секунду на сервер.

Что я могу и не могу сделать?

Я собираюсь использовать MarkLogic Server для сравнения. MarkLogic — это гибридная база данных NoSQL, поддерживающая операции Document, Search и Triple store. Он также может использоваться для хранения произвольных двоичных данных, а также текста, json и XML, для которых он был изначально создан. Многие исходные документы являются бинарными, как PDF-файлы. Это означает, что он обладает основными возможностями хранения и извлечения произвольных данных, как и хранилище KV.

Магазин и выборка

MarkLogic можно использовать для хранения двоичных данных, просто используя его REST API. Сделайте  POST для /v1/documents?uri=/some/doc/uri.bin  с Content-Type: установите соответствующий тип MIME для того, что вы хотите. Используйте  GET / v1 / documents? Uri = что угодно,  чтобы получить его в оригинальном типе контента.

URI в MarkLogic является нашим ключевым идентификатором. Вы можете назначить один самостоятельно, как указано выше, или попросить сервер сгенерировать случайный. В этом случае URI возвращается в ответе POST.

Sharding

Большие двоичные файлы MarkLogic (по умолчанию любые файлы размером более 1 МБ, хотя это можно настроить) хранятся в файловой системе как есть. Изменения заносятся в журнал, и данные реплицируются по причинам высокой доступности в пределах границы транзакции — это совместимо с ACID. Репликация базы данных и резервные копии также работают для двоичных данных, поэтому не стоит беспокоиться.

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

Увеличение / Уменьшение

MarkLogic может использоваться для хранения данных XML и JSON. Эти документы могут быть простыми или сложными, как вам нравится. Они могут быть одним значением, если хотите, как магазин KV, но это не очень эффективно (как магазин KV!). Каждый документ MarkLogic имеет небольшие издержки — около 750 байтов. Таким образом, хранение 2-байтового значения означает, что накладные расходы являются дорогостоящими.

Лучше создать документ со многими значениями и изменить часть этого документа. Например, вместо того, чтобы иметь ключ для продукта для каждого атрибута — например, PRODUCT1234-QuantityInStock — вместо этого у вас есть документ для Product1234, который содержит количество на складе, название продукта, название, штрих-код и все другие метаданные. (Вот почему магазины KV также поддерживают хеши, о которых я расскажу позже в этой статье…)

Но как управлять этими данными? REST API MarkLogic поддерживает  операцию PATCH . Это может сделать несколько вещей. В нашем сценарии его можно использовать для увеличения или уменьшения значения на 1 или любой другой суммы. Используйте  механизм замены патча с операцией  ml.add,  но вы также можете умножать, делить, выполнять поиск и замену по регулярному выражению, объединять строки или выполнять операцию с подстрокой.

Проверьте ключ существует

Если ваш документ в MarkLogic содержит все ваше значение ключа, вы можете просто сделать  HEAD для / v1 / documents? Uri = что угодно . Если вы получите ответ 404, то этот документ не существует.

Если вы хотите проверить значение в пределах одного элемента в документе XML или JSON, это немного сложнее.

MarkLogic индексирует то, что находится в документе, его структуру и какие элементы существуют. Люди обычно не проверяют, существует ли элемент в документе или нет — они обычно извлекают все и проверяют себя. Но вы можете проверить, есть ли у конкретного документа ключ, проверив универсальный индекс с помощью поиска.

По сути, вы создаете поиск, ограниченный одним документом — URI, который вас интересует. Кроме того, вы используете элемент-запрос (теперь называемый контейнерным запросом), чтобы проверить существование элемента. Если ваши результаты поиска возвращают один URI — ваш документ — тогда он существует. В противном случае это не так.

Вы создаете это с помощью POST / v1 / search. Я не проверял ниже, но что-то вроде этого в теле POST должно работать:

{
  "search": {
    "query" : {
      "queries": [{
        "and-query": {
          "queries": [
            {"document-query": {"uri": [ "/my/doc/uri.bin" ]},      // does my doc exist?
            {"container-query": {"json-property": "mypropertykey"}} // does my property exist?
          ]
        }
      }]
    }, 
    "options" : { "return-results" : false, "return-metrics" : false } 
  } 
}

(NB return-results: false означает, что никакие данные результата не будут возвращены, но вы все равно получите счетчик, который вы можете проверить — он будет 0 или 1.)

Добавить данные в список

Операция MarkLogic Patch также поддерживает  режим вставки . При этом вы можете добавить один или несколько элементов к существующему элементу контейнера. Таким образом, вы можете легко реализовать списки, используя вставку с позицией, установленной на «после».

Стек операций

Режим вставки патча позволяет вам указать позицию как «до» или «после», что позволяет размещать элементы в начале и в конце списка. Используя режим удаления Patch, вы также можете удалить первый (/ list / parent / child / fn: first ()) или последний (/ list / parent / child / fn: last ()) элементы списка.

Вы также можете получить определенный элемент, а не полный документ. Для этого вы создаете очень простое  преобразование  (XQuery или XSLT или серверный JavaScript) и используете его с  конечной точкой GET / v1 / documents ? Transform = mytransform. Таким образом, вы можете сохранить один для «первого элемента в списке» и один для «последнего элемента в списке», возможно, даже «получить весь список», если у вас есть сложная структура в ваших документах с ключевыми значениями.

Таким образом, вы можете реализовывать не только стеки (push и pop равняются ‘after’ и ‘fn: last’), но также очереди FIFO и FILO!

Операции хеширования

Hash в Redis работает так же, как HashMap в Java. Значение содержит список различных свойств, каждое из которых имеет количество элементов, равное единице. Затем вы можете выполнять операции с этими ключами в хэше.

В хранилище документов вы вместо этого создаете элементы внутри документа, например:

{
  "field1": "some value",
  "field2": "some other value",
  "field3": 45
}

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

Выборка и обновление агрегатов — это простой случай или сохранение или получение документа в хранилище документов. Используя патч, вы также можете изменить только часть документа.

Геопространственные полевые операции

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

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

У MarkLogic есть много, много, много дополнительных геопространственных функций, включая поиск точек в документе (документы могут содержать много точек), которые находятся в ограничительной рамке, радиусе точки (окружности) или многоугольнике. Вы даже можете вернуть результаты поиска, упорядоченные по обратному расстоянию от центра круга или многоугольника! (Как и в типичном приложении поиска отелей).

Опять же, вы также можете проверить документы, в которых существуют два поля (долгота и широта вашего географического значения) — так что вы также можете найти только документы с геоданными в них.

У MarkLogic слишком много геофункциональности, чтобы документировать здесь. Я бы посоветовал вам проверить это, потому что это круто.

Опубликовать / Подписаться

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

Этими действиями оповещения может быть код XQuery или JavaScript, который делает что угодно. Они могут отправить сообщение на почтовый сервер или веб-сервис. Я лично использовал Node.js для создания сервера W3C WebSockets, который поддерживает соединение с клиентом открытым. Сервер Node.js также имеет конечную точку веб-службы. MarkLogic запускает сообщение для этой конечной точки при срабатывании предупреждения, и Node.js передает его клиенту веб-приложения с помощью WebSockets.

Не самая простая настройка по сравнению с Redis — потому что MarkLogic не поддерживает сохранение соединения открытым за пределами границы транзакции по причинам ACID, поэтому не поддерживает стандарт WebSockets — но это возможно сделать всего несколькими строками кода в Node.js.

В итоге

Можете ли вы успешно использовать хранилище документов в качестве хранилища KV? Да. И для всех операций тоже? Да. Да, это будет медленнее, но скорость относительно.

Например, мой ноутбук с VMWare с CentOS, в котором MarkLogic настроен только с одним лесом (shard), может выполнять 3000-4000 операций записи или обновления в секунду. Обычно для 8-ядерного компьютера у вас будет около 6 осколков. Таким образом, вы можете легко получить доступ к десяткам тысяч обновлений на одной машине, не говоря уже о минимальном кластере из 3 узлов. (минимум для HA).

Если вам нужна экстремальная скорость, используйте настоящий магазин KV. Redis (и Redis Cloud) — отличные варианты с открытым исходным кодом. Aerospike — мой любимый коммерческий вариант (он отлично справляется с управлением флеш-хранилищем), но если вам не нужно более 100 000 обновлений в секунду, вы можете использовать хранилище документов, например MarkLogic. (Возможно, они будут работать еще быстрее, если вы отключите индексацию, которая вам не нужна).

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

Есть MarkLogic? Нужен магазин КВ? Вам не нужно более 100 000 обновлений в секунду на сервер? Тогда не стесняйтесь использовать MarkLogic.

Статья первоначально размещена в моем блоге по адресу:  https://adamfowlerml.wordpress.com/2015/08/14/hybrid-nosql-key-value-use-cases/