2014-12-01 3 views
0

Мы изучаем использование Breeze для полевого развертывания некоторых инструментов. Сценарий таков: аудитор посетит сайты в этой области, где большую часть времени не будет - или очень деградирован - доступ в Интернет. Вместо того, чтобы копировать нашу базу данных SQL на всех ноутбуках и планшетах (если это вообще возможно), мы надеемся использовать Breeze для кэширования данных, а затем сохранить их локально, чтобы они были доступны, когда нет доступного соединения.Ограничения кеша Breeze.js? Или браузер?

К сожалению, Breeze, кажется, задыхается при кешировании значительного количества данных. Как правило, в Chrome это где-то между 8 и 13 МБ объектов (как измеряется заголовками HTTPResponse). Это может немного измениться в зависимости от того, сколько вкладок у меня открыто и что такое, но я не смог переместить это более 10%. ошибка, которую я получаю, это вкладка Chrome, и говорит мне перезагрузить. Ошибка реплицируется (я загружаю данные в 100 тыс. Кусков, и она терпит неудачу при одном и том же чтении каждый раз и отлично работает, если я остановлю ее после предыдущего чтения). Когда я изменяю размер страницы, она всегда терпит неудачу в том же диапазоне.

Является ли это ограничением Бриз, или Chrome? Или окна? Я попробовал его в Firefox, и он обрабатывает еще меньше данных, прежде чем весь браузер выйдет из строя. IE намного лучше, но никто из них не делает ничего хорошего.

Глядя на производительность в диспетчере задач, я получаю следующее:

  1. IE идет от 250M использования памяти в 1.7g использования памяти во время процесса кэширования и кэширует в общей сложности около 14MB, прежде чем бросать OUT- ошибка памяти.
  2. Хром идет от использования памяти 206B до 850 М при кэшировании в общей сложности около 9 МБ
  3. Firefox работает от 400 М до 750 МБ, и ему удается кэшировать около 5 МБ до того, как вся программа выйдет из строя.

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

Неужели кто-нибудь еще решил эту проблему? Каковы наилучшие подходы к решению чего-то подобного. Я думал о нескольких вещах, но никто из них не идеален. Любые идеи были бы хорошы.

ДОБАВЛЕНО По просьбе Стива Шмитта:

Вот некоторые полезные ссылки:

Первый запрос, просто населяют теги на странице выполняются быстро и загружают минимальные данные:

var query = breeze.EntityQuery 
       .from("Countries") 
       .orderBy("Name") 
       .expand("Regions.Districts.Seasons, Regions.Districts.Sites"); 

После того, как пользователь выбрать сайты он/она хочет кэшировать следующие два запроса стартовало (используется как один запрос, но я разбил его на две части, надеясь, что будет меньше нагрузки на ресурсов - это не помогло). Первый запрос (обычно 2-3K-сущности и около 2 МБ) выполняется, как ожидалось. Некоторая комбинация перечисленных предикатов используется для фильтрации данных.

var qry = breeze.EntityQuery 
        .from("SeasonClients") 
        .expand("Client,Group.Site,Season,VSeasonClientCredit") 
        .orderBy("DistrictId,SeasonId,GroupId,ClientId") 

    var p = breeze.Predicate("District.Region.CountryId", "==", CountryId); 
    var p1 = breeze.Predicate("SeasonId", "==", SeasonId); 
    var p2 = breeze.Predicate("DistrictId", "==", DistrictId); 
    var p3 = breeze.Predicate("Group.Site.SiteId", "in", SiteIds); 

После выполнения первого запроса, второй запрос (ниже) работает (также с использованием некоторой комбинации из перечисленных предикатов для фильтрации данных. Приблизительно 9 МБ, она будет иметь около 50K строк для загрузки). Когда общая загрузка загрузки между двумя запросами составляет от 10 МБ до 13 МБ, браузеры будут разбиваться.

var qry = breeze.EntityQuery 
        .from("Repayments") 
        .orderBy('SeasonId,ClientId,RepaymentDate'); 

    var p1 = breeze.Predicate("District.Region.CountryId", "==", CountryId); 
    var p2 = breeze.Predicate("SeasonId", "==", SeasonId); 
    var p3 = breeze.Predicate("DistrictId", "==", DistrictId); 
    var p4 = breeze.Predicate("SiteId", "in", SiteIds); 

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

Спасибо за интерес, и дайте мне знать, если вам что-то еще нужно.

+0

Не могли бы вы предоставить дополнительную информацию о своих данных? Может быть, предоставить метаданные для объектов, которые вы кешируете? Это может помочь определить, есть ли ошибка где-то, что вызывает проблему. –

+0

Стив, спасибо за интерес. Обновлен вопрос, чтобы дать немного больше информации. – Beartums

+0

В ваших тестах, что вы делаете с результатами запроса? Отбросить их? Хранение их? Очистка кеша с помощью 'manager.clear()' между запросами? Попытка понять, какая фаза вызывает проблемы. Я считаю, что у каждого браузера есть своя точка задувания для размера полезной нагрузки, но я сомневаюсь, что это так. Я склоняюсь к «слишком большому количеству объектов в памяти», и в этом случае нам нужно переосмыслить ваш подход. – Ward

ответ

1

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

Это ни Бриз, ни Браузер, а скорее Нокаут. По-видимому, оболочка нокаута вокруг сумерек-бритвов использует всю эту память (по крайней мере, при загрузке объектов и в моей среде). Как описано выше, Knockout/Breeze исчезнет после чтения около 5 МБ данных, что приведет к сбою Chrome с использованием более 1,7 ГБ памяти (от использования памяти предварительной загрузки около 300 МБ). Перезапуск приложения в ANgularJS устранило проблему. До сих пор я мог загружать более 50 МБ из одной и той же модели EF6 в Breeze/Angular, общее использование памяти Chrome никогда не превышало 625 МБ.

