Что такое nosql базы данных
Что такое nosql базы данных
По Вашему запросу ничего не найдено.
Рекомендуем сделать следующее:
Темы на странице NoSQL
Что такое NoSQL?
Термин NoSQL обозначает нереляционные типы баз данных, которые хранят данные в формате, отличном от реляционных таблиц. Однако базы данных NoSQL можно запрашивать с помощью API-интерфейсов идиоматических языков, языков декларативных структурированных запросов и языков примеров запросов — вот почему их также называют «не только SQL» базами данных.
Для чего используется база данных NoSQL?
Базы данных NoSQL широко используются в веб-приложениях реального времени и больших данных, поскольку их основные преимущества — это высокая масштабируемость и высокая доступность.
Базы данных NoSQL предпочитают использовать разработчики, так как они естественным образом вписываются в парадигму гибкой разработки благодаря своей быстрой адаптации к меняющимся требованиям. Хранить данные в базах данных NoSQL легче и понятнее аналогично тому, как данные используются приложениями, а хранить или извлекать данные с использованием API-интерфейсов в стиле NoSQL можно без большого числа преобразований. Более того, базы данных NoSQL могут в полной мере использовать преимущества облака, обеспечивая нулевое время простоя.
Сравнение SQL и NoSQL
Базы данных SQL реляционные, а NoSQL нереляционные. Система управления реляционными базами данных (РСУБД) является основой для языка структурированных запросов (SQL), который позволяет пользователям получать доступ и управлять данными в высокоструктурированных таблицах. Это основная модель для таких систем баз данных, как MS SQL Server, IBM DB2, Oracle и MySQL. Но с базами данных NoSQL синтаксис доступа к данным может быть разным в разных базах данных.
Сравнение реляционной базы данных с базой данной NoSQL
Чтобы понять, что представляют собой базы данных NoSQL, важно знать, в чем отличие между РСУБД и нереляционными типами баз данных.
Данные в РСУБД хранятся в объектах базы данных, которые называются таблицами. Таблица — это набор связанных записей данных, состоящий из столбцов и строк. Для этих баз данных должна быть предварительно определена схема, то есть все столбцы и связанные с ними типы данных должны быть известны заранее, чтобы приложения могли записывать данные в базу данных. Они также хранят информацию, связывающую несколько таблиц с помощью ключей, тем самым создавая связь между несколькими таблицами. В простейшем случае ключ используется для извлечения определенной строки, чтобы ее можно было проверить или изменить.
И наоборот, в базах данных NoSQL данные могут храниться без предварительного определения схемы — это означает, что есть возможность быстро перемещаться и выполнять итерации, определяя модель данных по ходу дела. Такой подход может быть полезен для удовлетворения конкретных бизнес-требований, например на основе графиков, столбцов, документов, или для использования в качестве хранилища «ключ-значение».
До недавнего времени наиболее широко использовались реляционные базы данных. Такие модели по-прежнему широко распространены во многих компаниях, однако из-за разнообразия, скорости и объема данных, к которым сегодня осуществляется доступ, иногда требуется совсем другая база данных, дополняющая реляционную. Поэтому в некоторых областях стали активно использоваться базы данных NoSQL, которые также называются нереляционными базами данных. Благодаря своей способности к быстрому горизонтальному масштабированию нереляционные базы данных могут обрабатывать много трафика, что также делает их легко адаптируемыми.
Когда лучше отдать предпочтение базе данных NoSQL?
В условиях, когда предприятиям необходимо быстро внедрять инновации, возможность оставаться гибкими и продолжать работать в любом масштабе становится ключевым преимуществом. Базы данных NoSQL предлагают гибкие схемы, а также поддерживают различные модели данных, которые идеально подходят для создания приложений, требующих больших объемов данных и малой задержки или времени отклика, например веб-приложений для онлайн-игр и электронной коммерции.
Когда не рекомендуется использовать базу данных NoSQL?
Базы данных NoSQL обычно используют ненормализованные данные, поддерживая типы приложений, которые используют меньше таблиц (или контейнеров) и чьи отношения данных моделируются не с помощью эталонов, а скорее как встроенные записи (или документы). Большинство классических серверных бизнес-приложений в области финансов, бухгалтерского учета и планирования ресурсов предприятия полагаются на высокоструктурированные данные для предотвращения аномалий данных, а также их дублирования. Обычно такие типы приложений не подходят для базы данных NoSQL.
Еще одно отличие баз данных NoSQL — сложность запросов. Базы данных NoSQL отлично работают с запросами к одной таблице. Однако в случае увеличения сложности запросов лучше воспользоваться реляционными базами данных. Базы данных NoSQL обычно не поддерживают сложные объединения, подзапросы и вложенные запросы в предложении WHERE.
В некоторых случаях, однако, нет необходимости выбирать между реляционными и нереляционными базами данных. В большинстве случаев компаниям предлагаются базы данных с конвергентной моделью, когда можно использовать комбинацию реляционной и нереляционной моделей данных. Такой гибридный подход обеспечивает повышенную гибкость при обработке различных типов данных, а также согласованность чтения и записи без снижения производительности.
В чем преимущества NoSQL перед другими базами данных?
Одним из основных отличий между базами данных NoSQL и другими типами баз данных является то, что в базах данных NoSQL обычно используется неструктурированное хранилище. Базы данных NoSQL разрабатывались в течение последних двух десятилетий и предназначены для быстрых, простых запросов, больших объемов данных и частой смены приложений. Кроме того, эти базы данных также значительно упрощают программирование для разработчиков.
Еще одной важной особенностью баз данных NoSQL является то, что в них для горизонтального масштабирования применяется сегментирование, а это значит, что для обработки данных с нескольких серверов можно добавлять больше компьютеров. Вертикальное масштабирование, которое встречается в других базах данных SQL, требует увеличения мощности и памяти существующей машины, а это может привести к дестабилизации, поскольку требуется все больший и больший объем хранилища.
Горизонтальное масштабирование в базах данных NoSQL работает таким образом, что базы данных могут более эффективно обрабатывать чрезвычайно большие объемы данных, даже по мере роста объемов. Представьте себе, что вертикальное масштабирование — это добавление еще одного этажа в Ваш дом, а горизонтальное — строительство еще одного дома рядом с Вашим.
Преимущества базы данных NoSQL
Беспрецедентная скорость и масштаб цифрового взаимодействия и потребления данных, наблюдавшиеся за последние два десятилетия, потребовали от компаний внедрить более современный и гибкий подход к тому, как они хранят данные и как получают к ним доступ. Поскольку пользователям по всему миру требуется непрерывный поток контента и функций, неудивительно, что базам данных пришлось быстро адаптироваться. С учетом этого вот некоторые из основных причин, по которым разработчики выбирают NoSQL (нереляционные базы данных).
Типы баз данных NoSQL
Четыре основных типа баз данных NoSQL:
Опробуйте Oracle NoSQL Database
Oracle NoSQL Database Cloud Service упрощает разработчикам создание приложений с использованием моделей баз данных на основе документов, столбцов и ключей-значений, которые обеспечивают предсказуемое время отклика в миллисекундах с репликацией данных для обеспечения высокой доступности. Этот сервис предоставляет транзакции ACID, возможность масштабирования без использования серверов, комплексную безопасность и низккую цену и оплату по мере использования.
Oracle NoSQL Database Cloud теперь является частью программы Oracle Cloud Free Tier, которая включает в себя бесплатную пробную версию с ограниченным сроком действия, позволяющую изучить широкий спектр облачных сервисов, а также набор всегда бесплатных сервисов с неограниченным сроком действия.
NoSQL базы данных: понимаем суть
В последнее время термин “NoSQL” стал очень модным и популярным, активно развиваются и продвигаются всевозможные программные решения под этой вывеской. Синонимом NoSQL стали огромные объемы данных, линейная масштабируемость, кластеры, отказоустойчивость, нереляционность. Однако, мало у кого есть четкое понимание, что же такое NoSQL хранилища, как появился этот термин и какими общими характеристиками они обладают. Попробуем устранить этот пробел.
История.
Самое интересное в термине, что при том, что впервые он стал использоваться в конце 90-х, реальный смысл в том виде, как он используется сейчас, приобрел только в середине 2009. Изначально так называлась опенсорсная база данных, созданная Карло Строззи, которая хранила все данные как ASCII файлы и использовала шелловские скрипты вместо SQL для доступа к данным. С “NoSQL” в его нынешнем виде она ничего общего не имела.
В июне 2009 в Сан-Франциско Йоханом Оскарссоном была организована встреча, на которой планировалось обсудить новые веяния на ИТ рынке хранения и обработки данных. Главным стимулом для встречи стали новые опенсорсные продукты наподобие BigTable и Dynamo. Для яркой вывески для встречи требовалось найти емкий и лаконичный термин, который отлично укладывался бы в Твиттеровский хэштег. Один из таких терминов предложил Эрик Эванс из RackSpace — «NoSQL». Термин планировался лишь на одну встречу и не имел под собой глубокой смысловой нагрузки, но так получилось, что он распространился по мировой сети наподобие вирусной рекламы и стал де-факто названием целого направления в ИТ-индустрии. На конференции, к слову, выступали Voldemort (клон Amazon Dynamo), Cassandra, Hbase (аналоги Google BigTable), Hypertable, CouchDB, MongoDB.
Стоит еще раз подчеркнуть, что термин “NoSQL” имеет абсолютно стихийное происхождение и не имеет общепризнанного определения или научного учреждения за спиной. Это название скорее характеризует вектор развития ИТ в сторону от реляционных баз данных. Расшифровывается как Not Only SQL, хотя есть сторонники и прямого определения No SQL. Сгруппировать и систематизировать знания о NoSQL мире попытались сделать Прамод Садаладж и Мартин Фаулер в своей недавней книге “NoSQL Distilled”.
Характеристики NoSQL баз данных
Общих характеристик для всех NoSQL немного, так как под лэйблом NoSQL сейчас скрывается множество разнородных систем (самый полный, пожалуй, список можно найти на сайте http://nosql-database.org/). Многие характеристики свойственны только определенным NoSQL базам, это я обязательно упомяну при перечислении.
1. Не используется SQL
Имеется в виду ANSI SQL DML, так как многие базы пытаются использовать query languages похожие на общеизвестный любимый синтаксис, но полностью его реализовать не удалось никому и вряд ли удастся. Хотя по слухам есть стартапы, которые пытаются реализовать SQL, например, в хадупе (http://www.drawntoscalehq.com/ и http://www.hadapt.com/ )
2. Неструктурированные (schemaless)
Смысл таков, что в NoSQL базах в отличие от реляционных структура данных не регламентирована (или слабо типизированна, если проводить аналогии с языками прогаммирования) — в отдельной строке или документе можно добавить произвольное поле без предварительного декларативного изменения структуры всей таблицы. Таким образом, если появляется необходимость поменять модель данных, то единственное достаточное действие — отразить изменение в коде приложения.
Например, при переименовании поля в MongoDB:
Если мы меняем логику приложения, значит мы ожидаем новое поле также и при чтении. Но в силу отсутствия схемы данных поле totalSum отсутствует у других уже существующих объектов Order. В этой ситуации есть два варианта дальнейших действий. Первый — обойти все документы и обновить это поле во всех существующих документах. В силу объемов данных этот процесс происходит без каких-либо блокировок (сравним с командой alter table rename column), поэтому во время обновления уже существующие данные могут считываться другими процессами. Поэтому второй вариант — проверка в коде приложения — неизбежен:
А уже при повторной записи мы запишем это поле в базу в новом формате.
Приятное следствие отсутствия схемы — эффективность работы с разреженными (sparse) данными. Если в одном документе есть поле date_published, а во втором — нет, значит никакого пустого поля date_published для второго создано не будет. Это, в принципе, логично, но менее очевидный пример — column-family NoSQL базы данных, в которых используются знакомые понятия таблиц/колонок. Однако в силу отсутствия схемы, колонки не объявляются декларативно и могут меняться/добавляться во время пользовательской сессии работы с базой. Это позволяет в частности использовать динамические колонки для реализации списков.
У неструктурированной схемы есть свои недостатки — помимо упомянутых выше накладных расходов в коде приложения при смене модели данных — отсутствие всевозможных ограничений со стороны базы (not null, unique, check constraint и т.д.), плюс возникают дополнительные сложности в понимании и контроле структуры данных при параллельной работе с базой разных проектов (отсутствуют какие-либо словари на стороне базы). Впрочем, в условиях быстро меняющегося современного мира такая гибкость является все-таки преимуществом. В качестве примера можно привести Твиттер, который лет пять назад вместе с твиттом хранил лишь немного дополнительной информации (время, Twitter handle и еще несколько байтов метаинформации), однако сейчас в дополнение к самому сообщению в базе сохраняется еще несколько килобайт метаданных.
(Здесь и далее речь идет в-основном о key-value, document и column-family базах данных, graph базы данных могут не обладать этими свойствами).
3. Представление данных в виде агрегатов (aggregates).
В отличие от реляционной модели, которая сохраняет логическую бизнес-сущность приложения в различные физические таблицы в целях нормализации, NoSQL хранилища оперируют с этими сущностями как с целостными объектами:
В этом примере продемонстрированы агрегаты для стандартной концептуальной реляционной модели e-commerce “заказ — позиции заказа — платежи — продукт”. В обоих случаях заказ объединяется с позициями в один логический объект, при этом каждая позиция хранит в себе ссылку на продукт и некоторые его атрибуты, например, название (такая денормализация необходима, чтобы не запрашивать объект продукта при извлечении заказа — главное правило распределенных систем — минимум “джоинов” между объектами). В одном агрегате платежи объединены с заказом и являются составной частью объекта, в другом — вынесены в отдельный объект. Этим демонстрируется главное правило проектирования структуры данных в NoSQL базах — она должна подчиняться требованиям приложения и быть максимально оптимизированной под наиболее частые запросы. Если платежи регулярно извлекаются вместе с заказом — имеет смысл их включать в общий объект, если же многие запросы работают только с платежами — значит, лучше их вынести в отдельную сущность.
Многие возразят, заметив, что работа с большими, часто денормализованными, объектами чревата многочисленными проблемами при попытках произвольных запросов к данным, когда запросы не укладываются в структуру агрегатов. Что, если мы используем заказы вместе с позициями и платежами по заказу (так работает приложение), но бизнес просит нас посчитать, сколько единиц определенного продукта было проданно в прошлом месяце? В этом случае вместо сканирования таблицы OrderItem (в случае реляционной модели) нам придется извлекать заказы целиком в NoSQL хранилище, хотя большая часть этой информации нам будет не нужна. К сожалению, это компромисс, на который приходится идти в распределенной системе: мы не можем проводить нормализацию данных как в обычной односерверной системе, так как это создаст необходимость объединения данных с разных узлов и может привести к значительному замедлению работы базы
Плюсы и минусы обоих подходов я попытался сгруппировать в табличке:
4. Слабые ACID свойства.
Долгое время консистентность (consistency) данных была “священной коровой” для архитекторов и разработчиков. Все реляционные базы обеспечивали тот или иной уровень изоляции — либо за счет блокировок при изменении и блокирующего чтения, либо за счет undo-логов. С приходом огромных массивов информации и распределенных систем стало ясно, что обеспечить для них транзакционность набора операций с одной стороны и получить высокую доступность и быстрое время отклика с другой — невозможно. Более того, даже обновление одной записи не гарантирует, что любой другой пользователь моментально увидит изменения в системе, ведь изменение может произойти, например, в мастер-ноде, а реплика асинхронно скопируется на слейв-ноду, с которой и работает другой пользователь. В таком случае он увидит результат через какой-то промежуток времени. Это называется eventual consistency и это то, на что идут сейчас все крупнейшие интернет-компании мира, включая Facebook и Amazon. Последние с гордостью заявляют, что максимальный интервал, в течение которого пользователь может видеть неконсистентные данные составляют не более секунды. Пример такой ситуации показан на рисунке:
Логичный вопрос, который появляется в такой ситуации — а что делать системам, которые классически предъявляют высокие требования к атомарности-консистентности операций и в то же время нуждаются в быстрых распределенных кластерах — финансовым, интернет-магазинам и т.д? Практика показывает, что эти требования уже давно неактуальны: вот что сказал один разработчик финансовой банковской системы: “Если бы мы действительно ждали завершения каждой транзакции в мировой сети ATM (банкоматов), транзакции занимали бы столько времени, что клиенты убегали бы прочь в ярости. Что происходит, если ты и твой партнер снимаете деньги одновременно и превышаете лимит? — Вы оба получите деньги, а мы поправим это позже.” Другой пример — бронирование гостиниц, показанный на картинке. Онлайн-магазины, чья политика работы с данными предполагает eventual consistency, обязаны предусмотреть меры на случай таких ситуаций (автоматическое решение конфликтов, откат операции, обновление с другими данными). На практике гостиницы всегда стараются держать “пул” свободных номеров на непредвиденный случай и это может стать решением спорной ситуации.
На самом деле слабые ACID свойства не означают, что их нет вообще. В большинстве случаев приложение, работающее с реляционной базой данных, использует транзакцию для изменения логически связанных объектов (заказ — позиции заказа), что необходимо, так как это разные таблицы. При правильном проектировании модели данных в NoSQL базе (агрегат представляет из себя заказ вместе с перечнем пунктов заказа) можно добиться такого же самого уровня изоляции при изменении одной записи, что и в реляционной базе данных.
5. Распределенные системы, без совместно используемых ресурсов (share nothing).
Опять же, это не касается граф баз данных, чья структура по определению плохо разносится по удаленным нодам.
Это, возможно, главный лейтмотив развития NoSQL баз. С лавинообразным ростом информации в мире и необходимости ее обрабатывать за разумное время встала проблема вертикальной масштабируемости — рост скорости процессора остановился на 3.5 Ггц, скорость чтения с диска также растет тихими темпами, плюс цена мощного сервера всегда больше суммарной цены нескольких простых серверов. В этой ситуации обычные реляционные базы, даже кластеризованные на массиве дисков, не способны решить проблему скорости, масштабируемости и пропускной способности. Единственный выход из ситуации — горизонтальное масштабирование, когда несколько независимых серверов соединяются быстрой сетью и каждый владеет/обрабатывает только часть данных и/или только часть запросов на чтение-обновление. В такой архитектуре для повышения мощности хранилища (емкости, времени отклика, пропускной способности) необходимо лишь добавить новый сервер в кластер — и все. Процедурами шардинга, репликации, обеспечением отказоустойчивости (результат будет получен даже если одна или несколько серверов перестали отвечать), перераспределения данных в случае добавления ноды занимается сама NoSQL база. Вкратце представлю основные свойства распределенных NoSQL баз:
Репликация — копирование данных на другие узлы при обновлении. Позволяет как добиться большей масштабируемости, так и повысить доступность и сохранность данных. Принято подразделять на два вида:
master-slave:
Первый тип предполагает хорошую масштабируемость на чтение (может происходить с любого узла), но немасштабируемую запись (только в мастер узел). Также есть тонкости с обеспечением постоянной доступности (в случае падения мастера либо вручную, либо автоматически на его место назначается один из оставшихся узлов). Для второго типа репликации предполагается, что все узлы равны и могут обслуживать как запросы на чтение, так и на запись.
Шардинг — разделение данных по узлам:
Шардинг часто использовался как “костыль” к реляционным базам данных в целях увеличения скорости и пропускной способности: пользовательское приложение партицировало данные по нескольким независимым базам данных и при запросе соответствующих данных пользователем обращалось к конкретной базе. В NoSQL базах данных шардинг, как и репликация, производятся автоматически самой базой и пользовательское приложение обособленно от этих сложных механизмов.
6. NoSQL базы в-основном оупенсорсные и созданы в 21 столетии.
Именно по второму признаку Садаладж и Фаулер не классифицировали объектные базы данных как NoSQL (хотя http://nosql-database.org/ включает их в общий список), так как они были созданы еще в 90-х и так и не снискали большой популярности.
Дополнительно я хотел остановиться на классификации NoSQL баз данных, но, пожалуй, сделаю это в следующей статье, если это будет интересно хаброюзерам.
NoSQL – коротко о главном
Сергей Туленцев (TextMaster)
Меня зовут Сергей Туленцев, я уже несколько лет интересуюсь NoSQL базами данных и сегодня попытаюсь поделиться с вами знаниями и опытом.
Кому будет полезен этот доклад? Это обзорный доклад с претензией на структурированность. Если вы что-то где-то когда-то слышали про NoSQL, то через 40 минут вы будете знать гораздо больше, вы будете легче ориентироваться в терминах и более уверенно выбирать базы данных для своего проекта.
Поговорим также про типичные примеры применения и как не надо применять NoSQL базы данных.
Немного истории.
Впервые термин появляется в 1998 году — так чувак по имени Carlo Strozzi назвал свою реляционную базу данных. Она, однако, не предоставляла SQL-интерфейса для работы с собой, а вместо этого представляла из себя набор bash-скриптов, которые колбасили XML-файлы. Если верить википедии, то последний релиз этой базы данных вышел в 2010 году, и она как-то успешно работала. Я про нее узнал только в процессе подготовки к докладу, и, думаю, это хорошо, что я раньше про нее не узнал.
В 2009 году другие чуваки из Сан-Франциско организовывали конференцию для обсуждения новых распределенных баз данных, и им нужен был хэш-тег для твиттера, емкий короткий хэш-тег. Кто-то придумал хэш-тег NoSQL, чтобы подчеркнуть, что есть базы данных, в которых есть SQL, есть ACID и всякие крутые штуки, но мы будем говорить про другие базы данных, у которых ничего этого нет. Народу хэш-тег понравился, он вышел из-под контроля и до сих пор гуляет по интернету.
Термин NoSQL. Есть две трактовки: одна старая, другая новая. Оригинальная — это NoSQL, т.е., вообще, никакого SQL-а нет, а есть какой-то другой механизм, для работы с этой базой данных. И более новая трактовка — это «Not only SQL» — это не только SQL, т.е. может быть SQL, но есть что-то помимо.
Есть такой сайт http://nosql-database.org — это список разных баз данных NoSQL. Содержит описание, тип, ссылку на официальный проект, какие-то краткие важные вещи, которые стоит знать. Можете на досуге залезть почитать, но я про самые популярные сейчас расскажу.
Наиболее популярная классификация баз данных — это по типам данных.
Важный тип — это key/value store, или хранилище пар «ключ-значение».
Это самый густонаселенный тип, и он одновременно самый простой — обладает самым примитивным интерфейсом из всех. И, по идее, минимальный интерфейс для такой базы данных состоит всего из 3-х операций — get, set и delete. Наверное, есть какие-то базы данных, которые удовлетворяют этому интерфейсу, но обычно современные распространенные базы данных предоставляют больше плюшек, например, можно получить много ключей за раз, установить время жизни ключа, ну, соответственно, получить время жизни ключа, какие-нибудь сервисные команды для проверки статуса сервера…
Яркий представитель этого класса — это Memcashed. И сюда можно отнести с натяжкой Redis. Почему с натяжкой? Потому что у него на самом деле есть своя отдельная категория, в которой есть он один, эта категория называется «серверы структур данных». Он в этой категории находится, потому что у него несколько типов ключей и очень богатый набор команд (150 или больше), с помощью которых можно творить невообразимые вещи, но если эту категорию не учитывать, то так его можно отнести сюда — в key/value. Есть ещё Riak.
Документ-ориентированная база данных.
Это сильно усложненный вариант предыдущей категории. Эта добавленная сложность — она дает ещё и бонусы: теперь значения — это не какой-то непрозрачный текстовый блоб, с которым ничего нельзя делать, кроме того, что целиком прочитать или удалить, а теперь можно работать более тонко со значением. Если нам нужна только часть документа, можем ее прочитать или обновить только часть.
Обычно в базах данных такого типа присутствует богатая структура документа, т.е. дерево. Если грубо представить произвольный JSON, то любой JSON, который можно вообразить себе, можно записать в такую базу данных. И обычно реклама, пресс-релизы говорят — берете любой JSON, кладете в нашу базу данных и потом можно их анализировать. Обычно проблем не возникает только с первым пунктом, собственно с помещением JSON’а в базу данных, а дальше уже начинаются нюансы.
Типичные представители — MongoDB, CouchDB, ElasticSearch и др.
Колоночные базы данных.
Их сильная сторона в способности хранить большое количество данных с большим количеством атрибутов. Если у вас есть пара-тройка миллиардов записей, у каждой из которых по 300 атрибутов — это вам в колоночные базы данных.
Они немного по-другому хранят данные, нежели, например, реляционные базы данных — реляционки хранят по строкам, т.е. все атрибуты одной строки лежат рядом. Эти делают наоборот, они хранят отдельно колонки.
Есть файл — в нем хранятся все поля данной колонки из всех 3-х млрд. записей, хранятся все рядом. Соответственно, другая колонка хранится в другом файле. За счет этого они могут применять улучшенное сжатие за счет использования информации о типе данных колонки. Также это может ускорять запросы, если, нам, например, нужны 3 колонки из 300, то нам не обязательно грузить остальные 297.
Представители — это HBase, Cassandra, Vertica. У Vertica, кстати, SQL интерфейс, но это все равно колоночная БД.
Графовые базы данных.
Предназначены для обработки графов. На всякий случай напомню, что граф — это такая штука из дискретной математики — набор вершин, соединенных ребрами. Если посмотреть на любую интересную сложную задачу, то велик шанс, что мы там найдем граф. Например, социальные сети — это один большой граф. Дорожная сеть и прокладка маршрутов, рекомендация товаров.
Сила этих баз данных в том, что за счет своей специализации они могут эффективно выполнять всякие операции над графами, но также в силу той же специализации они не сильно распространены.
Все-таки не в каждой задаче есть граф, а если он там есть, то наверняка не очень большой и по ресурсам чаще всего бывает дешевле закодить на коленке какую-то обработку графов в приложении, нежели тащить в проект целую новую базу данных, за которой надо следить. Да и новая база данных доставляет целый ворох проблем. В моей практике так и было.
Мультимодельные базы данных.
Это такие базы данных, в которые одновременно входит две или более категорий из предыдущих.
Хочешь — пиши документы, хочешь — графы. FoundationDB, например, у нее основной слой — key/value и поверх этого слоя как-то прилажен SQL-слой. Я скачал себе дистрибутив и подписался на рассылку, они мне слали e-mail’ы каждую неделю, но так и не удалось мне поставить и запустить, пощупать как оно работает. И теперь уже не удастся, потому что пару месяцев назад, в марте, этих ребят купила компания Apple и сразу удалила все ссылки на скачку дистрибутива с сайта и теперь, видимо, этот продукт не будет в открытом доступе. Наверное, она работала неплохо, раз их купили.
Есть ещё две, которые у нас есть возможность пощупать, пока их кто-нибудь тоже не купил.
Еще есть классификация по способу хранения данных.
Есть базы данных, которые вообще никак данные не хранят, у них все хранится в памяти. Соответственно, любая перезагрузка процесса влечет за собой потерю данных. Здесь выхода два: либо не хранить там важные данные, которые нельзя восстановить, либо агрессивно применять репликацию. Из неважных данных — это, например, кэш, если у нас кэш куда-то пропадает, то приложение у нас не упадет, оно будет тормозить, пока кэш обратно не поднимется, не разогреется, но ничего смертельного не случится.
Иногда этот режим применяют для ускорения производительности. Взять, например, Redis. Он может обрабатывать десятки, сотни тысяч операций в секунду. И некоторые люди, конечно же, этим пользуются и нагружают его на всю катушку, но если он работает в режиме сохранения данных, т.е. либо сбрасывает снепшоты, либо лог пишет, то никакой диск с этим не справится, и работа с диском будет тормозить работу сервера. Поэтому можно применить такой трюк — берем систему из трех Redis’oв, один мастер, два его слейва. На мастере мы отключаем всю персистентность, и он вообще не касается диска, и туда мы пишем, потому что это мастер. На первом слейве мы тоже отключаем персистентность, и с него читаем. И на последнем слейве — его никто не трогает, не читает, и на нем мы включаем персистентность. И он, согласно настройкам, сохраняет данные на диск. В случае какой-то катастрофы, на нем будет копия данных, из которой можно восстановиться.
У Redis’a есть две модели, по которым он может сохранять данные на диск. Во-первых, он может сохранять снепшоты — это такой слепок базы данных на текущий момент. Чтобы этот слепок получился хороший, Redis форкается, создает копию своего процесса, чтобы слепок не был попорчен записями, которые происходят с мастером. И этот форк уже сохраняет этот снепшот, потому что в него никто не пишет.
Этот способ очень хорош, кроме того, что он требует дополнительной памяти. В зависимости от активности, которая происходит на сервере, вам может понадобиться до двукратного запаса памяти. Если у вас база данных 2 Гб, то вам надо держать ещё 2 Гб свободных для сохранения снепшотов.
Ещё можно настроить, чтобы он писал данные в лог — это другая техника. Т.е., когда ему приходит команда на запись, он ее быстро пишет сразу в лог и продолжает работу, т.е. эти 2 режима — снепшот и лог — они независимы, но можно настроить либо один, либо другой, либо оба вместе. В общем, этот лог тут только дописывается — в этом его плюс, а данные, которые уже попали в лог, они не изменяются и не могут быть поломаны. Поэтому, что обычно люди этот лог кладут на отдельный диск с отдельной головкой, и на этом диске никто, кроме Redis’а, ничего не делает и не трогает головку диска. И эта головка всегда показывает на конец файла. И запись новых операций в конец файла гораздо быстрее, чем если бы это происходило на обычной системе, где происходит другая активность.
Другие базы данных, например, MongoDB, — у них другая модель, называется in-place updates. У них есть одна копия базы данных, файлов данных, и они прямо “на живую” их изменяют. Это не очень безопасная практика, и если во время изменения, например, отключилось питание, то у вас база данных скарапчена, и сами виноваты. Поэтому несколько версий назад они приделали журналирование — так они называют контрольный лог, и даже сделали его включенным по умолчанию. Поэтому теперь Mongo можно запускать без двух реплик, и будет шанс, что она не попортит ваши данные.
Говоря про NoSQL нельзя упомянуть про CAP-теорему, это как 2 сапога — пара.
Теорема была сформулирована в году 2001-м, и некоторые считают, что она утратила актуальность и вообще не стоит про нее говорить, но упомянуть стоит. Она звучит так: распределенная система не может одновременно обладать более чем двумя из следующих трех характеристик — это доступность (availability), согласованность (consistency) и устойчивость к разрывам сети (partition tolerance).
На самом деле, выбор у нас только из двух вариантов — либо доступность, либо согласованность, потому что partition tolerance у нас везде есть по умолчанию. Мне не известны системы, которые не могли бы пережить разрыв сети, которые при разрыве сети самоуничтожались бы.
Доступность — это если у нас есть распределенная система, и мы обращаемся на любой ее узел и гарантированно получаем ответ. Если мы запрашиваем какие-то данные, то можем получить устаревшие версии этих данных, но мы получим данные, а не ошибку, или мы могли бы не достучаться до этого сервера. Если мы получили данные, то система доступна.
В противоположность этому система может быть согласована. Что означает согласованность? Если мы на одном узле записали какие-то данные и спустя некоторое время на другом узле пытаемся прочитать эти данные, если система согласована, мы получим новую версию данных, которую мы записали в другом месте.
Соответственно, распределенные системы любят относить себя к одному из двух лагерей либо на AP, либо на CP.
На самом деле есть третий секретный класс — это просто P, но ни один производитель базы данных не любит признаваться, что его система такая, а не из этих двух. То есть, если она просто P — она не обладает ни доступностью, ни согласованностью.
Соответственно, если система называет себя CP (т.е. consistency и partition tolerance), то при разрыве (если у нас есть кластер, и он разнесен, например, по двум дата-центрам, и связь рвется между дата-центрами) как ведет себя консистентная система? Она, если мы обращаемся на узел, и узел видит, что он не может надежно обеспечить эту запись, что у него нет, например, связи с большинством узлов системы, то он просто откажет приложению в этой записи, и она не удастся. Когда потом связь восстановится, приложение может попробовать снова и у него может получится.
А если система называет себя AP, то она будет всеми силами стараться удовлетворить запросы приложения путем отдачи ему устаревших данных, она может принять себе запрос на запись и куда-то ее себе записать, чтобы потом выполнить на всем кластере. Здесь есть нюансы. Например, если у нас разделился кластер надвое, и мы пишем в обе части, то есть шанс, что мы получим конфликты, т.е. мы в одной части записали в один ключ одни данные, а в другом — другие, а когда связь восстанавливается, то возникает проблема — какая версия данных корректная?
Специально для AP систем придумали термин — Eventual consistency — в грубом переводе на русский это означает, если не было конфликтующих записей, то когда-нибудь попозже кластер придет в согласованное состояние, при этом не дается каких-то гарантий по конкретным промежуткам — когда-нибудь.
Но в реальной жизни не приходится рассчитывать на отсутствие конфликтов и надо заранее думать, как мы будем с ними бороться.
Самый простой вариант, если у нас есть 2 конфликтующие записи — это разрешить конфликт по времени, грубо говоря, последняя, сделанная позже всех запись выигрывает.
Ещё некоторые системы сваливают все это дело на приложения. Когда приложение пытается прочитать данные, и база данных видит, что есть конфликты, она возвращает приложению все конфликтующие версии, и приложение само, руководствуясь своей логикой, должно будет выбрать правильную версию и отдать ее базе данных.
Более умный подход — это использовать типы данных, при использовании которых возникновение конфликтов, если не невозможно, то очень сложно. Например, тип данных — множество. Если у нас есть разорванные кластеры, и мы в одной половине во множество добавляем член А, и в другой половине добавляем B и С. Когда связь восстанавливается, то смерживать эти записи очень легко, мы просто делаем объединение этих множеств, и у нас получается одно результирующее множество (A, B и С).
Ещё пример — счетчики. Мы можем независимо инкрементировать счетчики, и когда связь восстановится, то мы просто сложим их и получим результирующий счетчик. В базе данных Riak есть специальный термин — CRDT — расшифровывается как бесконфликтные реплицирующиеся типы данных. По аббревиатуре можете загуглить, если интересно.
Поговорим про использование NoSQL. Когда надо использовать?
Это одна из самых главных, если не самая главная причина использования такого типа баз данных, потому что за счет своей пониженной сложности они легче масштабируются. Если ранее основные тяготы по масштабированию ложились на приложение, например, у нас есть 20 мемкэшей, и приложение собирает их в один хэшринг, чтобы обеспечить безотказность и масштабируемость, то современные базы данных все делают за тебя, в некоторых не надо даже ничего настраивать. Просто запускаешь ноду, она сама находит кластер, вступает в него, скачивает часть данных и начинает отдавать часть данных. Таким образом мы достигаем желанной линейной масштабируемости — это тоже один из святых граалей мира NoSQL.
Линейная масштабируемость — это когда мы путем увеличения ресурсов кластера получаем пропорциональное увеличение характеристик кластера. Удвоили количество серверов — получили в два раза больше производительность. Если мы линейно масштабируемся — мы очень крутые.
Традиционно реляционные базы данных требуют некоторое количество обслуживания, как до начала, так и во время проекта. Т.е. до начала проекта нам желательно продумать схему базы данных, ее создать, запустить с ней базу данных, а потом, когда проект запущен и работает, могут прийти новые бизнес-требования, или мы обнаружим, что мы как-то ошибались, нам надо добавить колонку… Часто это блокирующая операция. Что это означает? Нам либо нужно класть приложение, т.е. выключать его на минутку, на несколько дней, зависит от сложности ситуации, либо вручную дирижировать процессом обновления схемы. Т.е. накатываем схему на слейв, апгрейдим его до мастера, переключаем на него всех остальных слейвов и на них по очереди тоже накатываем схему. А перед этим надо не забыть выкатить код, который умеет одновременно работать с новой и старой версией базы данных, чтобы ошибки из приложения не летели. Это все делается, но это морока. Зачем делать, когда можно не делать? Поэтому бессхемные базы данных, документ-ориентирование особо, они этим и привлекают, что можно просто начать использовать новую схему данных, и она просто появится в ваших файловых данных. Совсем безболезненно это пройдет в случае, если мы добавляем поля, грубо говоря. Если мы изменяем структуру старых полей, то частенько придется сделать миграцию данных, но все равно это сильно ускоряет и упрощает создание прототипа продукта. Можно за несколько часов на MongoDB накодить минимальный продукт, и когда получим первый раунд финансирования нормально на Postgres писать все это.
Мы разносим нашу базу данных по нескольким датацентрам: в Америке, в Европе, Японии, если вдруг в какой-то из них бьет молния, и он исчезает, то мы можем писать в другие датацентры, и доступная база данных нам это позволит.
Здесь нечего говорить, про мемкэш все знаем, применяем. Некоторые товарищи извращаются и ставят Mongo как кэш перед реляционкой, т.е. у нас в реляционной базе данных хранятся данные, все такие нормализованные, а тут приложение делает запрос с 20-тью join’ами, получает результат и кладет его в Mongo, и далее отдает из Mongo. Profit.
Например, у нас в приложении льется огромный поток просмотров страниц, и нам надо их быстро считать. Если этот потом мы будем лить в реляционные базы данных, то любая база данных не выдержит, поэтому имеет больше смысла направить этот поток в Redis. Он очень быстро умеет работать со счетчиками и будет быстро считать. И уже из Redis’а можно раз в секунду, в 10 или в минуту, в зависимости от вашей самоуверенности, можно скидывать данные для сохранности в основную базу данных.
Если у нас есть на сайте форма регистрации пользователя, и во время регистрации пользователя нам надо отправить приветственный e-mail. Совершенно необязательно делать это во время обработки формы. Пользователю незачем ждать, пока мы отправим ему e-mail. Поэтому, когда мы получаем форму, мы кладем задание на отправку e-mail’а в очередь и возвращаем форму пользователю. Он продолжает пользоваться сайтом, а у нас в фоновом режиме какой-нибудь worker достанет это задание из очереди и отравит e-mail.
Например, нам надо хранить фотки — это на самом деле очень сложная проблема, если у вас фоток очень много, а все социальные сети изобрели свой велосипед для хранения фоток. Но если мы ещё не facebook, а хранить файлы на локальной файловой системе мы не хотим или не можем, потому что их слишком много, то у нас есть несколько выходов. Например, можно воспользоваться сервисом по типу Amazon S3 и просто лить файлы туда. Или можно поднять локальный кластер с Riak’ом или Mongo и хранить файлы там.
Здесь надо смотреть на ограничение конкретных продуктов. Если я правильно помню, то у Riak’а рекомендации — не класть файлы больше 2-3-х Мб, у Mongo — жесткое ограничение в 16 Мб на документ, но у нее есть специальный механизм для хранения больших файлов, которые бьет файлы по 16 Мб и хранит эти части.
Если нам надо что-то быстро считать берем Redis, Riak или Casandra и считаем.
Если у нас есть лог просмотров страницы или действий пользователей, как нам узнать, сколько уникальных пользователей здесь участвует? Если эти данные лежат, например, в реляционной базе данных, мы делаем SELECT COUNT(DISTINCT) — и это сработает. Если это не в базе лежит, а просто лог веб-сервера, то мы можем либо какие-то скрипты натравить, либо положить в Hadoop и Hadoop’ом это посчитать.
У всех этих способов есть один недостаток — производительность просаживается пропорционально увеличению количества данных. Но не стоит отчаиваться на помощь нам придет математика. Есть алгоритм — называется HyperLogLog. Он позволяет радикально уменьшить время и память, требуемые на выполнение этой операции. По ссылке на слайде можете прочитать статью Salvatore (автора Redis’а), который рассказывает про этот алгоритм. Этот алгоритм предполагает, что нам не нужно знать с абсолютной точностью цифру, а мы можем допускать некоторую погрешность, и в этом алгоритме мы можем, используя всего 12 Кб памяти по умолчанию, оценивать кардинальность множеств с миллиардами членов с погрешностью 0,8%. Это константная память — она не будет больше, т.е. если у нас 2 млрд или 7 — она 12 Кб. Размер буфера влияет на точность, чем можно увеличить буфер и уменьшить погрешность. Детали по ссылке (на слайде).
Для документных баз данных. Можно взять статью с контентом, с флажками и с настройками и записать ее, и использовать.
В некоторых реляционных базах данных он встроен и базовые нужды он может удовлетворять, но если вам нужно что-то большее, то нужно брать Sphinx или ElasticSearch.
Как не надо использовать NoSQL базы данных?
Если мы делаем социальную сеть или блог с системой комментариев, или систему с параллельными проектами, у этих систем нет единого фокуса точки зрения на данные. Мы можем смотреть на данные с разных сторон, можем сказать: «дай мне все проекты этого пользователя» или «дай мне всех участников этого проекта, или кто и когда изменял эти страницы», т.е. запросы могут быть совершенно различны, и бизнес-требования могут совершенно внезапно измениться. Хорошо бы, чтобы база данных была достаточно универсальна, чтобы обеспечить эти запросы. Можно постараться и блог или аналог Hacker News написать на Redis’е, но, мне кажется, это очень хрупкая структура, и любое дуновение бизнес-требований порушит все это.
Она описывает идеальнейшее приложение для MongoDB — это база данных фильмов. Там есть сериалы, в сериалах — сезоны, в сезонах — эпизоды, в эпизодах — набор актеров, все это друг в друга вложено, хранится в одном документе, мгновенно достается — красота! И оно так было несколько месяцев, пока на одном из митингов заказчик не попросил её сделать возможность просмотра фильмографии актера, посмотрев все эпизоды, в которых он участвовал. Для реляционных баз данных — это тривиальная задача, но для структуры, которую они имели, это было невыполнимо, потому что актер — не самостоятельный объект, а он вложен в сериалы на 5 уровней вниз — достать его никакой возможности нет.
Можно переколбасить структуру данных и поднять актера на верхний уровень, а в объекте сезона хранить ссылки, но тогда мы теряем все прелести документной базы данных, потому что мы можем одним запросом поднять все данные, которые нам нужны. Теперь мы поднимаем ID’шники, и по этим ID’шникам надо дополнительно идти искать авторов. Этот один запрос им все сломал, всю радость.
Здесь у нас гипотетический пример — документ статьи или поста в бложек. У поста есть автор, у автора есть e-mail, у поста есть комментарии, у комментария есть контент и автор. Там ещё можно многое наворотить — есть лайкеры… наворотить можно многое — было бы желание.
Это все выглядит хорошо на бумаге, но это сломается в тот же момент, когда ваш бложек попадет на крупный СМИ, например, на Хабр (не знаю насколько он крупный СМИ) — ваш бложек сломается сразу же, когда вам под пост нафигачат 10 тыс. комментов за 5 минут.
У нас в приложении в TextMaster’е была похожая ситуация. У нас есть сущность проекта, у проекта — документ, у документа — атрибуты. Изначально у нас все это хранилось вложено друг в друга, т.е. документы были вложены в проект и все это хранилось. Главной сущностью был проект. Все было хорошо пару недель.
Через 2 недели после начала эксплуатации у нас все это сломалось, мы вылезли за пределы лимита документов, и у нас появились новые запросы, которые эта структура не удовлетворяла. Нам в срочном порядке нужно было менять структуру данных и поднимать документ, т.е. выдирать его из проекта, поднимать его на верхний уровень и ещё несколько структур нам пришлось выдрать. Т.е. усердствовать с Embedding’ом не надо.
Возьмем 1-ую строчку — это классический пример из туториалов по MongoDB — это теги к какому-нибудь посту. Эта структура, когда значением является массив, Mongo очень хорошо умеет с ним работать, мы можем эффективно искать все посты, например, «дай мне все посты с тегом «ruby»», с тегом ««ruby» и «nosql»» или ««ruby», у которого нет тега «nosql»» — все что хочешь можно делать. Но присутствует избыточность данных, у нас один и тот же текст повторяется много раз, но теги — это вещь, в которой это не страшно. Если мы вышли из мира реляционных баз данных и решили делать все по-старому, то мы сделаем как во 2-ой строчке, мы будем хранить ID’шники тегов, а сами теги будут объектами верхнего уровня, в своей коллекции.
Здесь нет избыточности данных, но вместе с ней мы выплеснули и ребенка, т.е. мы теперь не можем искать посты по тексту тегов за один присест. Нам нужно вначале отдельно найти ID’ишники тегов по тексту и только после этого мы можем искать посты, т.е. минимум два запроса.
Это из серии «давай возьмем этот JSON, засериализуем его в строку и положим в строку». Положили — ок. Теперь мы не можем с ним ничего делать, потому что это не прозрачный блоб, и мы можем только целиком его вычитать, целиком перезаписать или целиком удалить.
На Stack Overflow (есть такой сайт для программистов) не счесть вопросов типа «у меня есть массивы 5-ти уровней вложенности, как мне теперь делать запросы по ней?». Каждый день такие вопросы встречаются. И ладно только запросы, потому что следующий вопрос «А как мне теперь менять эту структуру?». Т.е. люди, не думая, нафигачили каких-то данных и теперь не знают, что с ними делать. То, что по бумагам MongoDB — это бессхемная база данных — не значит, что над схемой думать не надо. Чуть-чуть надо.
Очень полезно знать свою предметную область и пытаться предвидеть будущие запросы, которые могут возникнуть. В примере про сериалы, для заказчика — это было очевидно, что есть ценность в возможности видеть фильмографию актера. Если бы разработчики видели это тоже, то история сложилась бы по-другому. Полезно следить за новостями в мире баз данных. Технологии развиваются очень быстро, и буквально за несколько дней может возникнуть какая-нибудь штука, которая серьезно облегчит вам жизнь. В моем случае — это был тот алгоритм для подсчета уников. И не надо слишком доверять пресс-релизам и рекламе — везде все идеально, надо смотреть ещё на недостатки, здесь возможны варианты, кто-то ищет негативные отзывы по форумам, кто-то читает код, кто-то ждет 3-го service pack’a. Главное выбирать базу данных, исходя не только из достоинств, но и также из недостатков.
Контакты
Этот доклад — расшифровка одного из лучших выступлений на обучающей конференции разработчиков высоконагруженных систем HighLoad++ Junior.
Также некоторые из этих материалов используются нами в обучающем онлайн-курсе по разработке высоконагруженных систем HighLoad.Guide — это цепочка специально подобранных писем, статей, материалов, видео. Уже сейчас в нашем учебнике более 30 уникальных материалов. Подключайтесь!
Ну и главная новость — мы начали подготовку весеннего фестиваля «Российские интернет-технологии», в который входит восемь конференций, включая HighLoad++ Junior. Будем ли мы говорить про NoSQL в этом году? Наверняка!