Кэширование данных#
Кэширование используется для сокращения количества обращений к базе данных и ускорения повторного чтения данных. Кэш хранит копию уже загруженных данных в памяти приложения, а источником актуального состояния остается база данных.
В системе используются два основных механизма кэширования данных: разделяемый кэш и транзакционный кэш. Разделяемый кэш (shared cache, кэш второго уровня) применяется для редко изменяемых справочных данных, которые часто читаются разными сессиями приложения. Транзакционный кэш работает в рамках текущей операции или транзакции и хранит данные, с которыми ORM работает в текущей сессии.
Примечание
Кэш не заменяет базу данных. Актуальное состояние данных хранится в БД, а кэш содержит копию данных, которая может устареть, если данные были изменены без последующей очистки соответствующего кэша.
Назначение кэширования#
Кэширование снижает количество повторных запросов к базе данных. Если данные уже были загружены и помещены в кэш, последующие обращения могут выполняться из памяти приложения без повторного чтения из БД.
При работе с кэшируемыми данными важно учитывать область действия кэша, момент его заполнения и способ очистки. Для разделяемого кэша основным риском является устаревание данных после изменения справочников. Для транзакционного кэша основным риском является рост потребления памяти при длительной обработке.
Основные механизмы кэширования#
Механизм |
Область действия |
Основное назначение |
|---|---|---|
Разделяемый кэш |
Сервер приложений / узел кластера |
Повторное использование редко изменяемых справочных данных между разными сессиями. |
Транзакционный кэш |
Текущая сессия/операция |
Хранение объектов, загруженных или измененных в рамках текущей операции. |
Разделяемый кэш#
Разделяемый кэш (shared cache, кэш второго уровня) — это общий кэш сущностей уровня приложения. Он используется для повторного чтения уже загруженных данных без обращения к БД и может переиспользоваться разными сессиями приложения.
Разделяемый кэш предназначен для справочных данных, которые часто используются в системе и редко изменяются. Обычно это небольшие таблицы: типы объектов, системные справочники, настройки и другие данные, которые многократно читаются бизнес-логикой.
Для классов, которые работают с разделяемым кэшем, ORM-методы могут получать данные из памяти приложения без повторного обращения к базе данных. Такой подход снижает нагрузку на БД, но требует контроля актуальности кэша при изменении данных.
Как включается
Разделяемый режим кэширования задается на уровне ORM-модели класса через cacheType="shared". Для типовых справочников этот режим может быть уже задан в модели класса, поэтому при работе с такими объектами разделяемый кэш используется без дополнительной настройки на проекте.
Пример ORM-описания класса с разделяемым кэшем:
<class xmlns="http://www.global-system.ru/xsd/global3-class-1.0"
name="Btk_Class"
caption="Классы"
cardEditor.representation="Card"
listEditor.representation="List"
viewOptions.openCardType="mdi"
supertype="journal"
cacheType="shared"
objectAttrCardType="simple"
isTrackChangesForIncludeToConf="true">
После включения cacheType="shared" сущности класса могут повторно использоваться без повторного запроса к БД.
Назначение
Разделяемый кэш используется, когда одни и те же данные повторно запрашиваются разными операциями и сессиями. Вместо повторного чтения из БД данные загружаются в память сервера приложений и затем переиспользуются.
Такой механизм снижает количество обращений к БД для стабильных справочных и настроечных данных, которые часто участвуют в бизнес-логике.
Какие данные кэшируются
Разделяемый кэш применяется для небольших и редко изменяемых таблиц: типов объектов, системных справочников, стабильных настроек и других данных, которые не меняются в ходе обычной оперативной работы.
Разделяемый кэш не используется для часто изменяемых данных и сценариев, где при каждом обращении требуется гарантированно актуальное состояние из БД. Если устаревшее значение может привести к ошибке расчета, проведения, выбора логики или отображения состояния, такие данные не должны опираться на разделяемый кэш.
Перед включением разделяемого кэша для класса нужно оценить размер данных, частоту изменений и возможные последствия работы со старой версией данных. Чем чаще данные изменяются и чем критичнее их актуальность, тем менее подходит разделяемый кэш.
Как работает
При первом обращении к кэшируемым данным сервер приложений считывает данные из базы данных и помещает их в разделяемый кэш. При последующих обращениях ORM может использовать данные из кэша, не выполняя повторный SQL-запрос.
Общий порядок работы:
Код обращается к данным через ORM-метод.
Если данные уже есть в кэше текущей сессии, используется кэш текущей сессии.
Если данных нет в кэше текущей сессии, проверяется разделяемый кэш.
Если данных нет в разделяемом кэше, выполняется чтение из БД.
Загруженные данные помещаются в кэш и могут использоваться повторно.
Разделяемый кэш хранит сущности по идентификатору. Для отдельных сценариев в ORM-модели могут использоваться дополнительные индексы cache-index, которые позволяют искать кэшированные данные по другим стабильным полям.
Изменение и сброс разделяемого кэша#
При изменении данных, которые используются в разделяемом кэше, сначала меняется состояние в базе данных. Кэш при этом может продолжить хранить прежнюю копию данных, загруженную до изменения.
Когда нужен сброс
Сброс кэша выполняется всегда после изменения данных, которые используются в разделяемом кэше. Это правило применяется независимо от способа изменения данных:
изменение через интерфейс;
изменение через ORM;
изменение через скрипт;
загрузка через DataInstall;
импорт данных;
миграция данных;
ручное изменение данных в БД.
Предупреждение
Обязательный сброс кэша. После любого изменения данных, которые используются в разделяемом кэше, выполняется сброс кэша. Без сброса серверы приложений могут продолжить использовать старую версию данных из памяти.
Риск рассинхронизации в кластере
В кластере разные серверы приложений могут иметь разное состояние разделяемого кэша. Один сервер уже мог обратиться к справочнику и загрузить данные в кэш, а другой сервер мог еще не обращаться к этим данным и не иметь их в кэше.
Если после этого данные изменяются в БД, но сброс кэша не выполняется, возникает временная рассинхронизация. Серверы, на которых кэш уже был заполнен, продолжают использовать старые данные. Серверы, на которых кэш еще не был заполнен, при первом обращении считывают уже измененные данные из БД.
Из-за этого одна и та же логика может работать по-разному на разных серверах приложений. Например, на одном сервере операция будет учитывать старые справочные данные, а на другом — уже новые.
Предупреждение
Риск разного поведения. До сброса кэша разные серверы приложений могут работать с разными версиями одних и тех же справочных данных. Это может привести к разному поведению одной и той же бизнес-логики на разных серверах.
Как выполняется сброс
Сброс разделяемого кэша очищает ранее загруженные данные из памяти приложения на серверах приложений. После сброса при следующем обращении данные снова считываются из БД и заново помещаются в кэш.
Для сброса разделяемого ORM-кэша используется операция Очистить кэш ORM (Shared Cache). Операция рассылает очистку на все серверы приложений.
Транзакционный кэш#
Транзакционный кэш работает в рамках текущей сессии или операции. Когда ORM-методы загружают объекты из БД, эти объекты помещаются в кэш текущей сессии. Если в рамках той же операции эти данные нужны повторно, система может использовать уже загруженные объекты из памяти.
Транзакционный кэш используется большинством ORM-операций. Он позволяет не читать повторно одни и те же объекты в рамках операции и хранит изменения до синхронизации с БД.
Назначение
Транзакционный кэш нужен для согласованной работы ORM внутри текущей операции. Он хранит объекты, которые уже были загружены из БД или изменены через сеттеры и другие ORM-операции.
Если объект уже есть в текущей сессии, повторное обращение может использовать это состояние без повторного чтения из БД. Если объект был изменен, изменения сохраняются в рамках сессии до записи в БД или отката операции.
Как работает
Общий порядок работы:
Код обращается к данным через ORM-метод.
Если данные уже есть в кэше текущей сессии, используется кэш текущей сессии.
Если данных нет в кэше текущей сессии, выполняется чтение из БД.
Загруженные данные помещаются в транзакционный кэш текущей сессии и могут использоваться повторно в рамках этой же операции.
Изменения объектов накапливаются в текущей сессии до синхронизации с БД.
При
commit,rollbackилиflushс очисткой транзакционный кэш текущей сессии очищается.
Транзакционный кэш не разделяется между сессиями. Он действует только в пределах текущей операции и удаляется при завершении работы с текущей сессией или при явной очистке.
Очистка транзакционного кэша#
При длительной обработке или массовом изменении данных транзакционный кэш может занимать значительный объем памяти. Если в одной операции загружается или изменяется много объектов, кэш текущей сессии растет. Это может привести к повышенному потреблению памяти и превышению лимита загружаемых ячеек.
Когда нужна очистка
Для таких сценариев данные обрабатываются порциями. После обработки очередной порции изменения синхронизируются с БД, а транзакционный кэш очищается. Это позволяет не накапливать в памяти слишком большой объем объектов в рамках одной операции.
Совет
Массовая обработка. При больших операциях данные обрабатываются частями. После очередной порции выполняется синхронизация изменений с БД и очистка транзакционного кэша.
Детальное описание различий между session.commit, session.commitWork, session.commitWorkAuto, session.flush и session.flush(true) приведено в разделе Принципы работы commit и flush. Дополнительные рекомендации по выбору методов, предварительной загрузке данных и обработке больших объемов приведены в разделе Оптимизация работы с данными и кэшем.
Особенность очистки
Транзакционный кэш очищается целиком в рамках текущей сессии. Сейчас нет механизма, который позволяет очистить только изменяемые данные и оставить в памяти неизменяемые данные, загруженные ранее для чтения.
Например, в одной операции могут использоваться два типа данных:
справочные данные, которые были загружены один раз и используются только для чтения;
бизнес-данные, которые изменяются и периодически должны записываться в БД.
При очистке транзакционного кэша из памяти удаляются и изменяемые, и неизменяемые объекты. Если после очистки справочные данные снова потребуются, они будут запрошены повторно.
Предупреждение
Очистка выполняется целиком. Очистка транзакционного кэша удаляет все загруженные объекты текущей сессии. После очистки неизменяемые данные, которые были нужны только для чтения, при повторном обращении будут загружены заново.
Это нужно учитывать при проектировании длительных операций. Очистка кэша необходима для контроля памяти, но после нее часть ранее прочитанных данных может быть загружена заново.
Сброс кэша через интерфейс#
Путь: Сервис > Управление решением
В блоке операций управления решением доступны операции сброса разных видов кэша.
Операция |
Назначение |
|---|---|
Очистить кэш метаданных выборок |
Очищает кэш метаданных выборок. Этот механизм не относится к разделяемому ORM-кэшу и используется для метаданных выборок. |
Очистить кэш прикладных объектов |
Очищает кэш прикладных объектов. Этот механизм отличается от разделяемого ORM-кэша. |
Очистить кэш ORM (Shared Cache) |
Очищает разделяемый ORM-кэш и рассылает очистку на все серверы приложений. Используется после изменения данных, которые работают через разделяемый кэш. |
Очистить все кэши |
Очищает все доступные виды кэша: кэш метаданных выборок, кэш прикладных объектов и ORM Shared Cache. |
В этом же блоке доступны настройки:
Настройка |
Назначение |
|---|---|
Восстанавливать изменения в интерфейсе при переоткрытии |
Управляет восстановлением изменений интерфейса при повторном открытии. |
Использовать кэш метаданных выборок |
Включает или отключает использование кэша метаданных выборок. |