Ключевая концепция, которую необходимо принять, — **DynamoDB требует иного мышления, нежели реляционные базы данных**. Вы проектируете не нормализованную схему, а структуру данных, оптимизированную под конкретные шаблоны доступа (access patterns) вашего приложения. Все начинается с вопроса: "Какие запросы будет выполнять мое приложение?".
**Сердце DynamoDB — первичный ключ (Primary Key)**. Он однозначно идентифицирует элемент и состоит из:
- **Partition Key (HASH key)**. От этого ключа зависит физическое распределение данных по партициям (секциям хранилища). Все элементы с одинаковым значением Partition Key хранятся вместе и могут быть извлечены очень быстро. Выбор Partition Key — самое важное решение. Цель — равномерное распределение данных и запросов (avoid hot partitions). Плохой ключ (например, "status" со значениями "ACTIVE"/"INACTIVE", где 99% данных "ACTIVE") создаст "горячую" партицию и ограничит производительность.
- **Sort Key (RANGE key, опционально)**. Если указан, то внутри одной партиции данные сортируются по этому ключу. Это позволяет выполнять мощные операции: запросы по диапазону (BETWEEN), начинающиеся с (BEGINS_WITH), а также эффективно организовывать иерархические данные (например, `UserId#OrderId`).
- **Global Secondary Index (GSI)**. Имеет свой собственный Partition Key и Sort Key, отличные от основной таблицы. Индекс асинхронно реплицируется, занимает отдельные ресурсы пропускной способности (за которые вы платите отдельно). Идеален для запросов по разным атрибутам (например, поиск заказов по `CustomerEmail`).
- **Local Secondary Index (LSI)**. Использует тот же Partition Key, что и основная таблица, но другой Sort Key. Не занимает отдельные ресурсы пропускной способности, но должен быть создан одновременно с таблицей (нельзя добавить позже). Полезен для альтернативных сортировок внутри партиции.
- **Единый объект с дистрибуцией (Single Table Design)**. Продвинутая, но крайне эффективная методика. Вы храните разнородные сущности (пользователи, заказы, продукты) в одной таблице, используя составные ключи для их различения. Например, PK: `USER#123`, SK: `PROFILE` — данные профиля; PK: `USER#123`, SK: `ORDER#2023-01` — заказ пользователя. Это позволяет за один запрос получить все связанные данные пользователя (используя Query с PK=`USER#123`), минимизируя задержки и стоимость.
- **Шардинг "горячих" партиций**. Если естественный ключ (например, популярный товар) создает горячую партицию, его можно "расшардить", добавив суффикс. Вместо `ProductId=123` использовать `ProductId=123#0`, `ProductId=123#1`, распределяя нагрузку. Приложение должно знать логику распределения.
- **Агрегация на запись (Write-time Aggregation)**. Вместо дорогостоящих операций суммирования (скан всей таблицы) при чтении, агрегируйте данные при записи. Например, при добавлении нового лайка к посту сразу увеличивайте счетчик `likesCount` в элементе поста. Это классический trade-off: более сложная запись vs молниеносное чтение.
- **Provisioned Mode**: вы резервируете фиксированное количество единиц емкости чтения (RCU) и записи (WCU). Подходит для стабильных, предсказуемых нагрузок. Для highload с пиками используйте **Auto Scaling**, который динамически подстраивает capacity под нагрузку.
- **On-Demand Mode**: вы платите за каждый запрос; емкость масштабируется автоматически и мгновенно. Идеально для непредсказуемых нагрузок или пилотных проектов, но может быть дороже на стабильных высоких нагрузках.
- Избегайте **Scan** операции как чумы. Она читает всю таблицу, очень дорогая и медленная.
- Используйте **Query** для поиска по ключу. Это самая эффективная операция.
- Используйте **BatchGetItem** и **BatchWriteItem** для групповых операций, чтобы уменьшить количество сетевых вызовов.
- Реализуйте **пагинацию** с помощью `LastEvaluatedKey`, никогда не загружайте все данные сразу.
- Для сложных запросов, которые невозможно выразить через ключи и индексы, используйте **DynamoDB Streams** + **AWS Lambda** для materialized views или отправки данных в Elasticsearch для полнотекстового поиска.
DynamoDB — это мощнейший инструмент, но он требует дисциплины. Начните с тщательного анализа access patterns, создайте несколько тестовых таблиц с разными ключами, загрузите реалистичные объемы данных и протестируйте производительность под нагрузкой (используя, например, Amazon Kinesis Data Generator или собственные скрипты). Инвестиции времени в правильное проектирование окупятся сторицей, когда ваше приложение будет обслуживать миллионы запросов в секунду без единой секунды простоя.
Комментарии (12)