Хранение и запрос объявлений между двумя датами - PullRequest
0 голосов
/ 08 мая 2020

Фон

Мне нужно создать таблицу для хранения объявлений в DynamoDB. Каждое объявление имеет следующую структуру:

{
    "announcementId": "(For the frontend to identify an announcement to the backend)",
    "author": "(id of author)",
    "displayStartDatetime": "",
    "displayEndDatetime": "",
    "title": "",
    "description": "",
    "image": "(A url to an image)",
    "link": "(A single url to another page)"
}

Поскольку мы все еще разрабатываем таблицу, изменения в структуре разрешены. В частности, можно изменить announcementId, displayStartDatetime и displayEndDatetime.

Основной шаблон доступа - найти текущие объявления. У пользователей есть веб-страница, на которой они могут видеть все текущие объявления и их детали.

У каждого объявления есть дата, когда его показывать (displayStartDatetime), а когда прекращать (displayEndDatetime). Объявление должно оставаться в таблице после того, как текущее datetime прошло displayEndDatetime для справки для администраторов.

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

Проблема

В идеале я хотел бы запросить таблицу для всех текущих объявлений в одном запросе.

Однако я пришел к выводу, что невозможно объединить два времени даты в один ключ сортировки потому что невозможно заказать два одинаковых по важности фрагмента данных (например, сохранение временных меток в виде строки будет означать, что один будет более важным / большим, чем другой).

Следовательно, в качестве компромисса я хотел бы чтобы отсортировать значения таблицы по displayEndDatetime, чтобы можно было отфильтровать прошлые объявления. Это связано с тем, что со временем прошлых анонсов будет больше, чем будущих, поэтому будет выгоднее оптимизировать это.

Скомпрометированное решение

В настоящее время мой (не очень хорошо ) решениями являются:

  1. Используйте один «горячий» ключ раздела и displayEndDatetime в качестве ключа сортировки.

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

Scan через таблицу

Я считаю, что Scan будет проверять каждый элемент в таблице, прежде чем выполнять какую-либо фильтрацию. Это решение не так хорошо, как 1., но его было бы проще всего реализовать, и оно позволило бы мне сохранить announcementId в качестве ключа раздела.

Scan GSI таблицы

Поскольку Scan просматривает каждый элемент, может быть более эффективным создать GSI (announcementId (PK), displayEndDatetime (SK)) и сканировать его, чтобы получить все announcementId ы, которые не прошли. После этого можно было сделать еще один запрос для получения всех объявлений.

Вопрос

Какое наиболее оптимизированное решение для хранения всех объявлений и последующего поиска текущих объявлений при использовании DynamoDB?

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

Изменить

Вот ответы на @ Вопросы tugberk на заднем плане:

  • Какую скорость записи вы ожидаете получить (т.е. пиковое количество операций записи в секунду, которое вам необходимо обработать)?

Я не уверен, как админы будут использовать эту систему, объявления могут быть очень регулярными (около 3 в день) или очень нечастыми (около 3 в месяц).

  • Сколько новых данных вы планируете хранить ежедневно и как вы думаете, это будет расти?

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

  • Какова скорость чтения (например, пиковое чтение в секунду)?

I можно ожидать, что пиковое количество чтений в секунду будет около 500-1000 чтений / с. Ожидается, что это число будет расти по мере увеличения количества пользователей.

  • Сколько объявлений пользователь может видеть одновременно (т.е. какое среднее / максимальное количество объявлений будет видно в любой момент времени)? С практической точки зрения, это не должно быть больше нескольких (например, 10-20 максимум).

Я ожидаю, что максимальное количество объявлений, доступных для просмотра, будет до 30-40. Это связано с тем, что наряду с краткосрочными объявлениями может быть несколько долгосрочных объявлений. В среднем, я ожидаю около 5-10 объявлений. 1 минута задержки при отображении и скрытии объявлений)?

Я думаю, что скорость, с которой начинается показ объявления, важна, особенно если администраторы решат, что это хорошая платформа для срочных объявлений (вероятно, срочно с точностью до минуты ). Однако, когда оно перестает отображаться, менее важно, но чтобы не сбивать с толку пользователей, объявление должно прекращать отображение не позднее, чем через 4 часа после того, как истечет время окончания его отображения.

1 Ответ

1 голос
/ 09 мая 2020

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

Я знаю, что делаю, и мне действительно нужно использовать DynamoDB

Отредактировал этот ответ на основе ответов OP на мои исходные вопросы.

Поскольку вам действительно нужен DynamoDB для этого по внутренним причинам, я думаю, что лучше хранить данные в двух таблицах DynamoDB для обслуживания операций чтения и записи, поскольку почти все шаблоны доступа, которые я могу придумать, будут попадать в несколько разделов, если у вас есть одна таблица. Вы можете обойтись без GSI, но это не слишком однозначно, как это сделать, и я не уверен, есть ли какие-то преимущества в том, чтобы делать это таким образом.

Главное, что вам нужно оптимизировать, это чтения, как вы упомянули, могут go до 2K / rps, что достаточно велико, чтобы сделать эту часть, в которой вы оптимизируете свою архитектуру. Исходя из ваших предположений о 3-х объявлениях в день, не о чем беспокоиться, что касается записи.