Я буду тестировать большую полезную нагрузку, но на 50 МБ больше, чем удовлетворяет мои потребности на данный момент. Спасибо всем за вашу помощь.

3

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

  1. Определить, какие типы объектов должна быть доступны для редактирования против которых используется для заполнения раскрывающегося меню и т.д. Загрузки нередактируемых данных с использованием noTracking запроса и кэшировать их в localStorage самостоятельно, используя JSON.stringify. Это позволяет избежать накладных расходов на принуждение данных к объектам, отслеживание изменений и т. Д. Хорошими кандидатами для такого подхода в вашей модели могут быть типы объектов, такие как Страна, Регион, Район, Участок и т. Д.

  2. Если возможно, обеспечьте объект в вашем приложении для пользователей, чтобы определить, какие записи они хотят «отключить». Таким образом, вам не нужно загружать и кэшировать все, что может стать довольно дорогостоящим в зависимости от количества отношений, объектов, свойств и т. Д.

  3. В сочетании с предложением № 2 избегайте загрузки всех доступных для редактирования данных в один раз и избегать использования одного экземпляра EntityManager для загрузки каждого набора данных. Например, если объект клиента является чем-то, что требуется для редактирования в поле без подключения, создайте новый EntityManager, загрузите один клиент (расширяя любые дочерние элементы, которые также должны быть доступны для редактирования) и кешируйте эти данные отдельно от других клиентов ,

  4. Сбросить метаданные бриза один раз. При вызове exportEntities аргумент includeMetadata должен быть ложным. Подробнее об этом here.

  5. Для создания новых экземпляров EntityManager используется метод createEmptyCopy.

EDIT:

Я хочу, чтобы ответить на этот комментарий:

Скажем, у меня есть клиент, который имеет счета и платежи. Этот клиент находится в группе , на сайте, в регионе, в стране. Вы говорите, что у клиентов клиент, платежная и счетная информация могут иметь свои собственные EM, , в то время как иерархия местоположений может быть в 4-м EM без отслеживания? Затем, когда я обращаюсь к ним, я связываю отношения по мере необходимости, используя LINQs на разных ЭМ (дайте мне все счета для клиента A, дайте мне все платежи за клиента A)?

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

Предполагая, что вам не нужно редактировать группы, сайты, регионы и страны в автономном режиме, первое, что я сделал бы, - загрузить список групп, используя параметр noTracking, и кэшировать их в localStorage для использования в автономном режиме. Затем сделайте то же самое для сайтов, регионов и стран. Имейте в виду, что объекты, загруженные с параметром noTracking, не кэшируются в менеджере сущностей, поэтому вам нужно захватить результат запроса, JSON.stringify, а затем вызвать localStorage.setItem. Цель состоит в том, чтобы убедиться, что ваше приложение всегда имеет доступ к списку групп, сайтов, регионов и т. Д., Чтобы при отображении формы для редактирования объекта клиента у вас были данные, необходимые для заполнения группы, сайта, региона и страны select/combobox/dropdown.

Предполагая, что пользователь идентифицировал подмножество клиентов, с которыми они хотят работать в автономном режиме, я загружал каждый из этих клиентов по одному (включая информацию об оплате и оплате, но не расширяя свою группу, сайт, регион , страна) и кешировать каждый клиент + платежи + счета, установленные с помощью entityManager.exportEntities. Рассуждая здесь, нет смысла загружать несколько клиентов, а также их платежи и счета в тот же EntityManager каждый раз, когда вы хотите отредактировать конкретного клиента. Это может быть много лишних накладных расходов, но опять же, это немного суждение.

+0

Джереми, спасибо за ваши мысли. Они выглядят как хорошие идеи, и я попробую их как можно скорее. Несколько вопросов: 1) если я использую notracking, это нарушает отношения и возможности LINQ? 2} Я уже ввел фильтры, чтобы получить общую полезную нагрузку ниже определенного размера, но сейчас этот размер является движущейся целью, 3) Те же вопросы, что и # 1. Я хочу сохранить отношения и возможности LINQ, но, возможно, я не понимаю, что будут делать отдельные менеджеры сущностей, 4) я не думаю, что это проблема, так как экспорт работает красиво. Я рассмотрю все эти варианты. – Beartums

+0

При использовании noTracking вы по-прежнему получаете материал запроса стиля linq (где, orderBy, expand и т. Д.). Разница заключается в том, что результаты запроса не преобразуются в объекты и отслеживаются EntityManager, что минимизирует обработку на стороне клиента. Например, скажем, вашим пользователям необходимо создавать новые объекты клиента во время автономной работы. Для создания нового Клиента вам не нужен субъект округа. Вы можете загрузить список Районов, используя noTracking, и использовать DistrictId и Name, чтобы создать элемент выбора «район» в новой форме клиента. –

+0

re: отдельные EntityManager, это может не иметь смысла в вашем случае, но для моего проекта не было смысла сериализовать/десериализовать все сущности в/из localStorage при редактировании. В моем случае я использовал один EntityManager для набора объектов, которые я хотел редактировать, - единицы стиля работы. В моем случае пользователи могли выбрать нескольких пользователей для работы в автономном режиме. Каждый потребитель кэшируется отдельно вместе со своими телефонами, адресами и т. Д. –