Использование программного компонента#
Пример использования плагина безопасности DataGrid#
У плагина безопасности, входящего в поставку DataGrid, имеется открытый API.
Этот API представлен в виде java-класса SecurityDataManager. Данный класс читает и вносит изменения в distributed metastorage (распределенное хранилище метаданных). Это касается тех записей, которые относятся к пользователям и ролям. Именно на его основе строится администрирование пользователей и прав.
API работает следующим образом:
Сущность
IgniteClientподключается к кластеру с правами администратора безопасности.После подключения
IgniteClientпользователь сможет выполнять различные действия, например, добавлять пользователей (addUser) или изменять пароль (changePassword).
Разработчик может подключить данный интерфейс к своему приложению, взяв из Nexus артефакт com.sbt.security.ignite:ignite-security-plugin:(ise-version), где ise-version — это версия DataGrid.
После этого, класс SecurityDataManager будет доступен для использования.
Механизм Read repair#
Внимание!
Экспериментальная функциональность.
Введение#
Read repair — это механизм проверки и восстановления согласованности данных между основной (primary) и резервными (backup) копиями партиции во время обычных операций чтения. В режиме Read repair DataGrid сравнивает значения определенного ключа (ключей) во всех копиях партиции.
Механизм Read repair применяется для восстановления согласованности данных в случае, если другие средства восстановления согласованности (восстановление из снепшота, восстановление из лога транзакции, восстановление из прикладной логики и т. д.) оказались неэффективны.
Примечание
При использовании механизма Read repair чтение производится со всех резервных копий данных, поэтому операции чтения становятся в ~2 раза более дорогостоящими. В связи с этим использовать механизм Read repair постоянно не рекомендуется.
По способу работы механизм напоминает утилиту idle_verify. Однако отличается тем, что idle_verify лишь обнаруживает несогласованность данных, а Read repair, используемый утилитой control.sh, обнаруживает каждый случай несогласованности данных, записывает его в общий лог либо в специальный файл consistency.log и исправляет несогласованность.
Ограничения#
Проверка согласованности не подходит для использования со следующими кешами:
кеши с
backup factor = 0;NEAR-кеши;
кеши, использующие стратегию read-through.
Отдельный лог-файл#
Отдельный лог-файл (например, consistency.log) содержит в себе информацию о каждом случае несогласованности (о каждом проблемном ключе).
Файл позволяет убедиться в том, что механизм выбрал и исправил необходимые записи.
Схема работы механизма#
Для включения механизма Read repair необходимо получить экземпляр кеша, в котором включена функция Read repair следующим образом:
IgniteCache<Object, Object> cache =
ignite.cache("<cache-name>").withReadRepair(ReadRepairStrategy.<strategy>);
Object value = cache.get(<key>);
где:
<cache-name>— имя кеша;<strategy>— стратегия восстановления;<key>— ключ, по которому запрашиваются данные.
Стратегии восстановления согласованности#
В случае обнаружения нарушений согласованности значения по всей топологии будут заменены восстановленными значениями в соответствии с выбранной стратегией.
Стратегии восстановления согласованности описаны в документе «Руководство по системному администрированию», раздел «Сценарии администрирования», подраздел «Стратегии проверки и восстановления согласованности данных».
События#
При обнаружении несогласованности данных в любой из копий партиции Platform V Data Grid генерирует событие нарушения согласованности EVT_CONSISTENCY_VIOLATION при условии, что генерация событий включена в конфигурации (подробнее о событии см. официальную документацию Apache Ignite или документ «Справочник Java API DataGrid»).
Такие события можно прослушивать и получать уведомления о проблемах согласованности (подробнее о работе с событиями см. официальную документацию Apache Ignite).
Read repair для транзакционных кешей#
Проверка и устранение несогласованности данных для транзакционных кешей происходит:
автоматически: для транзакций в оптимистическом режиме (
TransactionConcurrency.OPTIMISTIC) ИЛИ транзакций с уровнем изоляцииREAD_COMMITTED(TransactionIsolation.READ_COMMITTED);в фазе фиксации (
commit()): для транзакций в пессимистическом режиме (TransactionConcurrency.PESSIMISTIC) И с уровнем изоляции, отличным отREAD_COMMITTED(TransactionIsolation.READ_COMMITTED).
Внимание
Механизм Read repair не гарантирует проверку всех копий партиции в случае, если значение уже закешировано в транзакции. Например, при использовании уровня изоляции, отличного от
READ_COMMITTED, если значение уже прочитано, либо совершена операция записи, то будет получено закешированное значение.
Read repair для атомарных кешей#
Проверка и устранение несогласованности данных для атомарных кешей производится автоматически.
Внимание
Из-за природы атомарного кеша могут наблюдаться ложноположительные результаты. Например, попытка проверить согласованность данных при загрузке кеша может привести к исключению о нарушении согласованности.
По умолчанию реализация совершает три попытки проверки заданного ключа. Количество попыток можно изменить с помощью свойства
IgniteSystemProperties.IGNITE_NEAR_GET_MAX_REMAPS.
Промежуточное ПО для сервисов#
DataGrid позволяет пользователям применять собственную логику промежуточного ПО для своих сервисов и предоставляет следующую функциональность:
Возможность скрытой передачи пользовательских неизменяемых параметров от прокси к сервису. Данная функциональность схожа с функциональностью заголовков HTTP-запросов.
Возможность определения пользовательского перехватчика (interceptor) вызовов методов сервиса.
Контекст вызова сервиса#
Данная функциональность дает возможность пользователю скрыто передавать параметры любому сервису без повторного развертывания сервиса.
Пользователь может создавать контекст и привязывать его к прокси сервиса. После этого, каждый вызов метода прокси будет скрыто передавать параметры контекста сервису:
Java
try (Ignite ignite = Ignition.start()) {
ignite.services().deployClusterSingleton("EchoService", new EchoServiceImpl());
// Создаем контекст.
ServiceCallContext johnCtx = ServiceCallContext.builder().put("user", "John").build();
ServiceCallContext maryCtx = ServiceCallContext.builder().put("user", "Mary").build();
// Привязываем контекст к прокси.
EchoService johnProxy = ignite.services().serviceProxy("EchoService", EchoService.class, false, johnCtx);
EchoService maryProxy = ignite.services().serviceProxy("EchoService", EchoService.class, false, maryCtx);
// Следующий вызов напечатает "Hello John!".
System.out.println(johnProxy.hello());
// Следующий вызов напечатает "Hello Mary!".
System.out.println(maryProxy.hello());
}
C#/.NET
var ignite = Ignition.Start();
ignite.GetServices().DeployNodeSingleton("EchoService", new EchoService());
// Создаем контекст.
IServiceCallContext johnCtx = new ServiceCallContextBuilder().Set("user", "John").Build();
IServiceCallContext maryCtx = new ServiceCallContextBuilder().Set("user", "Mary").Build();
// Привязываем контекст к прокси.
IEchoService johnProxy = ignite.GetServices().GetServiceProxy<IEchoService>("EchoService", false, johnCtx);
IEchoService maryProxy = ignite.GetServices().GetServiceProxy<IEchoService>("EchoService", false, maryCtx);
// Следующий вызов напечатает "Hello John!".
Console.WriteLine(johnProxy.Hello());
// Следующий вызов напечатает "Hello Mary!".
Console.WriteLine(maryProxy.Hello());
Пользователь может прочитать контекст вызова (call context) с помощью метода currentCallContext класса ServiceContext:
Java
@ServiceContextResource private ServiceContext ctx; /** {@inheritDoc} */ @Override public String hello() { ServiceCallContext callCtx = ctx.currentCallContext(); String proxyUser = callCtx != null ? callCtx.attribute("user") : null; return String.format("Hello %s!", (proxyUser == null || proxyUser.isEmpty() ? "anonymous" : proxyUser)); }C#/.NET
public class EchoService : IEchoService { private IServiceContext _context; public void Init(IServiceContext context) { _context = context; } // ... public string Hello() { IServiceCallContext callCtx = _context.CurrentCallContext(); String proxyUser = callCtx != null ? callCtx.GetAttribute("user") : null; return "Hello " + (proxyUser == null ? "anonymous" : proxyUser) + "!"; } }
Примечание
Контекст вызова сервиса доступен только из текущего потока во время исполнения метода сервиса.
Перехватчик сервисов (Service Interceptor)#
Функционал Service Interceptor позволяет пользователям перехватывать вызовы методов любого сервиса, кроме методов, относящихся к жизненному циклу сервиса (init(), execute() и cancel()).
В классе конфигурации ServiceConfiguration вы можете задать один или несколько таких перехватчиков. Эти перехватчики развертываются вместе с сервисом и используют тот же загрузчик классов.
Каждый предыдущий перехватчик приводит в действие следующий перехватчик в цепи, используя делегированный вызов. Последний перехватчик в цепи вызывает метод сервиса. Таким образом, перехватчик, обозначенный первым в конфигурации, последним обрабатывает результат выполнения метода сервиса.
Внимание
Некорректная реализация перехватчика может привести к непредсказуемому поведению сервиса при его исполнении.
Пример создания перехватчика#
В данном разделе приводится пример создания перехватчика вызовов сервиса:
Java
public class EchoServiceAccessInterceptor implements ServiceCallInterceptor { /** {@inheritDoc} */ @Override public Object invoke(String mtd, Object[] args, ServiceContext ctx, Callable<Object> next) throws Exception { ServiceCallContext callCtx = ctx.currentCallContext(); if (callCtx == null || callCtx.attribute("user") == null) throw new SecurityException("Anonymous access is restricted."); return next.call(); } }C#/.NET
public class EchoServiceAccessInterceptor : IServiceCallInterceptor { /** <inheritdoc /> */ public object Invoke(string mtd, object[] args, IServiceContext ctx, Func<object> next) { IServiceCallContext callCtx = ctx.CurrentCallContext; if (callCtx == null || callCtx.GetAttribute("user") == null) throw new SecurityException("Anonymous access is restricted."); return next.Invoke(); } }
Статистика производительности (Performance statistics)#
DataGrid включает в себя встроенный инструмент профилирования кластера.
Вы можете собирать статистику производительности с кластера и создавать отчеты о производительности.
Сбор статистики производительности#
Для сбора статистики производительности используются:
Интерфейс JMX:
Метод
Описание
start()Начать сбор статистики по кластеру
stop()Остановить сбор статистики по кластеру
rotate()Произвести ротацию файлов статистики в кластере
started()true, если сбор статистики начатУтилита
control.sh:Метод
Описание
startНачать сбор статистики по кластеру
stopОстановить сбор статистики по кластеру
rotateПроизвести ротацию файлов статистики в кластере
statusПолучить статус сбора статистики по кластеру
Каждый узел собирает статистику производительности в бинарном файле. Этот файл размещается в рабочей директории DataGrid по пути Platform-v-datagrid-work-directory/perf_stat. Для имени используется следующая маска: node-{nodeId}-{index}.prf.
Файлы статистики производительности используются для создания отчета в режиме оффлайн.
Узлы используют циклический off-heap-буфер для временного хранения сериализованной статистики. Записывающий поток отправляет содержимое буфера в файл при достижении порога. Если буфер переполняется из-за медленного диска, некоторые показатели в статистике пропускаются. Для настройки обратитесь к разделу «Системные свойства» ниже.
Каждый процесс сбора статистики создает на узлах новый файл. Каждый следующий файл имеет такое имя, как у предыдущего, но с соответствующим индексом, например:
node-faedc6c9-3542-4610-ae10-4ff7e0600000.prf;node-faedc6c9-3542-4610-ae10-4ff7e0600000-1.prf;node-faedc6c9-3542-4610-ae10-4ff7e0600000-2.prf.
Создание отчета#
DataGrid предоставляет инструмент для генерации отчета из файлов статистики производительности. Инструмент является расширением для DataGrid и находится в каталоге utils под именем performance-statistics-ext.
Для создания отчета:
Остановите сбор статистики, и поместите файлы со всех узлов в пустой каталог. Например:
/path_to_files/ ├── node-162c7147-fef8-4ea2-bd25-8653c41fc7fa.prf ├── node-7b8a7c5c-f3b7-46c3-90da-e66103c00001.prf └── node-faedc6c9-3542-4610-ae10-4ff7e0600000.prfЗапустите скрипт из поставки:
performance-statistics-tool/build-report.sh path_to_files
Отчет о производительности создается в новом каталоге по пути файлов статистики производительности:
path_to_files/report_yyyy-MM-dd_HH-mm-ss/
Для отображения отчета откройте в браузере страницу report_yyyy-MM-dd_HH-mm-ss/index.html.
Системные свойства#
Свойство |
Тип |
Значение по умолчанию |
Описание |
|---|---|---|---|
|
Long |
32 Гб |
Максимальный размер файла статистики производительности в байтах. Сбор статистики производительности прекращается при превышении максимального размера файла |
|
Integer |
32 Мб |
Размер off-heap-буфера статистики производительности в байтах |
|
Integer |
8 Мб |
Минимальный размер пакета данных статистики производительности для отправления в файл в байтах |
|
Integer |
1024 |
Порог закешированных строк статистики производительности. Кеширование строк прекращается при превышении порога |
Настройки для аудита событий#
Для настройки аудита событий необходимо:
Добавить
RestProcessorPluginProviderв список плагинов.Включить события
RestEventType.EVT_REST_REQ_SUCCEEDEDиRestEventType.EVT_REST_REQ_FAILEDвIgniteConfiguration. Пример:<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration" primary="true"> ... <property name="pluginProviders"> <list> ... <ref bean="restProcPlugin"/> </list> </property> <property name="includeEventTypes" ref="eventTypes"/> ... </bean> <bean id="restProcPlugin" class="com.sbt.security.ignite.core.rest.RestProcessorPluginProvider"> <property name="configuration"> <bean id="restProcPluginConfiguration" class="com.sbt.security.ignite.core.rest.RestProcessorPluginConfiguration"/> </property> </bean> <util:list id="eventTypes" value-type="java.lang.Integer"> ... <util:constant static-field="com.sbt.security.ignite.core.events.RestEventType.EVT_REST_REQ_SUCCEEDED"/> <util:constant static-field="com.sbt.security.ignite.core.events.RestEventType.EVT_REST_REQ_FAILED"/> ... </util:list>