Amazon DynamoDB — это полностью управляемая проприетарная база данных NoSQL , предлагаемая Amazon.com как часть портфеля Amazon Web Services . [2] [3] DynamoDB предлагает быстрое постоянное хранилище данных «ключ-значение» со встроенной поддержкой репликации , автомасштабирования , шифрования при хранении и резервного копирования по требованию, а также других функций. [4] [5]
Вернер Фогельс , технический директор Amazon.com, мотивировал проект в своем объявлении в 2012 году. [6] Amazon начинался как децентрализованная сеть сервисов. Первоначально сервисы имели прямой доступ к базам данных друг друга. Когда это стало узким местом в инженерных операциях, сервисы отошли от этого шаблона прямого доступа в пользу общедоступных API . Тем не менее, сторонние системы управления реляционными базами данных с трудом справлялись с клиентской базой Amazon. Кульминацией этого стал праздничный сезон 2004 года [7] [8] , когда несколько технологий вышли из строя из-за большого трафика.
Инженеры нормализовали эти реляционные системы, чтобы уменьшить избыточность данных , и эта конструкция оптимизирует хранение. Жертва: они сохранили заданный «элемент» данных (например, информацию, относящуюся к продукту в базе данных продуктов) в нескольких отношениях, и для сборки непересекающихся частей для запроса требуется время. Многие сервисы Amazon требовали в основном чтения данных по первичному ключу, а поскольку скорость была главным приоритетом, объединение этих частей было чрезвычайно трудоемким. [9]
Ответом Amazon было Dynamo : высокодоступное хранилище пар «ключ-значение», созданное для внутреннего использования. [6] Казалось, что «Динамо» было всем, что нужно их инженерам, но внедрение отставало. Разработчики Amazon выбрали «просто работающие» шаблоны проектирования с S3 и SimpleDB. Хотя эти системы имели заметные конструктивные недостатки, они не требовали дополнительных затрат на обеспечение оборудования, а также масштабирование и перераспределение данных. Следующая версия технологии NoSQL от Amazon , DynamoDB, автоматизировала эти операции по управлению базами данных.
В DynamoDB данные хранятся в таблицах как элементы и могут быть запрошены с помощью индексов . Элементы состоят из ряда атрибутов , которые могут принадлежать к нескольким типам данных и должны иметь ключ , который должен быть уникальным во всей таблице.
Таблица DynamoDB — это логическая группа элементов, которые представляют данные, хранящиеся в этой таблице. Учитывая NoSQL-природу DynamoDB, таблицы не требуют, чтобы все элементы в таблице соответствовали некоторой предопределенной схеме. [10]
Элемент в DynamoDB — это набор атрибутов, которые можно однозначно идентифицировать в таблице. Атрибут — это атомарный объект данных, который сам по себе представляет собой пару «ключ-значение». Ключ всегда имеет тип String, а значение может относиться к одному из нескольких типов данных.
Элемент однозначно идентифицируется в таблице с использованием подмножества его атрибутов, называемых ключами. [10]
Первичный ключ — это набор атрибутов, которые однозначно идентифицируют элементы в таблице DynamoDB. Для создания таблицы DynamoDB требуется определение первичного ключа. Каждый элемент в таблице DynamoDB должен иметь все атрибуты, составляющие первичный ключ, и никакие два элемента в таблице не могут иметь один и тот же первичный ключ. Первичные ключи в Dynamo DB могут состоять из одного или двух атрибутов.
Когда первичный ключ состоит только из одного атрибута, он называется ключом раздела. Ключи раздела определяют физическое местоположение связанного элемента. В этом случае никакие два элемента в таблице не могут иметь одинаковый ключ раздела.
Когда первичный ключ состоит из двух атрибутов, первый называется «ключом раздела», а второй — «ключом сортировки». Как и раньше, ключ раздела определяет физическое местоположение данных, но затем ключ сортировки определяет относительное логическое положение записи связанного элемента внутри этого физического местоположения. В этом случае два элемента в таблице могут иметь один и тот же ключ раздела, но никакие два элемента в разделе не могут иметь одинаковый ключ сортировки. Другими словами, с данной комбинацией ключа раздела и ключа сортировки гарантированно связан не более одного элемента в таблице DynamoDB. [10]
DynamoDB поддерживает числовые, строковые, логические типы данных, а также типы данных документа и набора данных. [11]
Первичный ключ таблицы — это индекс по умолчанию или первичный индекс таблицы DynamoDB.
Кроме того, таблица DynamoDB может иметь вторичные индексы. Вторичный индекс определяется по атрибуту, который отличается от ключа раздела или ключа сортировки в качестве первичного индекса.
Если вторичный индекс имеет тот же ключ раздела, что и первичный индекс, но другой ключ сортировки, он называется локальным вторичным индексом.
Если первичный индекс и вторичный индекс имеют разные ключи раздела, вторичный индекс называется глобальным вторичным индексом. [10]
DynamoDB использует JSON в качестве синтаксиса из-за его повсеместного распространения. [ нужна цитация ] Для действия создания таблицы требуется всего три аргумента: TableName, KeySchema — список, содержащий ключ раздела и необязательный ключ сортировки, — и AttributeDefinitions — список определяемых атрибутов, который должен как минимум содержать определения для атрибуты, используемые в качестве ключей разделения и сортировки. В то время как реляционные базы данных предлагают надежные языки запросов, DynamoDB предлагает только операции «Поместить», «Получить», «Обновить» и «Удалить». Запросы на размещение содержат атрибут TableName и атрибут Item, который состоит из всех атрибутов и значений, которые имеет элемент. Запрос на обновление имеет тот же синтаксис. Аналогичным образом, чтобы получить или удалить элемент, просто укажите TableName и Key.
DynamoDB использует хеширование и B-деревья для управления данными. При вводе данные сначала распределяются по разным разделам путем хеширования ключа раздела. Каждый раздел может хранить до 10 ГБ данных и по умолчанию обрабатывать 1000 единиц емкости записи (WCU) и 3000 единиц емкости чтения (RCU). [12] Один RCU представляет собой одно строго согласованное чтение в секунду или два окончательно согласованных чтения в секунду для элементов размером до 4 КБ. [13] Один WCU соответствует одной записи в секунду для элемента размером до 1 КБ.
Чтобы предотвратить потерю данных, DynamoDB имеет двухуровневую систему резервного копирования, репликации и долговременного хранения. [14] Каждый раздел состоит из трех узлов, каждый из которых содержит копию данных этого раздела. Каждый узел также содержит две структуры данных: B-дерево, используемое для поиска элементов, и журнал репликации, в котором отмечаются все изменения, внесенные в узел. DynamoDB периодически делает снимки этих двух структур данных и сохраняет их в течение месяца в S3 , чтобы инженеры могли выполнять восстановление своих баз данных на определенный момент времени.
Внутри каждого раздела один из трех узлов назначается «ведущим узлом». Все операции записи перед распространением сначала проходят через ведущий узел, что обеспечивает согласованность операций записи в DynamoDB. Чтобы поддерживать свой статус, лидер каждые 1,5 секунды отправляет «пульс» друг другу. Если другой узел перестанет получать сигналы пульса, он может инициировать выборы нового лидера. DynamoDB использует алгоритм Paxos для выбора лидеров.
Инженеры Amazon изначально избегали Dynamo из-за накладных расходов на проектирование, таких как предоставление разделов и узлов и управление ими. [9] В ответ команда DynamoDB создала службу AutoAdmin для управления базой данных. [14] AutoAdmin заменяет узел, когда он перестает отвечать, копируя данные с другого узла. Когда размер раздела превышает любой из трех пороговых значений (RCU, WCU или 10 ГБ), AutoAdmin автоматически добавит дополнительные разделы для дальнейшей сегментации данных. [12]
Как и системы индексирования в реляционной модели, DynamoDB требует, чтобы любые обновления таблицы отражались в каждом из ее индексов. DynamoDB справляется с этим с помощью службы, которую он называет «распространителем журналов», которая подписывается на журналы репликации в каждом узле и при необходимости отправляет дополнительные запросы Put, Update и Delete к индексам. [14] Поскольку индексы приводят к существенному снижению производительности запросов на запись, DynamoDB позволяет пользователю использовать не более пяти таких запросов в каждой таблице. [15]
Предположим, что пользователь DynamoDB выполняет операцию записи (Put, Update или Delete). В то время как типичная реляционная система преобразует SQL-запрос в реляционную алгебру и запускает алгоритмы оптимизации, DynamoDB пропускает оба процесса и сразу же приступает к работе. [14] Запрос поступает на маршрутизатор запросов DynamoDB, который аутентифицирует: «Поступает ли запрос от того места/кого, как он утверждает?» — и проверяет авторизацию — «Имеет ли пользователь, отправляющий запрос, необходимые разрешения». ?" Если эти проверки пройдены, система хэширует ключ раздела запроса, чтобы попасть в соответствующий раздел. Внутри имеется три узла, каждый из которых содержит копию данных раздела. Система сначала записывает информацию на ведущий узел, затем на второй узел, затем отправляет сообщение об успехе и, наконец, продолжает передачу на третий узел. Записи согласованы, поскольку они всегда сначала проходят через ведущий узел.
Наконец, распространитель журнала распространяет изменение на все индексы. Для каждого индекса он извлекает значение первичного ключа этого индекса из элемента, а затем выполняет ту же запись в этом индексе без распространения журнала. Если операция представляет собой обновление уже существующего элемента, обновленный атрибут может служить первичным ключом для индекса, и, следовательно, B-дерево для этого индекса также должно обновиться. B-деревья обрабатывают только операции вставки, удаления и чтения, поэтому на практике, когда распространитель журнала получает операцию обновления, он выполняет как операцию удаления, так и операцию размещения для всех индексов.
Теперь предположим, что пользователь DynamoDB выполняет операцию Get. Маршрутизатор запросов продолжает, как и прежде, аутентификацию и авторизацию. Далее, как и выше, мы хэшируем ключ раздела, чтобы получить соответствующий хеш. Теперь мы сталкиваемся с проблемой: если три узла в конечном итоге согласованы друг с другом, как мы можем решить, какой из них исследовать? DynamoDB предлагает пользователю два варианта выполнения чтения: согласованный и согласованный в конечном итоге. Последовательное чтение посещает ведущий узел. Но здесь снова возникает компромисс между согласованностью и доступностью: в системах с интенсивным чтением постоянное чтение с ведущего узла может привести к перегрузке одного узла и снижению доступности.
Второй вариант, окончательно согласованное чтение, выбирает случайный узел. На практике именно здесь DynamoDB жертвует согласованностью ради доступности. Если мы выберем этот путь, каковы шансы на несоответствие? Нам понадобится операция записи, чтобы вернуть «успех» и начать передачу данных на третий узел, но не завершить ее. Нам также понадобится наш Get, чтобы нацелиться на этот третий узел. Это означает, что вероятность несогласованности в пределах окна распространения операции записи составляет 1 из 3. Какова длина этого окна? Любое количество катастроф может привести к отставанию узла, но в подавляющем большинстве случаев третий узел обновляется в пределах миллисекунд от лидера.
DynamoDB предоставляет показатели производительности, которые помогают пользователям правильно подготовить его и обеспечить бесперебойную работу приложений, использующих DynamoDB:
Эти метрики можно отслеживать с помощью Консоли управления AWS , интерфейса командной строки AWS или инструмента мониторинга, интегрируемого с Amazon CloudWatch . [17]
Языки и платформы с привязкой DynamoDB включают Java , JavaScript , Node.js , Go , C# .NET , Perl , PHP , Python , Ruby , Rust , Haskell , Erlang , Django и Grails . [18]
В отношении HTTP API элементы запроса:
POST / HTTP / 1.1 Хост : dynamodb.<регион>.<домен>; Accept-Encoding : идентификатор Content-Length : <PayloadSizeBytes> User-Agent : <UserAgentString> Content-Type : application/x-amz-json-1.0 Авторизация : AWS4-HMAC-SHA256 Credential=<Credential>, SignedHeaders=<Headers> , Signature=<подпись> X-Amz-Date : <Date> X-Amz-Target : DynamoDB_20120810.Query{ "TableName": "Ответить", "IndexName": "PostedBy-Index", «Лимит»: 3, «ConsistentRead»: правда, "ProjectionExpression": "Id, PostedBy, ReplyDateTime", "KeyConditionExpression": "Id = :v1 И PostedBy BETWEEN :v2a AND :v2b", "ExpressionAttributeValues": { ":v1": {"S": "Amazon DynamoDB#DynamoDB Thread 1"}, ":v2a": {"S": "Пользователь А"}, ":v2b": {"S": "Пользователь C"} }, «ReturnConsumedCapacity»: «ИТОГО»}
Пример ответа:
HTTP / 1.1 200 OK x-amzn-RequestId : <RequestId> x-amz-crc32 : <Контрольная сумма > Тип контента : application/x-amz-json-1.0 Длина контента : <PayloadSizeBytes> Дата : <Дата> { " ConsumedCapacity": { "CapacityUnits": 1, "TableName": "Reply" }, "Count": 2, "Items": [ { "ReplyDateTime": {"S": "2015-02-18T20:27:36.165 Z"}, "PostedBy": {"S": "Пользователь A"}, "Id": {"S": "Amazon DynamoDB#DynamoDB Thread 1"} }, { "ReplyDateTime": {"S": " 2015-02-25T20:27:36.165Z"}, "PostedBy": {"S": "Пользователь Б"}, "Id": {"S": "Amazon DynamoDB#DynamoDB Thread 1"} } ], " ScannedCount": 2 }
GetItem в Go :
getItemInput := & dynamodb . GetItemInput { Имя таблицы : aws . Строка ( «счастливый маркетолог» ), Ключ : карта [ строка ] * dynamodb . AttributeValue { "пк" : { S : aws . Строка ( «проект» ), }, «sk» : { S : aws . Строка ( электронная почта + " " + имя ), }, }, } getItemOutput , err := dynamodbClient . ПолучитьItem ( getItemInput )
Удалить элемент в Go :
deleteItemInput := & dynamodb . УдалитьItemInput { Имя таблицы : aws . Строка ( «счастливый маркетолог» ), Ключ : карта [ строка ] * dynamodb . AttributeValue { "пк" : { S : aws . Строка ( «проект» ), }, «sk» : { S : aws . Строка ( адрес электронной почты + " " + имя ), }, }, } _ , ошибка := dynamodbClient . УдалитьItem ( deleteItemInput ) , если ошибка != ноль { паника ( ошибка ) }
UpdateItem в Go с помощью Expression Builder:
обновление := выражение . Установить ( выражение . Имя ( имя ), выражение . Значение ( значение ), ) выражение , ошибка := выражение . НьюБилдер (). WithUpdate ( обновление ). Построить () если ошибка != ноль { паника ( ошибка ) } updateItemInput := & dynamodb . UpdateItemInput { Имя Таблицы : aws . Строка ( имя_таблицы ), Ключ : карта [ строка ] * dynamodb . AttributeValue { "пк" : { S : aws . Строка ( «проект» ), }, «sk» : { S : aws . String ( "mySortKeyValue" ), }, }, UpdateExpression : expr . Обновление (), ExpressionAttributeNames : expr . Имена (), ExpressionAttributeValues : выражение . Значения (), } fmt . Printf ( "updateItemInput: %#v\n" , updateItemInput ) _ , ошибка = dynamodbClient . UpdateItem ( updateItemInput ) , если ошибка != ноль { паника ( ошибка ) }
{{cite web}}
: CS1 maint: числовые имена: список авторов ( ссылка )