Это частичный перевод статьи Netflix, касается только проблемных мест перехода c Oracle DB на Amazon SimpleDB и способов их решения компанией.

Где-то в конце 2008 года, у Netflix был всего один датацентр. И этот ДЦ поставил перед нами несколько вопросов. Как единственная точка отказа, к примеру, из-за проблем с электричеством, он мог привести к недовольству наших пользователей сервисом. К тому же, с одновременным ростом трафика потокового вещания и подписок на услуги, Netflix скоро бы переросла этот дата центр — мы видели неизбежную потребность в электроэнергии, лучшем охлаждении, нам требовалось больше места и больше оборудования.

Как вариант, можно было построить новые дата центры. Однако, кроме высоких затрат, это усилие привело бы к тому, что наши технические кадры не смогли бы заниматься новыми продуктами, так были бы заняты расширением ДЦ. К тому же, мы понимали, что управление несколькими дата центрами сложная задача. Строительство и поддержка нескольких дата центров казались нам опасным отвлечением от нашего основного бизнеса.

Вместо того, чтобы встать ��а этот путь, мы выбрали более радикальный. Мы перешли на решение IAAS (инфраструктура как сервис), предлагаемое в то время веб-сервисом Amazon. Со множеством уже работающих центров обработки данных, многократным уровнем избыточности различных сервисов (таких как, S3 и SimpleDB), AWS обещал лучшую доступность и маштабируемость за относительно короткое время.

Отдавая различные сетевые и фоновые задачи в аутсорсинг, Netflix сосредоточилась на своем основном бизнесе, поставке фильмов и сериалов.

В процессе перехода на инфраструктуру AWS мы сформулировали набор лучших практик, необходимых для работы с AP системами, такими как SimpleDB.

Оставив СУБД позади


Частичная или вообще отсутствующая поддержка SQL. В общем случае, SimpleDB поддерживает подмножестно SQL

  • Используйте GROUP BY и JOIN операции на уровне приложения.
  • Один из способов избежать необходимости использовать JOIN денормализировать несколько таблиц в один логический домен SimpleDB

Отсутствие связей между доменами

  • Реализовать связи на уровне приложения

Отсутствие транзакций

  • Используйте API SimpleDB: ConditionalPut и Conditional Delete

Нет тригеров

  • Возможно обойтись без них

Нет поддержки схем – к тому же, это не очевидно. Запрос с ошибочным названием атрибута не приводит к возникновению ошибки

  • Внедрение проверки схемы на уровне доступа к данным приложения.

Отсутствие поддержки последовательностей

Последовательности часто используются в качестве первичных ключей.

  • В этом случае необходимо использовать естественный уникальный ключ, например, в домене контактов с клиентами использовать мобильный телефон клиента в качестве ключа.
  • Если нет естественных ключей, необходимо использовать UUID.

Последовательности также часто используются для номеров заказов.

  • Используйте распределенный генератор последовательностей.

Нет операций для работы со временем

  • Можно обойтись без них

Нет поддержки ограничений, в частности, нет ограничений уникальности поля, нет контроля внешнего ключа, нет ограничений целостности.

  • Приложение может проверить ограничения в момент чтения данных и исправить проблему постфактум. Это называется восстановление при чтении (read-repair). Восстановление при чтении должно использовать ConditionalPut или ConditionalDelete API для того, чтобы изменения были атомарными.

Новые вызовы, возникшие в SimpleDB


Кроме того, были особенности, с которыми мы столкнулись, характерные именно для SimpleDB. Вот некоторые из них:

SimpleDB домены обеспечивают максимальную скорость записи, если разбить данные на несколько доменов.

  • Все данные Netflix со значительной нагрузкой по записи были распределены на несколько доменов.

Нет поддержки собственных типов данных. Все данные хранятся и обрабатываются как строки.

Все сравнения (т.е. WHERE условия) и сортировка происходит только со строками.

  • Хранить все даты в ISO 8601
  • Добавлять нули перед числами, которые используются при сортировке и/или WHERE сравнении.

Два раздельных вызова API для DeleteAtributes и PutAttributes.

Как выполнить атомарную операцию требующую как удаление одного атрибута, так и обновление другого атрибута в одной и той же строке?

  • Наиболее простым вариантом является использование псевдо нулей (например, слово NULL) вместо операции DeleteAttributes.
  • Это сводит на нет оптимизацию свободного пространства таблиц SimpleDB и приводит к раздуванию данных.

Использование чувствительных к регистру названий доменов и атрибутов

Во многих СУБД имена таблиц и столбцов нечувствительны к регистру, а в SimpleDB наоборот, в связи с чем, операции put, delete и select могут работать неправильно, даже не сообщив об ошибке. Задача программиста обнаружить все случаи несоответствия регистра имен.

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

Операции с опечатками в названиях атрибутов select, put или delete могут завершится без уведомления об ошибке.

В отличии от чуствительности к регистру, эта проблема возникает из-за отсутствия проверки схемы. Simple DB не только разреженная БД, но еще и без поддержки схем.

  • Внедрить в приложении единой точки доступа к данным слоя и реализовать там проверку.

Если забыть указать LIMIT в select может потребоваться несколько запросов, для того чтобы получить все данные.

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

  • Имя единую точку доступа к данным на уровне приложения, можно устанавливать LIMIT непосредственно в нем.
  • Максимальное значение может в любой момент быть изменено, если Amazon увеличит лимит.

Необходимо также иметь ввиду проблемы «целостности в конечном итоге» (eventual consistency).

Необходимо избегать анти-паттерна чтение непосредственно после записи.

  • Избегайте чтения непосредственно после записи.
  • Если это невозможно используйте ConsistentRead

Неиндексированные запросы могут быть очень дорогими

Анти-паттерн: SELECT * FROM MY_DOMAIN WHERE MY_ATTR_1 IS NULL

  • Используйте отдельный флаговый атрибут со строковым значением TRUE или FALSE вместо проверки на NULL. Таким образом, запрос будет использовать индекс: SELECT * FROM MY_DOMAIN WHERE MY_ATTR_1 = ‘FALSE’

Некоторые запросы работают медленно, хотя и проиндексированы.

Селективность индекса влияет на скорость также как и в других SQL движках

  • Как и в других БД, производительность запросов на выборку данных определяется селективностью индексов, указанных в WHERE. Убедитесь, что вы понимаете селективность ваших индексов и что ваше WHERE выражение содержит лучший из них.

Как и в любой другой многопользовательской системе могут появляться значительные скачки времени отклика.

  • Защитите приложение от скачков, возникающих в SimpleDB или S3, кеширующим фронтендом, таким как MemCached

Решив перейти на SimpleDB и S3, Netflix очень быстро мигрировала в облачную инфраструктуру, во всеоружии встретив новые агрессивные планы запуска продуктов и рост трафика. Были проблемы, но мы справились практически со всеми.