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

Couchbase Server
База данных Couchbase Server едва ли широко известна среди веб-комьюнити, однако это не мешает многим компаниям (как Cisco или Zynga) строить крупномасштабные приложения на её основе. Проект возник около 4 лет назад, успев сменить за это время несколько названий (NorthScale, Membase) и поглотить CouchOne — компанию, которая занималась разработкой и поддержкой базы данных CouchDB.

На сегодняшний день Couchbase Server — это гибридное решение, сочетающее в себе возможности key-value (за счёт memcached-совместимого протокола) и документ-ориентированных баз данных (за счёт хранения данных в JSON-формате и наличия вторичных индексов).

Хранение данных
Условным эквивалентом таблиц и коллекций в Couchbase Server являются бакеты (bucket). Бакеты не связаны с какой-либо строгой схемой и представляют собой произвольный набор JSON-документов. Структурно каждый бакет делится на 1024 вибакекта (vbucket), благодаря чему реализуется абсолютно прозрачный для пользователя шардинг. При этом каждый из узлов кластера содержит в себе равное количество вибакетов. Таким образом для масштабирования базы достаточно добавить новые сервера через административную консоль, распределение данных между узлами реализуется автоматически.

Не требуются усилия и для настройки репликации данных между узлами кластера. При создании бакета достаточно указать количество требуемых копий, процесс репликации же реализуется незаметно для пользователя. Couchbase Server предоставляет доступ к реплицированным данным, однако эта возможность реализована не во всех клиентских библиотеках. Как правило, реплицированные данные используются лишь в чрезвычайных ситуациях.

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

Для сжатия хранимых на диске данных используется специальный демон, который вызывается по мере достижения заданного порога фрагментации данных. С данной операцией связаны серьезные издержки из-за дискового чтения и записи, что негативно сказывается на общесистемной производительности.

Кэширование данных
Наиболее часто используемые данные Couchbase Server помещает в память, по умолчанию для этого резервируется 60% доступной памяти (максимум 80%). При этом с каждым документом ассоциируется специальный NRU (not recently used) бит, который является одним из критерием для хранения данных в памяти.

Следует отметить, что в памяти хранятся не только активные данные, но и реплицированные копии. Крайне важно учесть это при планировании системых ресурсов. Издержки, связанные с метаданными документов, минимальны начиная с версии 2.0.

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

Вторичный индексы
Начиная с версии 2.0 появилась возможность построения вторичных индексов на основе специальных Map-Reduce функций, написанных на языке JavaScript. При использовании данной функциональности важно учесть несколько аспектов:

  • В зависимости от количества данных и сложности написанных функций на первоначальное индексирование данных может уходить от нескольких минут до нескольких часов. После построения первичного индекса новые данные индексируют инкрементально. При это можно получить доступ как к актуальной, так и необновленной версии индекса. Разумеется время отклика в последнем случае будет меньше.
  • Couchbase Server хранит индексы на диске и в вопросах кэширования полностью полагается на операционную систему. По этой причине крайне важно использовании наличие отдельных дисков для данных и индексов. Во втором случае SSD диски крайне рекомендуются. Кроме того в зависимости от размера индекса может иметь смысл уменьшение квоты для кэша основных данных.
  • Большая часть функционала для индексирование данных написана на языке Erlang, что приводит к крайнее высокой утилизации процессорных ресурсов. Для использования данной фичи необходимы быстрые многоядерные серверы.

XDCR
Новой фичей Couchbase Server 2.0 стала поддержка технологии XDCR (cross datacenter replication), что позволяют хранить данные не только в локальной сети, но и создать распределённое хранилище данных. Реализована поддержка как однонаправленной (“master” — “slave”), так и двунаправленной (“master” — “master”) репликации. С помощью XDCR, к примеру, можно реализовывать сценарий локализации данных в требуемом регионе, а также создавать резервные копии данных.

Скорость репликации во многом определяется сетевыми задержками между дата-центрами, а также уровнем нагрузки на мастер-кластере. Но даже при оптимистичном стечении обстоятельства стоит рассчитывать на задержки в репликации порядка нескольких секунд.

Клиентские приложения
Важным преимуществом Couchbase Server является новое поколение клиентских библиотек, которые позволяют прозрачно работать с шардами данных. Соответственно не возникает необходимости использовать роутеры вроде mongos для обращения к кластеру серверов. Кроме минимизации RTT между клиентскими приложениями и серверами базы данных, это существенно упрощает процесс разработки.

На сегодняшний день существует более десятка драйверов для различных языков программирования, включая даже сравнительно редкие для Go и Clojure. С полном списком можно ознакомить на странице. http://www.couchbase.com/develop

Для достижения наиболее высокой производительности базы данных крайнее важно обеспечить минимальные (менее 1 мс) задержки между нодами кластера и клиентскими приложениями. Кроме того в случае приложений с высокой нагрузкой пропускная способности сети нередко может стать узким местом.

Резюме
Масштабируемость и отказаустойчивость в случае Couchbase Server не являются пустыми словами. Проекту действительно удалось создать базу данных, с помощью которой за счёт предельно простого процесса шардинга и репликации данных можно строить надёжные приложения с непредсказуемым ростом нагрузки.

Метки: