Существует ли установленный шаблон для разбиения по страницам в Service Fabric ReliableCollections?

В надежных коллекциях (в частности, IReliableDictionary) подход к реализации «общих» запросов заключается в обновлении вторичного словаря, который структурирует ключи, которые должны быть упорядочены определенным образом в перечислении. При работе с большими наборами данных мне хотелось бы избежать переноса большого количества данных.

Для этого я хотел бы внедрить какой-то токен продолжения, который вызывающая сторона может предоставить мне при запросе данных. В настоящее время я реализую это, сначала генерируя упорядоченное перечисление и возвращая первые n элементов, где n = размер MAX_PAGE. Продолжение — это, по сути, последний ключ в этом списке из n элементов. В следующий раз, когда вызывающий объект передает токен продолжения, я генерирую упорядоченное перечисление с функцией фильтра, указывающей, что ключ должен быть больше, чем продолжение.

У этого есть 2 проблемы (которые я вижу):

  1. Коллекция может меняться между моментом, когда вызывающая сторона впервые запрашивает страницу, и последующим запросом. Я не уверен, что смогу избежать этого, поскольку обновления коллекции должны происходить в любое время, независимо от того, кто пытается просмотреть данные.
  2. Я не уверен, как используется функция фильтра. Я предполагаю, что, поскольку разработчик может фильтровать что угодно, метод GetEnumerableAsync() должен предоставлять все ключи в словаре, прежде чем возвращать перечисляемое. Для достаточно большого набора данных это кажется медленным.

Существуют ли какие-либо предписанные подходы для разбиения данных на страницы, подобные этому? Мне начинает казаться, что я использую неверные коллекции с надежными коллекциями для некоторых случаев использования.


person Justin Blakley    schedule 07.12.2016    source источник


Ответы (2)


Одним из способов создания вторичных индикаторов является использование Уведомления. Используя уведомления со ссылочным типом TKey и TValue, вы можете поддерживать вторичный индекс, не создавая никаких копий вашего TKey или TValue.

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

Если у вас нет такой структуры данных для размещения вторичного индекса, другой вариант заключается в том, чтобы сохранить транзакцию и перечисление в реальном времени при вызовах клиентов с постраничными страницами. Таким образом, вы можете использовать встроенную поддержку моментальных снимков Reliable Dictionary, чтобы обеспечить постраничное последовательное сканирование данных без блокировки записи. Токеном в этом случае будет TransactionId позволяя вашей службе найти соответствующее перечисление для MoveNextAsync включен. Недостатком использования этого параметра является то, что Reliable Dictionary не сможет обрезать старые версии значений, которые остаются видимыми из-за потенциально длительных транзакций моментальных снимков.

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

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

person Mert Coskun - MSFT    schedule 08.12.2016
comment
Когда вы говорите, что «токен в этом случае будет TransactionID», означает ли это, что существует механизм для создания транзакции из transactionId, или вы просто говорите, что я могу хранить ITransaction/IAsyncEnumerable в словаре где-то в службе? Если последнее - выдержит ли это реплику, которая выйдет из строя? - person Justin Blakley; 09.12.2016
comment
Я имею в виду последнее @JustinBlakley: сохраните ITransaction и IAsyncEnumerable в структуре данных, которая позволяет вам использовать TransactionId для индексации. В случае отработки отказа все текущие транзакции, инициированные на неудачной реплике, прерываются. - person Mert Coskun - MSFT; 11.12.2016
comment
Это имеет смысл @MertCoskun, я думаю, что одна последняя оптимизация, которую я мог бы сделать, - это также включить последний ключ, возвращенный в токен продолжения. Таким образом, в случае аварийного переключения реплики я мог продолжить с того места, где остановился, с падением производительности. - хотя при достаточно большом наборе ключей может быть лучше вернуть ошибку вызывающей стороне и позволить ей определить, что делать. - person Justin Blakley; 12.12.2016
comment
@JustinBlakley, помните, что транзакция в исходной реплике отслеживала то, что видно в этом перечислении (представление моментального снимка), и обеспечивала, чтобы старые версии, видимые для этой транзакции, не удалялись сборщиком мусора. Новая реплика, пытающаяся обслужить следующее постраничное чтение, не будет иметь этой транзакции. Более того, созданная им новая транзакция будет иметь другое представление моментального снимка (поскольку она создается в другое логическое время). Следовательно, вы не только не можете гарантировать изоляцию моментального снимка для своего клиента, но и должны обрабатывать случаи, когда новая реплика может не иметь последнего считываемого ключа. - person Mert Coskun - MSFT; 12.12.2016

У меня похожая проблема, и она также включает фильтрацию и сортировку данных из нескольких разделов.

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

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

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

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

person Robert    schedule 20.09.2017