Общая идея такова:

  • Я бы подумал использование одной таблицы DynamoDB для обработки записи, где вы можете настроить идентификатор author в качестве ключа раздела и идентификатор announcement в качестве ключа сортировки (и сделать свой первичный ключ как комбинацию обоих). Это позволит вам легко запрашивать все объявления для данного автора.

  • У меня также была бы вторая таблица DynamoDB для обработки чтений, где вы будете хранить только активные объявления, которые ваше приложение может запросить и получить все это с помощью запроса Scan (т.е. O(N)), что не вызывает беспокойства, поскольку вы упомянули, что в любой момент времени будет только 30-40 активных объявлений. Давайте представим, что это будет даже 500, вы все еще в порядке с этой структурой. Что касается ключа разделения и сортировки, у меня было бы просто логическое поле active в качестве ключа раздела, которое у вас всегда будет как true, вы можете использовать идентификатор объявления в качестве ключа сортировки и сделать комбинацию оба в качестве первичного ключа. Если вам важен вид этих объявлений, вы можете соответствующим образом настроить ключ сортировки, но убедитесь, что он уникален (т.е. рассмотрите возможность объединения идентификатора объявления, например, {displayBeginDatetime-in-yyyyMMddHHmmss-format}-{announcementId}. Таким образом вы гарантируете, что попадете только в один раздел. Однако , вы действительно можете упростить это и использовать идентификатор объявления в качестве ключа раздела и первичного ключа, поскольку я почти уверен, что DynamoDB будет хранить все ваши данные в одном разделе, поскольку он будет таким маленьким. Лучше подтвердить это, хотя я не Уверен на 100%. Дело в том, что вы намного лучше обеспечиваете попадание в один раздел с помощью этого запроса.

Вот как это может работать, где есть некоторые крайние случаи, которые я упускаю :

  • записать запись внутри первой DynamoDB для объявления. Когда объявление записано, настройте displayEndDatetime как TTL этой строки, предполагая, что вы не По истечении срока действия объявления эта запись в этой таблице не нужна.
  • иметь задание, выполняющееся N минуту (одно или несколько, в зависимости от разрыва несогласованности данных, с которым вы можете справиться), что будет Scan всей таблицы DynamoDB по разделам (делать это с разбивкой на страницы) и принимать решения по какие объявления видны в данный момент. Затем запишите свои данные во вторую таблицу DynamoDB, которая будет обрабатывать операции чтения, в структуре, которую мы установили выше, чтобы ваш потребитель мог читать из нее, не беспокоясь о какой-либо фильтрации, поскольку данные уже отфильтрованы (например, все объявления вот видимые). Обратите внимание, что Scan здесь подойдет, так как вы запускаете это один раз каждые N минут, при условии, что у вас все в порядке с пробелом несогласованности данных не менее 1 минуты + время обработки. Я бы посоветовал запускать это каждые 10 минут или около того, если у вас нет строгих требований к согласованности данных.
  • В системе хранения для чтения также настройте displayEndDatetime как TTL для
  • Настройте потоки DynamoDB в первой таблице DynamoDB, которая хранится в течение 24 часов и гарантирует единовременную доставку, а также имеет лямбда-потребителя этого потока, который для обработки, когда элемент удален (произойдет, когда TTL сработает для определенной строки), чтобы сохранить запись этих объявлений в другом месте, по причинам более длительного хранения, и вам необходимо будет раскрыть его с помощью другого шаблона доступа (например, показать все объявления на автора, чтобы они могли повторно активировать старые объявления), как вы упомянули в своем вопросе. Вы можете настроить источник лямбда-событий с потоками DynamoDb , что позволит вам обрабатывать сбои с повторными попытками и т. Д. c. Убедитесь, что ваши logi c в этих лямбдах идемпотентны, чтобы вы могли безопасно повторить попытку.

Ниже приведены части моего исходного вопроса, которые по-прежнему актуальны для всех, кто может пытаться достичь того же. Итак, я оставлю их здесь, но они менее актуальны, поскольку OP должен использовать DynamoDB.

Почему DynamoDB?

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

Вопросы, приведенные ниже, помогут вам понять, действительно ли вам нужен DynamoDB для этого, или вы можете обойтись более гибкой системой хранения данных:

  • какова скорость записи, которую вы ожидаете получение (т.е. пиковое количество операций записи в секунду, которые вам необходимо обработать)?
  • сколько новых данных вы планируете хранить ежедневно и как, по вашему мнению, это будет расти?
  • какова скорость чтения (например, пиковое число чтений в секунду)?
  • Сколько объявлений пользователь может видеть одновременно (т.е. какое среднее / максимальное количество объявлений будет видно в любой момент времени)? С практической точки зрения, их должно быть не больше нескольких (например, не более 10-20). Это поможет вам понять, нужно ли вам, чтобы все видимые объявления были собраны в один go, или нужна система нумерации страниц.
  • Какой пробел в несогласованности данных вы счастливы здесь (т.е. требуется точность на уровне секунд, или вы были бы счастливы иметь задержку примерно в 1 минуту при отображении и скрытии объявлений)?

На самом деле мне не нужен DynamoDB

Исходя из моих предположений о ваше потребление и потребности администратора для этого варианта использования, я считаю, что вам не нужен DynamoDB для этого с предположением, что для этого не будет большого количества операций записи (что может быть неправильным), и если эти предположения верны, приведенное выше является супер инженерное решение для вас. Допустим, это правильно, я думаю, вам лучше использовать для этого PostgreSQL, который может дать вам легкую возможность изменить свой шаблон доступа по своему усмотрению с дальнейшей индексацией, а для текущего шаблона доступа вы можете иметь запрос диапазона по времени начала и окончания.

...